| 39 | | In the proposed example, the initiator module is modeled by the '''!VciSimpleInitiator''' class. |
| 40 | | This class inherits from the '''soclib::tlmt::!BaseModule''' class, that acts as the root class for all TLM-T modules. |
| 41 | | The process time, as well as other useful process attributes, is contained in a C++ structure called |
| 42 | | a '''tlmt_core::tlmt_thread_context'''. As there is only one thread in this module, there is only one member |
| 43 | | variable '''c0''' of type '''tlmt_core::tlmt_thread_context'''. '''c0''' mostly contains the PDES process local |
| 44 | | time ('''H''' on the figure). In all the TLM-T models, time is handled by the '''tlmt_core::tlmt_time''' class. |
| 45 | | In order to get the time associated to the initiator process, one should use the getter |
| 46 | | function '''time()''' on the '''c0''' object, and should use the setter functions |
| 47 | | '''set_time()''' and '''update_time()''' to assign a new time to the PDES process. |
| | 42 | In the proposed example, the initiator module is modeled by the '''!my_initiator''' class. |
| | 43 | This class inherits from the SystemC '''sc_core::!sc_module''' class, that acts as the root class for all TLM-T modules. |
| | 44 | |
| | 45 | The initiator local time is contained in a member variable named '''m_localTime''', of type '''sc_core::sc_time'''. The |
| | 46 | local time can be accessed through the use of the following accessors: '''addLocalTime()''', '''setLocalTime()''' |
| | 47 | and '''getLocalTime()'''. |
| | 48 | {{{ |
| | 49 | sc_core::sc_time m_localTime; // the initiator local time |
| | 50 | ... |
| | 51 | void addLocalTime(sc_core::sc_time t); // add a value to the local time |
| | 52 | void setLocalTime(sc_core::sc_time& t); // set the local time |
| | 53 | sc_core::sc_time getLocalTime(void); // get the local time |
| | 54 | }}} |
| | 55 | |
| | 56 | The initiator activity corresponds to the boolean member '''m_activity''' that indicates if the initiator is currently active |
| | 57 | (i.e. '''true''', wants to participate in the arbitration in the interconnect) or inactive (i.e. '''false''', does not want |
| | 58 | to participate in the arbitration in the interconnect). The corresponding access functions are '''setActivity()''' and '''getActivity()'''. |
| | 59 | {{{ |
| | 60 | bool m_activity; |
| | 61 | ... |
| | 62 | void setActivity(bool t); // set the activity status (true if the component is active) |
| | 63 | bool getActivity(void); // get the activity state |
| | 64 | }}} |
| 57 | | To send a VCI command packet, the '''execLoop()''' method must use the '''send()''' method, that is a member function of |
| 58 | | the '''p_vci''' port. The prototype is the following: |
| 59 | | {{{ |
| 60 | | void send(soclib::tlmt::vci_cmd_packet<vci_param> *cmd, // pointer to a VCI command packet |
| 61 | | tlmt_core::tlmt_time time); // initiator local time |
| 62 | | }}} |
| 63 | | |
| 64 | | The contents of a VCI command packet is defined below: |
| 65 | | {{{ |
| 66 | | template<typename vci_param> |
| 67 | | class vci_cmd_packet |
| 68 | | { |
| 69 | | public: |
| 70 | | typename vci_param::cmd_t cmd; // VCI transaction type |
| 71 | | typename vci_param::addr_t address; // address on the target side |
| 72 | | uint32_t int be; // byte_enable value (same value for all packet words) |
| 73 | | bool contig; // contiguous addresses (when true) |
| 74 | | typename vci_param::data_t *buf; // pointer to the local buffer on the initiator |
| 75 | | size_t nwords; // number of words in the packet |
| 76 | | uint32_t srcid; // VCI Source ID |
| 77 | | uint32_t trdid; // VCI Thread ID |
| 78 | | uint32_t pktid; // VCI Packet ID |
| 79 | | }; |
| 80 | | }}} |
| 81 | | |
| 82 | | The possible values for the '''cmd''' filed are `vci_param::CMD_READ`, `vci_param::CMD_WRITE`, `vci_param::CMD_READ_LOCKED`, |
| 83 | | and `vci_param::CMD_STORE_COND`. |
| 84 | | The '''contig''' field can be used for optimization. |
| 85 | | |
| 86 | | The '''send()''' function is non-blocking. |
| | 82 | To send a VCI command packet, the '''execLoop()''' method must use the '''nb_transport_fw()''' method, that is a member |
| | 83 | function of the '''p_vci_init''' port. The prototype is the following: |
| | 84 | {{{ |
| | 85 | |
| | 86 | tlm::tlm_sync_enum nb_transport_fw /// sync status |
| | 87 | ( soclib_vci_types::vci_payload_type &payload, ///< VCI payload pointer |
| | 88 | soclib_vci_types::tlmt_phase_type &phase, ///< transaction phase |
| | 89 | sc_core::sc_time &time); ///< time |
| | 90 | }}} |
| | 91 | |
| | 92 | The first parameter of this member function is the VCI packet, the second represents the phase (TLMT_CMD in this case), and the third |
| | 93 | parameter contains the initiator local time. |
| | 94 | |
| | 95 | To prepare a VCI packet for sending, the '''execLoop''' function must declare two objects locally, '''payload''' and '''phase'''. |
| | 96 | {{{ |
| | 97 | soclib_vci_types::vci_payload_type payload; |
| | 98 | soclib_vci_types::tlmt_phase_type phase; |
| | 99 | }}} |
| | 100 | A payload of type '''soclib_vci_types::vci_payload_type''' corresponds to a '''tlmt_vci_transaction''' and thus |
| | 101 | contains three kinds of structure fields: TLM2.0 related fields,VCI related fields, and TLM-T related fields. |
| | 102 | |
| | 103 | The contents of a '''tlmt_transaction''' is defined below: |
| | 104 | {{{ |
| | 105 | class tlmt_vci_transaction |
| | 106 | { |
| | 107 | ... |
| | 108 | private: |
| | 109 | // TLM2.0 related fields and common structure |
| | 110 | |
| | 111 | sc_dt::uint64 m_address; // address |
| | 112 | unsigned char* m_data; // buf |
| | 113 | unsigned int m_length; // nword |
| | 114 | tlmt_response_status m_response_status; // rerror |
| | 115 | bool m_dmi; // nothing |
| | 116 | unsigned char* m_byte_enable; // be |
| | 117 | unsigned int m_byte_enable_length; |
| | 118 | unsigned int m_streaming_width; // |
| | 119 | |
| | 120 | // VCI related fields |
| | 121 | |
| | 122 | tlmt_command m_command; // cmd |
| | 123 | unsigned int m_src_id; // srcid |
| | 124 | unsigned int m_trd_id; // trdid |
| | 125 | unsigned int m_pkt_id; // pktid |
| | 126 | |
| | 127 | // TLM-T related fields |
| | 128 | |
| | 129 | bool* m_activity_ptr; |
| | 130 | sc_core::sc_time* m_local_time_ptr; |
| | 131 | |
| | 132 | }}} |
| | 133 | |
| | 134 | The TLM2.0 compliant accessors allow to set the TLM2.0 related fields, such as the transaction address, the byte enable |
| | 135 | array pointer and its associated size in bytes, and the data array pointer and its associated size in bytes. The byte |
| | 136 | enable array allows to build versatile packets thanks to a powerful but slow data masking scheme. Further experiments are |
| | 137 | currently done. It is likely that the types of the '''m_data''' and '''m_byte_enable''' of the '''tlmt_vci_transaction''' |
| | 138 | will be changed to '''uint32*''' in a near future. |
| | 139 | |
| | 140 | The VCI accessors are used to define the VCI transaction type, that can either be '''set_read()''' (for read command), |
| | 141 | '''set_write()''' (for write command),'''set_locked_read()''' (for atomic locked read), |
| | 142 | and '''set_store_cond()''' (for atomic store conditional). The '''set_src_id()''', '''set_trd_id()''' and '''set_pkt_id()''' functions |
| | 143 | respectively set the VCI source, thread and packet identifiers. |
| | 144 | |
| | 145 | {{{ |
| | 146 | payload.set_address(0x10000000);//ram 0 |
| | 147 | payload.set_byte_enable_ptr(byte_enable); |
| | 148 | payload.set_byte_enable_length(nbytes); |
| | 149 | payload.set_data_ptr(data); |
| | 150 | payload.set_data_length(nbytes); // 5 words of 32 bits |
| | 151 | |
| | 152 | payload.set_write(); |
| | 153 | payload.set_src_id(m_id); |
| | 154 | payload.set_trd_id(0); |
| | 155 | payload.set_pkt_id(pktid); |
| | 156 | |
| | 157 | phase= soclib::tlmt::TLMT_CMD; |
| | 158 | sendTime = getLocalTime(); |
| | 159 | |
| | 160 | p_vci_init->nb_transport_fw(payload, phase, sendTime); |
| | 161 | }}} |
| | 162 | |
| | 163 | |
| | 164 | The '''nb_transport_fw()''' function is non-blocking. |
| 99 | | tlmt_core::tlmt_return &rspReceived(soclib::tlmt::vci_rsp_packet<vci_param> *pkt, |
| 100 | | const tlmt_core::tlmt_time &time, |
| 101 | | void *private_data); |
| 102 | | }}} |
| 103 | | |
| 104 | | The contents of a VCI response packet is defined below: |
| 105 | | {{{ |
| 106 | | template<typename vci_param> |
| 107 | | class vci_rsp_packet |
| 108 | | { |
| 109 | | public: |
| 110 | | typename vci_param::cmd_t cmd; // VCI transaction type |
| 111 | | size_t nwords; // number of words in the packet |
| 112 | | uint32_t error; // error code (0 if no error) |
| 113 | | uint32_t srcid; // VCI Source ID |
| 114 | | uint32_t trdid; // VCI Thread ID |
| 115 | | uint32_t pktid; // VCI Packet ID |
| 116 | | }; |
| 117 | | }}} |
| 118 | | |
| 119 | | The second parameter, '''time''', is of type '''tlmt_core::tlmt_time''' and corresponds to the time of the response. The third parameter, |
| 120 | | '''private_data''' has a default value of '''NULL''' and is not used when transmitting or receiving VCI packets. |
| 121 | | |
| 122 | | |
| 123 | | The actions executed by the call-back function depend on the response transaction type ('''cmd''' field), as well as |
| | 177 | tlm::tlm_sync_enum my_nb_transport_bw // for resp messages |
| | 178 | ( soclib_vci_types::vci_payload_type &payload, // payload |
| | 179 | soclib_vci_types::tlmt_phase_type &phase, // transaction phase |
| | 180 | sc_core::sc_time &time); // resp time |
| | 181 | }}} |
| | 182 | |
| | 183 | The function parameters are identical to those described in the forward transport function |
| | 184 | |
| | 185 | The actions executed by the call-back function depend on the response transaction type ('''m_command''' field), as well as |
| 161 | | ////////////////////////// vci_simple_initiator.h //////////////////////////////// |
| 162 | | |
| 163 | | #ifndef VCI_SIMPLE_INITIATOR_H |
| 164 | | #define VCI_SIMPLE_INITIATOR_H |
| 165 | | |
| 166 | | #include <tlmt> |
| 167 | | #include "tlmt_base_module.h" |
| 168 | | #include "vci_ports.h" |
| 169 | | |
| 170 | | namespace soclib { namespace tlmt { |
| 171 | | |
| 172 | | template<typename vci_param> |
| 173 | | class VciSimpleInitiator |
| 174 | | : public soclib::tlmt::BaseModule |
| 175 | | { |
| 176 | | tlmt_core::tlmt_thread_context c0; |
| 177 | | sc_core::sc_event m_rsp_received; |
| 178 | | tlmt_core::tlmt_return m_return; |
| 179 | | soclib::tlmt::vci_cmd_packet<vci_param> cmd; |
| 180 | | |
| 181 | | uint32_t addresses[8]; // address table, |
| 182 | | uint32_t localbuf[8]; // local buffer |
| 183 | | |
| 184 | | uint32_t m_counter; // iteration counter |
| 185 | | uint32_t m_lookahead; // lookahead value |
| 186 | | uint32_t m_index; // initiator index |
| 187 | | |
| | 224 | ////////////////////////// my_initiator.h //////////////////////////////// |
| | 225 | #ifndef __MY_INITIATOR_H__ |
| | 226 | #define __MY_INITIATOR_H__ |
| | 227 | |
| | 228 | #include "tlm.h" // TLM headers |
| | 229 | #include "tlmt_transactions.h" // VCI headers |
| | 230 | #include "tlmt_simple_initiator_socket.h" // VCI socket |
| | 231 | #include "mapping_table.h" |
| | 232 | |
| | 233 | class my_initiator // my_initiator |
| | 234 | : public sc_core::sc_module // inherit from SC module base class |
| | 235 | { |
| | 236 | private: |
| | 237 | //Variables |
| | 238 | typedef soclib::tlmt::VciParams<uint32_t,uint32_t,4> vci_param; |
| | 239 | sc_core::sc_event m_rspEvent; |
| | 240 | sc_core::sc_time m_localTime; |
| | 241 | bool m_activity; |
| | 242 | uint32_t m_initid; |
| | 243 | uint32_t m_counter; |
| | 244 | uint32_t m_lookahead; |
| | 245 | |
| | 246 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 247 | // Fuctions |
| | 248 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 249 | void execLoop(void); // initiator thread |
| | 250 | void addLocalTime(sc_core::sc_time t); // add a value to the local time |
| | 251 | void setLocalTime(sc_core::sc_time& t); // set the local time |
| | 252 | sc_core::sc_time getLocalTime(void); // get the local time |
| | 253 | void setActivity(bool t); // set the activity status (true if the component is active) |
| | 254 | bool getActivity(void); // get the activity state |
| | 255 | |
| | 256 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 257 | // Virtual Fuctions tlm::tlm_bw_transport_if (VCI INITIATOR SOCKET) |
| | 258 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 259 | |
| | 260 | /// Receive rsp from target |
| | 261 | tlm::tlm_sync_enum my_nb_transport_bw // for resp messages |
| | 262 | ( soclib_vci_types::vci_payload_type &payload, // payload |
| | 263 | soclib_vci_types::tlmt_phase_type &phase, // transaction phase |
| | 264 | sc_core::sc_time &time); // resp time |
| | 265 | |
| 192 | | soclib::tlmt::VciInitiator<vci_param> p_vci; |
| 193 | | |
| 194 | | VciSimpleInitiator( sc_core::sc_module_name name, |
| 195 | | uint32_t initiator index, |
| 196 | | uint32_t lookahead ); |
| 197 | | |
| 198 | | tlmt_core::tlmt_return &rspReceived(soclib::tlmt::vci_rsp_packet<vci_param> *pkt, |
| 199 | | const tlmt_core::tlmt_time &time, |
| 200 | | void *private_data); |
| 201 | | void behavior(); |
| 202 | | }; |
| 203 | | |
| 204 | | }} |
| 205 | | |
| 206 | | #endif |
| 207 | | |
| 208 | | ////////////////////////// vci_simple_initiator.cpp //////////////////////////////// |
| 209 | | |
| 210 | | #include "../include/vci_simple_initiator.h" |
| 211 | | |
| 212 | | namespace soclib { namespace tlmt { |
| 213 | | |
| 214 | | #define tmpl(x) template<typename vci_param> x VciSimpleInitiator<vci_param> |
| 215 | | |
| 216 | | tmpl(tlmt_core::tlmt_return&)::rspReceived(soclib::tlmt::vci_rsp_packet<vci_param> *pkt, |
| 217 | | const tlmt_core::tlmt_time &time, |
| 218 | | void *private_data) |
| 219 | | { |
| 220 | | if(pkt->cmd == vci_param::VCI_CMD_READ) { |
| 221 | | c0.set_time(time + tlmt_core::tlmt_time(pkt->length)); |
| 222 | | m_rsp_received.notify(sc_core::SC_ZERO_TIME) ; |
| | 270 | tlmt_simple_initiator_socket<my_initiator,32,soclib_vci_types> p_vci_init; // VCI initiator port |
| | 271 | |
| | 272 | //constructor |
| | 273 | my_initiator( // constructor |
| | 274 | sc_core::sc_module_name name, // module name |
| | 275 | const soclib::common::IntTab &index, // VCI initiator index |
| | 276 | const soclib::common::MappingTable &mt, // mapping table |
| | 277 | uint32_t lookahead // lookahead |
| | 278 | ); |
| | 279 | |
| | 280 | }; |
| | 281 | #endif /* __MY_INITIATOR_H__ */ |
| | 282 | |
| | 283 | ////////////////////////// my_initiator.cpp //////////////////////////////// |
| | 284 | |
| | 285 | #include "my_initiator.h" // Our header |
| | 286 | |
| | 287 | #ifndef MY_INITIATOR_DEBUG |
| | 288 | #define MY_INITIATOR_DEBUG 1 |
| | 289 | #endif |
| | 290 | |
| | 291 | #define tmpl(x) x my_initiator |
| | 292 | |
| | 293 | ///Constructor |
| | 294 | tmpl (/**/)::my_initiator |
| | 295 | ( sc_core::sc_module_name name, // module name |
| | 296 | const soclib::common::IntTab &index, // index of mapping table |
| | 297 | const soclib::common::MappingTable &mt, // mapping table |
| | 298 | uint32_t lookahead // lookahead |
| | 299 | ) |
| | 300 | : sc_module(name) // init module name |
| | 301 | , p_vci_init("p_vci_init") // vci initiator socket name |
| | 302 | { |
| | 303 | //register callback function |
| | 304 | p_vci_init.register_nb_transport_bw(this, &my_initiator::my_nb_transport_bw); |
| | 305 | |
| | 306 | // initiator identification |
| | 307 | m_initid = mt.indexForId(index); |
| | 308 | |
| | 309 | //lookahead control |
| | 310 | m_counter = 0; |
| | 311 | m_lookahead = lookahead; |
| | 312 | |
| | 313 | //initialize the local time |
| | 314 | m_localTime= 0 * UNIT_TIME; |
| | 315 | |
| | 316 | // initialize the activity variable |
| | 317 | setActivity(true); |
| | 318 | |
| | 319 | // register thread process |
| | 320 | SC_THREAD(execLoop); |
| | 321 | } |
| | 322 | |
| | 323 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 324 | // Fuctions |
| | 325 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 326 | tmpl (sc_core::sc_time)::getLocalTime() |
| | 327 | { |
| | 328 | return m_localTime; |
| | 329 | } |
| | 330 | |
| | 331 | tmpl (bool)::getActivity() |
| | 332 | { |
| | 333 | return m_activity; |
| | 334 | } |
| | 335 | |
| | 336 | tmpl (void)::setLocalTime(sc_core::sc_time &t) |
| | 337 | { |
| | 338 | m_localTime=t; |
| | 339 | } |
| | 340 | |
| | 341 | tmpl (void)::addLocalTime(sc_core::sc_time t) |
| | 342 | { |
| | 343 | m_localTime= m_localTime + t; |
| | 344 | } |
| | 345 | |
| | 346 | tmpl (void)::setActivity(bool t) |
| | 347 | { |
| | 348 | m_activity =t; |
| | 349 | } |
| | 350 | |
| | 351 | tmpl (void)::execLoop(void) // initiator thread |
| | 352 | { |
| | 353 | soclib_vci_types::vci_payload_type payload; |
| | 354 | soclib_vci_types::tlmt_phase_type phase; |
| | 355 | sc_core::sc_time sendTime; |
| | 356 | unsigned char data[32]; |
| | 357 | unsigned char byte_enable[32]; |
| | 358 | int pktid = 0; |
| | 359 | int nbytes = 4; // 1 word of 32 bits |
| | 360 | |
| | 361 | uint32_t int_data = 12345678; |
| | 362 | std::ostringstream name; |
| | 363 | name << "" << int_data; |
| | 364 | std::cout << "NAME = " << std::dec << name << std::endl; |
| | 365 | |
| | 366 | for(int i=0; i<nbytes; i++) |
| | 367 | byte_enable[i] = TLMT_BYTE_ENABLED; |
| | 368 | |
| | 369 | for(int i=0; i<32; i++) |
| | 370 | data[i] = 0x0; |
| | 371 | |
| | 372 | data[0]='a'; |
| | 373 | data[1]='b'; |
| | 374 | data[2]='c'; |
| | 375 | data[3]='d'; |
| | 376 | data[4]='\0'; |
| | 377 | |
| | 378 | std ::cout<< "DATA = " << data << std::endl; |
| | 379 | |
| | 380 | while ( 1 ){ |
| | 381 | addTime(10 * UNIT_TIME); |
| | 382 | |
| | 383 | payload.set_address(0x10000000);//ram 0 |
| | 384 | payload.set_byte_enable_ptr(byte_enable); |
| | 385 | payload.set_byte_enable_length(nbytes); |
| | 386 | payload.set_data_ptr(data); |
| | 387 | payload.set_data_length(nbytes); // 5 words of 32 bits |
| | 388 | |
| | 389 | payload.set_write(); |
| | 390 | payload.set_src_id(m_id); |
| | 391 | payload.set_trd_id(0); |
| | 392 | payload.set_pkt_id(pktid); |
| | 393 | |
| | 394 | phase= soclib::tlmt::TLMT_CMD; |
| | 395 | sendTime = getLocalTime(); |
| | 396 | |
| | 397 | #if MY_INITIATOR_DEBUG |
| | 398 | std::cout << "[INITIATOR " << m_id << "] send cmd packet id = " << payload.get_pkt_id() << " time = " << getLocalTime().value() << std::endl; |
| | 399 | #endif |
| | 400 | |
| | 401 | p_vci_init->nb_transport_fw(payload, phase, sendTime); |
| | 402 | wait(m_rspEvent); |
| | 403 | |
| | 404 | #if MY_INITIATOR_DEBUG |
| | 405 | std::cout << "[INITIATOR " << m_id << "] receive rsp packet id = " << payload.get_pkt_id() << " time = " << getLocalTime().value() << std::endl; |
| | 406 | #endif |
| | 407 | |
| | 408 | pktid++; |
| | 409 | |
| | 410 | addTime(10 * UNIT_TIME); |
| | 411 | |
| | 412 | payload.set_address(0x10000000);//ram 0 |
| | 413 | payload.set_byte_enable_ptr(byte_enable); |
| | 414 | payload.set_byte_enable_length(nbytes); |
| | 415 | payload.set_data_ptr(data); |
| | 416 | payload.set_data_length(nbytes); // 5 words of 32 bits |
| | 417 | |
| | 418 | payload.set_read(); |
| | 419 | payload.set_src_id(m_id); |
| | 420 | payload.set_trd_id(0); |
| | 421 | payload.set_pkt_id(pktid); |
| | 422 | |
| | 423 | phase= soclib::tlmt::TLMT_CMD; |
| | 424 | sendTime = getLocalTime(); |
| | 425 | |
| | 426 | #if MY_INITIATOR_DEBUG |
| | 427 | std::cout << "[INITIATOR " << m_id << "] send cmd packet id = " << payload.get_pkt_id() << " time = " << getLocalTime().value() << std::endl; |
| | 428 | #endif |
| | 429 | |
| | 430 | p_vci_init->nb_transport_fw(payload, phase, sendTime); |
| | 431 | wait(m_rspEvent); |
| | 432 | |
| | 433 | #if MY_INITIATOR_DEBUG |
| | 434 | std::cout << "[INITIATOR " << m_id << "] receive rsp packet id = " << payload.get_pkt_id() << " time = " << getLocalTime().value() << std::endl; |
| | 435 | |
| | 436 | #endif |
| | 437 | |
| | 438 | pktid++; |
| | 439 | |
| | 440 | // lookahead management |
| | 441 | m_counter++ ; |
| | 442 | if (m_counter >= m_lookahead) { |
| | 443 | m_counter = 0 ; |
| | 444 | wait(sc_core::SC_ZERO_TIME) ; |
| 224 | | return m_return; |
| 225 | | } |
| 226 | | |
| 227 | | tmpl(void)::behavior() |
| 228 | | { |
| 229 | | |
| 230 | | for(;;) { |
| 231 | | |
| 232 | | // sending a read VCI packet |
| 233 | | |
| 234 | | cmd.cmd = vci_param::CMD_READ; // a VCI read packet |
| 235 | | addresses[0] = 0xBFC00000; // the start address |
| 236 | | cmd.address = addresses; // assigned |
| 237 | | cmd.be = 0xF; // reading full words |
| 238 | | cmd.contig = true; // at successive addresses |
| 239 | | cmd.buf = localbuf; // storing the read results in localbuf |
| 240 | | cmd.length = 8; // packet of 8 words |
| 241 | | cmd.srcid = 0; // srcid=0 |
| 242 | | cmd.trdid = 0; // trdid=0 |
| 243 | | cmd.pktid = 0; // pktid=0 |
| 244 | | |
| 245 | | tlmt_core::tlmt_return ret; // in case a test on the send function is needed |
| 246 | | ret = p_vci.send(&cmd, c0.time()); // sending the packet |
| 247 | | sc_core::wait(m_rsp_received); // and waiting for the response packet |
| 248 | | |
| 249 | | // sending a write VCI packet |
| 250 | | |
| 251 | | localbuf[0]=0x00112233; // first, fill the write local buffer with write data |
| 252 | | |
| 253 | | cmd.cmd = vci_param::CMD_WRITE; // then issue the VCI write packet |
| 254 | | addresses[0] = 0x10000000; // starting with this address |
| 255 | | cmd.address = addresses; |
| 256 | | cmd.be = 0xF; |
| 257 | | cmd.contig = 0; |
| 258 | | cmd.buf = localbuf; |
| 259 | | cmd.length = 1; |
| 260 | | cmd.srcid = 0; |
| 261 | | cmd.trdid = 0; |
| 262 | | cmd.pktid = 0; |
| 263 | | |
| 264 | | ret = p_vci.send(&cmd, c0.time()); // Don't wait for the answer |
| 265 | | |
| 266 | | // lookahead management |
| 267 | | m_counter++ ; |
| 268 | | if (m_counter >= m_lookahead) { |
| 269 | | m_counter = 0 ; |
| 270 | | sc_core::wait(sc_core::SC_ZERO_TIME) ; |
| 271 | | } // end if |
| 272 | | |
| 273 | | // process time= process time+1 |
| 274 | | c0.set_time(c0.time()+tlmt_core::tlmt_time(1)) ; |
| 275 | | |
| 276 | | } |
| 277 | | } |
| 278 | | |
| 279 | | tmpl(/**/)::VciSimpleInitiator( sc_core::sc_module_name name, |
| 280 | | uint32_t initiator index, |
| 281 | | uint32_t lookahead) |
| 282 | | : soclib::tlmt::BaseModule(name), |
| 283 | | m_index(initiator_index), |
| 284 | | m_lookahead(lookahead), |
| 285 | | m_counter(0), |
| 286 | | p_vci("vci", new tlmt_core::tlmt_callback<VciSimpleInitiator,soclib::tlmt::vci_rsp_packet<vci_param> *>( |
| 287 | | this, &VciSimpleInitiator<vci_param>::rspReceived), &c0) |
| 288 | | { |
| 289 | | SC_THREAD(behavior); |
| 290 | | } |
| 291 | | |
| 292 | | }} |
| | 446 | |
| | 447 | } // end while true |
| | 448 | setActivity(false); |
| | 449 | } // end initiator_thread |
| | 450 | |
| | 451 | |
| | 452 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 453 | // Virtual Fuctions tlm::tlm_bw_transport_if (VCI SOCKET) |
| | 454 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 455 | |
| | 456 | /// receive the response packet from target socket |
| | 457 | tmpl (tlm::tlm_sync_enum)::my_nb_transport_bw // inbound nb_transport_bw |
| | 458 | ( soclib_vci_types::vci_payload_type &payload, // VCI payload |
| | 459 | soclib_vci_types::tlmt_phase_type &phase, // tlm phase |
| | 460 | sc_core::sc_time &rspTime // the response timestamp |
| | 461 | ) |
| | 462 | { |
| | 463 | switch(phase){ |
| | 464 | case soclib::tlmt::TLMT_RSP : |
| | 465 | setLocalTime(rspTime); |
| | 466 | m_rspEvent.notify(0 * UNIT_TIME); |
| | 467 | break; |
| | 468 | case soclib::tlmt::TLMT_INFO : |
| | 469 | payload.set_local_time_ptr(&m_localTime); |
| | 470 | payload.set_activity_ptr(&m_activity); |
| | 471 | break; |
| | 472 | } |
| | 473 | return tlm::TLM_COMPLETED; |
| | 474 | } // end backward nb transport |
| 343 | | ////////////////////////// vci_simple_target.h //////////////////////////////// |
| 344 | | |
| 345 | | #ifndef VCI_SIMPLE_TARGET_H |
| 346 | | #define VCI_SIMPLE_TARGET_H |
| 347 | | |
| 348 | | #include <tlmt> |
| 349 | | #include "tlmt_base_module.h" |
| 350 | | #include "vci_ports.h" |
| 351 | | |
| 352 | | namespace soclib { namespace tlmt { |
| 353 | | |
| 354 | | template<typename vci_param> |
| 355 | | class VciSimpleTarget |
| 356 | | : public soclib::tlmt::BaseModule |
| 357 | | { |
| 358 | | private: |
| 359 | | tlmt_core::tlmt_return m_return; |
| 360 | | uint32_t m_index; |
| 361 | | uint32_t m_latency; |
| 362 | | soclib::tlmt::vci_rsp_packet<vci_param> rsp; |
| 363 | | |
| 364 | | public: |
| 365 | | soclib::tlmt::VciTarget<vci_param> p_vci; |
| 366 | | |
| 367 | | VciSimpleTarget(sc_core::sc_module_name name, |
| 368 | | uint32_t targetIndex, |
| 369 | | uint32_t latency); |
| 370 | | |
| 371 | | tlmt_core::tlmt_return &cmdReceived(soclib::tlmt::vci_cmd_packet<vci_param> *pkt, |
| 372 | | const tlmt_core::tlmt_time &time, |
| 373 | | void *private_data); |
| | 528 | ////////////////////////// my_target.h //////////////////////////////// |
| | 529 | |
| | 530 | #ifndef __MY_TARGET_H__ |
| | 531 | #define __MY_TARGET_H__ |
| | 532 | |
| | 533 | #include "tlm.h" // TLM headers |
| | 534 | #include "tlmt_transactions.h" // VCI headers |
| | 535 | #include "tlmt_simple_target_socket.h" // VCI SOCKET |
| | 536 | #include "mapping_table.h" |
| | 537 | #include "soclib_endian.h" |
| | 538 | |
| | 539 | class my_target |
| | 540 | : public sc_core::sc_module |
| | 541 | { |
| | 542 | private: |
| | 543 | typedef soclib::tlmt::VciParams<uint32_t,uint32_t,4> vci_param; |
| | 544 | |
| | 545 | uint32_t m_targetid; |
| | 546 | soclib::common::MappingTable m_mt; |
| | 547 | |
| | 548 | |
| | 549 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 550 | // Virtual Fuctions tlm::tlm_fw_transport_if (VCI SOCKET) |
| | 551 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 552 | |
| | 553 | // receive command from initiator |
| | 554 | tlm::tlm_sync_enum my_nb_transport_fw /// sync status |
| | 555 | ( soclib_vci_types::vci_payload_type &payload, ///< VCI payload pointer |
| | 556 | soclib_vci_types::tlmt_phase_type &phase, ///< transaction phase |
| | 557 | sc_core::sc_time &time); ///< time |
| | 558 | |
| | 559 | protected: |
| | 560 | SC_HAS_PROCESS(my_target); |
| | 561 | public: |
| | 562 | tlmt_simple_target_socket<my_target,32,soclib_vci_types> p_vci_target; ///< VCI target socket |
| | 563 | |
| | 564 | my_target(sc_core::sc_module_name name, |
| | 565 | const soclib::common::IntTab &index, |
| | 566 | const soclib::common::MappingTable &mt); |
| | 567 | |
| | 568 | ~my_target(); |
| 376 | | }} |
| 377 | | |
| 378 | | #endif |
| 379 | | |
| 380 | | ////////////////////////// vci_simple_target.cpp //////////////////////////////// |
| 381 | | |
| 382 | | #include "../include/vci_simple_target.h" |
| 383 | | |
| 384 | | namespace soclib { namespace tlmt { |
| 385 | | |
| 386 | | #define tmpl(x) template<typename vci_param> x VciSimpleTarget<vci_param> |
| 387 | | |
| 388 | | tmpl(tlmt_core::tlmt_return&)::cmdReceived(soclib::tlmt::vci_cmd_packet<vci_param> *pkt, |
| 389 | | const tlmt_core::tlmt_time &time, |
| 390 | | void *private_data) |
| 391 | | { |
| 392 | | uint32_t m_data[128]; |
| 393 | | |
| 394 | | if(pkt->cmd == vci_param::VCI_CMD_WRITE) { |
| 395 | | for(int i = 0 ; i < pkt->length ; i++) |
| 396 | | m_data[i] = cmd->buf[i]; |
| 397 | | } |
| 398 | | if(pkt->cmd == vci_param::VCI_CMD_READ) { |
| 399 | | for(int i = 0 ; i < pkt->length ; i++) |
| 400 | | cmd->buf[i] = m_data[i]; |
| 401 | | } |
| 402 | | rsp.srcid = pkt->srcid; |
| 403 | | rsp.trdid = pkt->trdid; |
| 404 | | rsp.pktid = pkt->pktid; |
| 405 | | rsp.length = pkt->length; |
| 406 | | rsp.error = 0; |
| 407 | | p_vci.send(&m_rsp, time+tlmt_core::tlmt_time(latency+pkt->length)) ; |
| 408 | | m_return.time=time+tlmt_core::tlmt_time(latency+pkt->length; |
| 409 | | return (m_return); |
| 410 | | } |
| 411 | | |
| 412 | | tmpl(/**/)::VciSimpleTarget(sc_core::sc_module_name name, |
| 413 | | uint32_t targetIndex, |
| 414 | | uint32_t latency) |
| 415 | | : soclib::tlmt::BaseModule(name), |
| 416 | | m_index(targetIndex), |
| 417 | | m_latency(latency), |
| 418 | | p_vci("vci", new tlmt_core::tlmt_callback<VciSimpleTarget,soclib::tlmt::vci_cmd_packet<vci_param> *>( |
| 419 | | this, &VciSimpleTarget<vci_param>::cmdReceived)) |
| 420 | | { |
| 421 | | } |
| 422 | | |
| 423 | | }} |
| | 571 | #endif |
| | 572 | |
| | 573 | ////////////////////////// my_target.cpp //////////////////////////////// |
| | 574 | |
| | 575 | #include "my_target.h" |
| | 576 | |
| | 577 | #ifndef MY_TARGET_DEBUG |
| | 578 | #define MY_TARGET_DEBUG 1 |
| | 579 | #endif |
| | 580 | |
| | 581 | #define tmpl(x) x my_target |
| | 582 | |
| | 583 | ////////////////////////////////////////////////////////////////////////////////////////// |
| | 584 | // CONSTRUCTOR |
| | 585 | ////////////////////////////////////////////////////////////////////////////////////////// |
| | 586 | tmpl(/**/)::my_target |
| | 587 | ( sc_core::sc_module_name name, |
| | 588 | const soclib::common::IntTab &index, |
| | 589 | const soclib::common::MappingTable &mt) |
| | 590 | : sc_module(name), |
| | 591 | m_mt(mt), |
| | 592 | p_vci_target("p_vci_target") |
| | 593 | { |
| | 594 | //register callback fuction |
| | 595 | p_vci_target.register_nb_transport_fw(this, &my_target::my_nb_transport_fw); |
| | 596 | |
| | 597 | m_id = m_mt.indexForId(index); |
| | 598 | } |
| | 599 | |
| | 600 | tmpl(/**/)::~my_target(){} |
| | 601 | |
| | 602 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 603 | // Virtual Fuctions tlm::tlm_fw_transport_if VCI SOCKET |
| | 604 | ///////////////////////////////////////////////////////////////////////////////////// |
| | 605 | |
| | 606 | //nb_transport_fw implementation calls from initiators |
| | 607 | tmpl(tlm::tlm_sync_enum)::my_nb_transport_fw // non-blocking transport call through Bus |
| | 608 | ( soclib_vci_types::vci_payload_type &payload, // VCI payload pointer |
| | 609 | soclib_vci_types::tlmt_phase_type &phase, // transaction phase |
| | 610 | sc_core::sc_time &time) // time |
| | 611 | { |
| | 612 | int nwords = payload.get_data_length() / vci_param::nbytes; |
| | 613 | switch(payload.get_command()){ |
| | 614 | case soclib::tlmt::VCI_READ_COMMAND: |
| | 615 | case soclib::tlmt::VCI_WRITE_COMMAND: |
| | 616 | case soclib::tlmt::VCI_LOCKED_READ_COMMAND: |
| | 617 | case soclib::tlmt::VCI_STORE_COND_COMMAND: |
| | 618 | { |
| | 619 | #if MY_TARGET_DEBUG |
| | 620 | std::cout << "[RAM " << m_id << "] Receive from source " << payload.get_src_id() <<" a packet "<< payload.get_pkt_id() << " Time = " << time.value() << std::endl; |
| | 621 | #endif |
| | 622 | |
| | 623 | payload.set_response_status(soclib::tlmt::TLMT_OK_RESPONSE); |
| | 624 | |
| | 625 | phase = soclib::tlmt::TLMT_VCI_RSP; |
| | 626 | time = time + (nwords * UNIT_TIME); |
| | 627 | |
| | 628 | #if MY_TARGET_DEBUG |
| | 629 | std::cout << "[RAM " << m_id << "] Send to source "<< payload.get_src_id() << " a anwser packet " << payload.get_pkt_id() << " Time = " << time.value() << std::endl; |
| | 630 | #endif |
| | 631 | |
| | 632 | p_vci_target->nb_transport_bw(payload, phase, time); |
| | 633 | return tlm::TLM_COMPLETED; |
| | 634 | } |
| | 635 | break; |
| | 636 | default: |
| | 637 | break; |
| | 638 | } |
| | 639 | |
| | 640 | //send error message |
| | 641 | payload.set_response_status(soclib::tlmt::TLMT_ERROR_RESPONSE); |
| | 642 | |
| | 643 | phase = soclib::tlmt::TLMT_VCI_RSP; |
| | 644 | time = time + nwords * UNIT_TIME; |
| | 645 | |
| | 646 | #if MY_TARGET_DEBUG |
| | 647 | std::cout << "[RAM " << m_id << "] Address " << payload.get_address() << " does not match any segment " << std::endl; |
| | 648 | std::cout << "[RAM " << m_id << "] Send to source "<< payload.get_src_id() << " a error packet with time = " << time.value() << std::endl; |
| | 649 | #endif |
| | 650 | p_vci_target->nb_transport_bw(payload, phase, time); |
| | 651 | return tlm::TLM_COMPLETED; |
| | 652 | } |
| 459 | | |
| 460 | | As described in Figure 4, when a VCI command packet - sent by the corresponding arbitration thread - is received by a VCI target, |
| 461 | | two synchronization mechanisms are activated : |
| 462 | | * The '''cmdReceived()''' function sends a VCI response packet with an associated time to the source initiator, through |
| 463 | | the '''!VciVgmn''' response network. The corresponding time can be used to update the initiator local clock. |
| 464 | | * The '''cmdReceived()''' function returns a time to the arbitration thread. This time is used to update the arbitration thread local |
| 465 | | clock. |
| 466 | | |
| 467 | | [[Image(tlmt_figure_4.png, nolink)]] |
| 468 | | |
| 469 | | = F) Interrupt modeling = |
| 470 | | |
| 471 | | Interrupts are asynchronous events that are not carried by the VCI network. |
| 472 | | |
| 473 | | As illustrated in Figure 5, each interrupt line is modeled by a specific point to point, uni-directional channel. This channel uses two ports of |
| 474 | | type '''tlmt_core::tlmt_out<bool>''' and '''tlmt_core::tlmt_in<bool>''' that must be declared as member variables of the source and |
| 475 | | destination modules respectively. |
| 476 | | |
| 477 | | [[Image(tlmt_figure_5.png, nolink)]] |
| 478 | | |
| 479 | | == F.1) Source modeling == |
| 480 | | |
| 481 | | The source module (named '''!VciSimpleSourceInterrupt''' in this example) must contain a member variable '''p_irq''' of |
| 482 | | type '''tlmt_core::tlmt_out<bool>'''. To activate, or desactivate an interruption, the source module must use the '''send()''' method, |
| 483 | | that is a member function of the '''tlmt_core::tlmt_out<bool>''' class. These interrupt packets transport both a Boolean, |
| 484 | | and a time. The '''send()''' prototype is defined as follows : |
| 485 | | {{{ |
| 486 | | void send( bool val, const tlmt_core::tlmt_time &time) |
| 487 | | }}} |
| 488 | | |
| 489 | | == F.2) Destination modeling == |
| 490 | | |
| 491 | | The destination module (named here '''!VciProcessor''') must contain a member variable '''p_irq''' of type |
| 492 | | '''tlmt_core::tlmt_in<bool>''', and a call-back function (named here '''irqReceived()''' that is executed when an interrupt |
| 493 | | packet is received on the '''p_irq''' port. |
| 494 | | |
| 495 | | A link between the '''p_irq''' port and the call-back function must be established by the port constructor in the constructor of |
| 496 | | the class '''VciProcessor''' : |
| 497 | | {{{ |
| 498 | | tlmt_core::tlmt_callback < VciProcessor,bool >(this, &VciProcessor < iss_t, |
| 499 | | vci_param >::irqReceived); |
| 500 | | }}} |
| 501 | | |
| 502 | | In the Parallel Discrete Event Simulation, the pessimistic approach relies on the fact that any PDES process is not allowed to update |
| 503 | | his local time until it has received messages on all its input ports with times greater than its local time. |
| 504 | | |
| 505 | | Therefore, a SC_THREAD modeling the behavior of a processor containing an '''tlmt_core::tlmt_in<bool>''' should in principle |
| 506 | | wait a timestamped packet on its interrupt port before executing instructions. However, such a behavior would be very inefficient, |
| 507 | | and is prone to dead-lock situations. |
| 508 | | |
| 509 | | The recommended policy for handling interrupts is the following: |
| 510 | | * The call-back function '''irqReceived()''' sets the member variables '''m_irqpending''' and '''m_irqtime''', when a interrupt packet |
| 511 | | is received on the '''p_irq''' port. |
| 512 | | * The '''execLoop()''' thread must test the '''m_irqpending''' variable at each cycle (i.e. in each iteration of |
| 513 | | the infinite loop). |
| 514 | | * If there is no interrupt pending, the thread continues its execution. If an interrupt is pending, and the interrupt time is greater |
| 515 | | than the local time, the thread continues execution. If the interrupt time is equal or smaller than the local time, the interrupt |
| 516 | | is handled. |
| 517 | | |
| 518 | | Such a violation of the the pessimistic parallel simulation principles creates a loss of accuracy on the interrupt handling |
| 519 | | timestamp. This loss of accuracy in the TLM-T simulation is acceptable, as interrupts are asynchronous events, and the timing error |
| 520 | | is bounded by the '''m_lookahead''' parameter. |
| 521 | | |
| 522 | | == F.3) Processor with interrupt example == |
| 523 | | |
| 524 | | {{{ |
| 525 | | |
| 526 | | ////////////////////////// vci_processor.h //////////////////////////////// |
| 527 | | |
| 528 | | namespace soclib { namespace tlmt { |
| 529 | | |
| 530 | | template<typename iss_t,typename vci_param> |
| 531 | | class VciProcessor |
| 532 | | : public soclib::tlmt::BaseModule |
| 533 | | { |
| 534 | | tlmt_core::tlmt_thread_context c0; |
| 535 | | sc_core::sc_event m_rsp_received; |
| 536 | | tlmt_core::tlmt_return m_return; |
| 537 | | bool m_irqpendig; // pending interrupt request |
| 538 | | tlmt_core::tlmt_time m_irqtime; // irq date |
| 539 | | uint32_t m_counter; // iteration counter |
| 540 | | uint32_t m_lookahead; // lookahead value |
| 541 | | |
| 542 | | protected: |
| 543 | | SC_HAS_PROCESS(VciProcessor); |
| 544 | | |
| 545 | | public: |
| 546 | | soclib::tlmt::VciInitiator<vci_param> p_vci; |
| 547 | | tlmt_core::tlmt_in<bool> p_irq; |
| 548 | | |
| 549 | | VciProcessor( sc_core::sc_module_name name, int id ); |
| 550 | | |
| 551 | | tlmt_core::tlmt_return &rspReceived(soclib::tlmt::vci_rsp_packet<vci_param> *pkt, |
| 552 | | const tlmt_core::tlmt_time &time, |
| 553 | | void *private_data); |
| 554 | | tlmt_core::tlmt_return &irqReceived(bool, |
| 555 | | const tlmt_core::tlmt_time &time, |
| 556 | | void *private_data); |
| 557 | | void execLoop(); |
| 558 | | }; |
| 559 | | |
| 560 | | }} |
| 561 | | |
| 562 | | ////////////////////////// vci_processor.cpp //////////////////////////////// |
| 563 | | |
| 564 | | #include "../include/vci_processor.h" |
| 565 | | |
| 566 | | namespace soclib |
| 567 | | { |
| 568 | | namespace tlmt |
| 569 | | { |
| 570 | | |
| 571 | | #define tmpl(x) template<typename iss_t, typename vci_param> x VciProcessor<vci_param> |
| 572 | | |
| 573 | | tmpl (tlmt_core::tlmt_return &)::rspReceived (soclib::tlmt:: vci_rsp_packet < vci_param > *pkt, |
| 574 | | const tlmt_core:: tlmt_time & time, void *private_data) |
| 575 | | { |
| 576 | | if (pkt->cmd == vci_param::CMD_WRITE) |
| 577 | | m_write_error = (pkt->error != 0); |
| 578 | | else |
| 579 | | m_write_error = false; |
| 580 | | if (pkt->cmd == vci_param::CMD_READ) |
| 581 | | m_read_error = (pkt->error != 0); |
| 582 | | else |
| 583 | | m_read_error = false; |
| 584 | | m_rsptime = time + tlmt_core::tlmt_time (pkt->length); |
| 585 | | m_vci_pending = false; |
| 586 | | m_rsp_received.notify (sc_core::SC_ZERO_TIME); |
| 587 | | |
| 588 | | return m_return; |
| 589 | | } |
| 590 | | |
| 591 | | tmpl (tlmt_core::tlmt_return &)::irqReceived (bool v, const tlmt_core:: |
| 592 | | tlmt_time & time, void *private_data) |
| 593 | | { |
| 594 | | m_irqpending = val; |
| 595 | | m_irqtime = time; |
| 596 | | |
| 597 | | return m_return; |
| 598 | | } |
| 599 | | |
| 600 | | |
| 601 | | tmpl (void)::execLoop () |
| 602 | | { |
| 603 | | while(1) { |
| 604 | | ... |
| 605 | | // test interrupts |
| 606 | | if (m_irqpending && (m_irqtime <= c0.time())) |
| 607 | | { |
| 608 | | // interrupt handling |
| 609 | | } |
| 610 | | ... |
| 611 | | // lookahead management |
| 612 | | m_counter++ ; |
| 613 | | if (m_counter >= m_lookahead) { |
| 614 | | m_counter = 0 ; |
| 615 | | sc_core::wait(sc_core::SC_ZERO_TIME) ; |
| 616 | | } // end if |
| 617 | | c0.set_time(c0.time()+tlmt_core::tlmt_time(1)) ; |
| 618 | | } // end while |
| 619 | | } |
| 620 | | |
| 621 | | tmpl ( /**/)::VciProcessor( |
| 622 | | sc_core::sc_module_name name, |
| 623 | | int id ) |
| 624 | | : soclib::tlmt::BaseModule (name), |
| 625 | | m_counter (0), |
| 626 | | m_lookahead (10), |
| 627 | | p_vci("vci",new tlmt_core::tlmt_callback<VciProcessor,vci_rsp_packet<vci_param>*>( |
| 628 | | this,&VciProcessor<vci_param>::rspReceived),&c0), |
| 629 | | p_irq("irq",new tlmt_core::tlmt_callback<VciProcesspr,bool>( |
| 630 | | this,&VciProcessor<vci_param>::irqReceived)) |
| 631 | | { |
| 632 | | SC_THREAD (execLoop); |
| 633 | | } |
| 634 | | |
| 635 | | }} |
| 636 | | |
| 637 | | }}} |
| 638 | | |