sc_target.cc revision 12048:a280e9bc358d
13561SN/A/* 23561SN/A * Copyright (c) 2015, University of Kaiserslautern 33561SN/A * All rights reserved. 43561SN/A * 53561SN/A * Redistribution and use in source and binary forms, with or without 63561SN/A * modification, are permitted provided that the following conditions are 73561SN/A * met: 83561SN/A * 93561SN/A * 1. Redistributions of source code must retain the above copyright notice, 103561SN/A * this list of conditions and the following disclaimer. 113561SN/A * 123561SN/A * 2. Redistributions in binary form must reproduce the above copyright 133561SN/A * notice, this list of conditions and the following disclaimer in the 143561SN/A * documentation and/or other materials provided with the distribution. 153561SN/A * 163561SN/A * 3. Neither the name of the copyright holder nor the names of its 173561SN/A * contributors may be used to endorse or promote products derived from 183561SN/A * this software without specific prior written permission. 193561SN/A * 203561SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 213561SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 223561SN/A * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 233561SN/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 243561SN/A * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 253561SN/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 263561SN/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 273561SN/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 283561SN/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 293561SN/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 303561SN/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 313561SN/A * 323561SN/A * Authors: Matthias Jung 333561SN/A */ 343561SN/A 353561SN/A#include "sc_target.hh" 363561SN/A 373561SN/Ausing namespace sc_core; 383561SN/Ausing namespace std; 393565Sgblack@eecs.umich.edu 403561SN/ATarget::Target(sc_core::sc_module_name name, 413561SN/A bool debug, 423561SN/A unsigned long long int size, 433561SN/A unsigned int offset) : 443561SN/A socket("socket"), 453561SN/A transaction_in_progress(0), 463561SN/A response_in_progress(false), 473561SN/A next_response_pending(0), 483561SN/A end_req_pending(0), 493561SN/A m_peq(this, &Target::peq_cb), 503561SN/A debug(debug), 513561SN/A size(size), 523561SN/A offset(offset) 533561SN/A{ 543561SN/A /* Register tlm transport functions */ 553561SN/A socket.register_b_transport(this, &Target::b_transport); 563561SN/A socket.register_transport_dbg(this, &Target::transport_dbg); 573561SN/A 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::check_address(unsigned long long int addr) 70{ 71 if (addr < offset || addr >= offset + size) 72 SC_REPORT_FATAL("Target", "Address out of range. Did you set an " 73 "appropriate size and offset?"); 74} 75 76void 77Target::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay) 78{ 79 /* Execute the read or write commands */ 80 execute_transaction(trans); 81} 82 83unsigned int 84Target::transport_dbg(tlm::tlm_generic_payload& trans) 85{ 86 check_address(trans.get_address()); 87 88 tlm::tlm_command cmd = trans.get_command(); 89 sc_dt::uint64 adr = trans.get_address() - offset; 90 unsigned char* ptr = trans.get_data_ptr(); 91 unsigned int len = trans.get_data_length(); 92 93 unsigned char *mem_array_ptr = mem + adr; 94 95 /* Load / Store the access: */ 96 if ( cmd == tlm::TLM_READ_COMMAND ) { 97 if (debug) { 98 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND"); 99 } 100 std::memcpy(ptr, mem_array_ptr, len); 101 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) { 102 if (debug) { 103 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND"); 104 } 105 std::memcpy(mem_array_ptr, ptr, len); 106 } 107 108 return len; 109} 110 111 112/* TLM-2 non-blocking transport method */ 113tlm::tlm_sync_enum Target::nb_transport_fw(tlm::tlm_generic_payload& trans, 114 tlm::tlm_phase& phase, 115 sc_time& delay) 116{ 117 /* Queue the transaction until the annotated time has elapsed */ 118 m_peq.notify(trans, phase, delay); 119 return tlm::TLM_ACCEPTED; 120} 121 122void 123Target::peq_cb(tlm::tlm_generic_payload& trans, 124 const tlm::tlm_phase& phase) 125{ 126 sc_time delay; 127 128 if (phase == tlm::BEGIN_REQ) { 129 if (debug) SC_REPORT_INFO("target", "tlm::BEGIN_REQ"); 130 131 /* Increment the transaction reference count */ 132 trans.acquire(); 133 134 if ( !transaction_in_progress ) { 135 send_end_req(trans); 136 } else { 137 /* Put back-pressure on initiator by deferring END_REQ until 138 * pipeline is clear */ 139 end_req_pending = &trans; 140 } 141 } else if (phase == tlm::END_RESP) { 142 /* On receiving END_RESP, the target can release the transaction and 143 * allow other pending transactions to proceed */ 144 if (!response_in_progress) { 145 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase END_RESP" 146 "received by target"); 147 } 148 149 transaction_in_progress = 0; 150 151 /* Target itself is now clear to issue the next BEGIN_RESP */ 152 response_in_progress = false; 153 if (next_response_pending) { 154 send_response( *next_response_pending ); 155 next_response_pending = 0; 156 } 157 158 /* ... and to unblock the initiator by issuing END_REQ */ 159 if (end_req_pending) { 160 send_end_req( *end_req_pending ); 161 end_req_pending = 0; 162 } 163 164 } else /* tlm::END_REQ or tlm::BEGIN_RESP */ { 165 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by" 166 "target"); 167 } 168} 169 170void 171Target::send_end_req(tlm::tlm_generic_payload& trans) 172{ 173 tlm::tlm_phase bw_phase; 174 sc_time delay; 175 176 /* Queue the acceptance and the response with the appropriate latency */ 177 bw_phase = tlm::END_REQ; 178 delay = sc_time(10.0, SC_NS); // Accept delay 179 180 tlm::tlm_sync_enum status; 181 status = socket->nb_transport_bw(trans, bw_phase, delay); 182 183 /* Ignore return value; 184 * initiator cannot terminate transaction at this point 185 * Queue internal event to mark beginning of response: */ 186 delay = delay + sc_time(40.0, SC_NS); // Latency 187 target_done_event.notify(delay); 188 189 assert(transaction_in_progress == 0); 190 transaction_in_progress = &trans; 191} 192 193void 194Target::execute_transaction_process() 195{ 196 /* Execute the read or write commands */ 197 execute_transaction( *transaction_in_progress ); 198 199 /* Target must honor BEGIN_RESP/END_RESP exclusion rule; i.e. must not 200 * send BEGIN_RESP until receiving previous END_RESP or BEGIN_REQ */ 201 if (response_in_progress) { 202 /* Target allows only two transactions in-flight */ 203 if (next_response_pending) { 204 SC_REPORT_FATAL("TLM-2", "Attempt to have two pending responses" 205 "in target"); 206 } 207 next_response_pending = transaction_in_progress; 208 } else { 209 send_response( *transaction_in_progress ); 210 } 211} 212 213void 214Target::execute_transaction(tlm::tlm_generic_payload& trans) 215{ 216 check_address(trans.get_address()); 217 218 tlm::tlm_command cmd = trans.get_command(); 219 sc_dt::uint64 adr = trans.get_address() - offset; 220 unsigned char* ptr = trans.get_data_ptr(); 221 unsigned int len = trans.get_data_length(); 222 unsigned char* byt = trans.get_byte_enable_ptr(); 223 unsigned int wid = trans.get_streaming_width(); 224 225 if ( byt != 0 ) { 226 cout << "Byte Error" << endl; 227 trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); 228 return; 229 } 230 231 //if ( len > 4 || wid < len ) { 232 // cout << "Burst Error len=" << len << " wid=" << wid << endl; 233 // trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); 234 // return; 235 //} 236 237 unsigned char *mem_array_ptr = mem + adr; 238 239 /* Load / Store the access: */ 240 if ( cmd == tlm::TLM_READ_COMMAND ) { 241 if (debug) { 242 SC_REPORT_INFO("target", "tlm::TLM_READ_COMMAND"); 243 } 244 std::memcpy(ptr, mem_array_ptr, len); 245 } else if ( cmd == tlm::TLM_WRITE_COMMAND ) { 246 if (debug) { 247 SC_REPORT_INFO("target", "tlm::TLM_WRITE_COMMAND"); 248 } 249 std::memcpy(mem_array_ptr, ptr, len); 250 } 251 252 trans.set_response_status( tlm::TLM_OK_RESPONSE ); 253} 254 255void 256Target::send_response(tlm::tlm_generic_payload& trans) 257{ 258 tlm::tlm_sync_enum status; 259 tlm::tlm_phase bw_phase; 260 sc_time delay; 261 262 response_in_progress = true; 263 bw_phase = tlm::BEGIN_RESP; 264 delay = sc_time(10.0, SC_NS); 265 status = socket->nb_transport_bw( trans, bw_phase, delay ); 266 267 if (status == tlm::TLM_UPDATED) { 268 /* The timing annotation must be honored */ 269 m_peq.notify(trans, bw_phase, delay); 270 } else if (status == tlm::TLM_COMPLETED) { 271 /* The initiator has terminated the transaction */ 272 transaction_in_progress = 0; 273 response_in_progress = false; 274 } 275 trans.release(); 276} 277