sc_target.cc revision 11818:f12963cb9dc2
1/* 2 * Copyright (c) 2015, University of Kaiserslautern 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of the copyright holder nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * Authors: Matthias Jung 33 */ 34 35#include "sc_target.hh" 36 37using namespace sc_core; 38using namespace std; 39 40Target::Target(sc_core::sc_module_name name, 41 bool debug, 42 unsigned long long int size, 43 unsigned int offset) : 44 socket("socket"), 45 transaction_in_progress(0), 46 response_in_progress(false), 47 next_response_pending(0), 48 end_req_pending(0), 49 m_peq(this, &Target::peq_cb), 50 debug(debug), 51 size(size), 52 offset(offset) 53{ 54 /* Register tlm transport functions */ 55 socket.register_b_transport(this, &Target::b_transport); 56 socket.register_transport_dbg(this, &Target::transport_dbg); 57 socket.register_nb_transport_fw(this, &Target::nb_transport_fw); 58 59 60 /* allocate storage memory */ 61 mem = new unsigned char[size]; 62 63 SC_METHOD(execute_transaction_process); 64 sensitive << target_done_event; 65 dont_initialize(); 66} 67 68void 69Target::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay) 70{ 71 /* Execute the read or write commands */ 72 execute_transaction(trans); 73} 74 75unsigned int 76Target::transport_dbg(tlm::tlm_generic_payload& trans) 77{ 78 tlm::tlm_command cmd = trans.get_command(); 79 sc_dt::uint64 adr = trans.get_address() - offset; 80 unsigned char* ptr = trans.get_data_ptr(); 81 unsigned int len = trans.get_data_length(); 82 83 unsigned char *mem_array_ptr = mem + adr; 84 85 /* Load / Store the access: */ 86 if ( cmd == tlm::TLM_READ_COMMAND ) { 87 if (debug) { 88 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND"); 89 } 90 std::memcpy(ptr, mem_array_ptr, len); 91 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) { 92 if (debug) { 93 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND"); 94 } 95 std::memcpy(mem_array_ptr, ptr, len); 96 } 97 98 return len; 99} 100 101 102/* TLM-2 non-blocking transport method */ 103tlm::tlm_sync_enum Target::nb_transport_fw(tlm::tlm_generic_payload& trans, 104 tlm::tlm_phase& phase, 105 sc_time& delay) 106{ 107 /* Queue the transaction until the annotated time has elapsed */ 108 m_peq.notify(trans, phase, delay); 109 return tlm::TLM_ACCEPTED; 110} 111 112void 113Target::peq_cb(tlm::tlm_generic_payload& trans, 114 const tlm::tlm_phase& phase) 115{ 116 sc_time delay; 117 118 if (phase == tlm::BEGIN_REQ) { 119 if (debug) SC_REPORT_INFO("target", "tlm::BEGIN_REQ"); 120 121 /* Increment the transaction reference count */ 122 trans.acquire(); 123 124 if ( !transaction_in_progress ) { 125 send_end_req(trans); 126 } else { 127 /* Put back-pressure on initiator by deferring END_REQ until 128 * pipeline is clear */ 129 end_req_pending = &trans; 130 } 131 } else if (phase == tlm::END_RESP) { 132 /* On receiving END_RESP, the target can release the transaction and 133 * allow other pending transactions to proceed */ 134 if (!response_in_progress) { 135 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase END_RESP" 136 "received by target"); 137 } 138 139 transaction_in_progress = 0; 140 141 /* Target itself is now clear to issue the next BEGIN_RESP */ 142 response_in_progress = false; 143 if (next_response_pending) { 144 send_response( *next_response_pending ); 145 next_response_pending = 0; 146 } 147 148 /* ... and to unblock the initiator by issuing END_REQ */ 149 if (end_req_pending) { 150 send_end_req( *end_req_pending ); 151 end_req_pending = 0; 152 } 153 154 } else /* tlm::END_REQ or tlm::BEGIN_RESP */ { 155 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by" 156 "target"); 157 } 158} 159 160void 161Target::send_end_req(tlm::tlm_generic_payload& trans) 162{ 163 tlm::tlm_phase bw_phase; 164 sc_time delay; 165 166 /* Queue the acceptance and the response with the appropriate latency */ 167 bw_phase = tlm::END_REQ; 168 delay = sc_time(10.0, SC_NS); // Accept delay 169 170 tlm::tlm_sync_enum status; 171 status = socket->nb_transport_bw(trans, bw_phase, delay); 172 173 /* Ignore return value; 174 * initiator cannot terminate transaction at this point 175 * Queue internal event to mark beginning of response: */ 176 delay = delay + sc_time(40.0, SC_NS); // Latency 177 target_done_event.notify(delay); 178 179 assert(transaction_in_progress == 0); 180 transaction_in_progress = &trans; 181} 182 183void 184Target::execute_transaction_process() 185{ 186 /* Execute the read or write commands */ 187 execute_transaction( *transaction_in_progress ); 188 189 /* Target must honor BEGIN_RESP/END_RESP exclusion rule; i.e. must not 190 * send BEGIN_RESP until receiving previous END_RESP or BEGIN_REQ */ 191 if (response_in_progress) { 192 /* Target allows only two transactions in-flight */ 193 if (next_response_pending) { 194 SC_REPORT_FATAL("TLM-2", "Attempt to have two pending responses" 195 "in target"); 196 } 197 next_response_pending = transaction_in_progress; 198 } else { 199 send_response( *transaction_in_progress ); 200 } 201} 202 203void 204Target::execute_transaction(tlm::tlm_generic_payload& trans) 205{ 206 tlm::tlm_command cmd = trans.get_command(); 207 sc_dt::uint64 adr = trans.get_address() - offset; 208 unsigned char* ptr = trans.get_data_ptr(); 209 unsigned int len = trans.get_data_length(); 210 unsigned char* byt = trans.get_byte_enable_ptr(); 211 unsigned int wid = trans.get_streaming_width(); 212 213 if ( byt != 0 ) { 214 cout << "Byte Error" << endl; 215 trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); 216 return; 217 } 218 219 //if ( len > 4 || wid < len ) { 220 // cout << "Burst Error len=" << len << " wid=" << wid << endl; 221 // trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); 222 // return; 223 //} 224 225 unsigned char *mem_array_ptr = mem + adr; 226 227 /* Load / Store the access: */ 228 if ( cmd == tlm::TLM_READ_COMMAND ) { 229 if (debug) { 230 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND"); 231 } 232 std::memcpy(ptr, mem_array_ptr, len); 233 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) { 234 if (debug) { 235 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND"); 236 } 237 std::memcpy(mem_array_ptr, ptr, len); 238 } 239 240 trans.set_response_status( tlm::TLM_OK_RESPONSE ); 241} 242 243void 244Target::send_response(tlm::tlm_generic_payload& trans) 245{ 246 tlm::tlm_sync_enum status; 247 tlm::tlm_phase bw_phase; 248 sc_time delay; 249 250 response_in_progress = true; 251 bw_phase = tlm::BEGIN_RESP; 252 delay = sc_time(10.0, SC_NS); 253 status = socket->nb_transport_bw( trans, bw_phase, delay ); 254 255 if (status == tlm::TLM_UPDATED) { 256 /* The timing annotation must be honored */ 257 m_peq.notify(trans, bw_phase, delay); 258 } else if (status == tlm::TLM_COMPLETED) { 259 /* The initiator has terminated the transaction */ 260 transaction_in_progress = 0; 261 response_in_progress = false; 262 } 263 trans.release(); 264} 265