SimpleLTInitiator_ext.h revision 12855:588919e0e4aa
1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20#ifndef __SIMPLE_LT_INITIATOR_EXT_H__ 21#define __SIMPLE_LT_INITIATOR_EXT_H__ 22 23#include "tlm.h" 24#include "tlm_utils/simple_initiator_socket.h" 25#include "my_extension.h" 26 27#include <systemc> 28#include <cassert> 29#include <iostream> 30#include <iomanip> 31#include <map> 32 33class SimpleLTInitiator_ext : public sc_core::sc_module 34{ 35public: 36 typedef tlm::tlm_generic_payload transaction_type; 37 typedef tlm::tlm_dmi dmi_type; 38 typedef tlm::tlm_phase phase_type; 39 typedef tlm::tlm_sync_enum sync_enum_type; 40 typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator_ext, 32, 41 my_extended_payload_types> initiator_socket_type; 42 43public: 44 initiator_socket_type socket; 45 46public: 47 SC_HAS_PROCESS(SimpleLTInitiator_ext); 48 SimpleLTInitiator_ext(sc_core::sc_module_name name, 49 unsigned int nrOfTransactions = 0x5, 50 unsigned int baseAddress = 0x0) : 51 sc_core::sc_module(name), 52 socket("socket"), 53 mNrOfTransactions(nrOfTransactions), 54 mBaseAddress(baseAddress), 55 mTransactionCount(0) 56 { 57 invalidate(mDMIData); 58 59 // register nb_transport method 60 socket.register_nb_transport_bw(this, &SimpleLTInitiator_ext::myNBTransport); 61 socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator_ext::invalidate_direct_mem_ptr); 62 63 // Initiator thread 64 SC_THREAD(run); 65 66 } 67 68 bool initTransaction(transaction_type& trans) 69 { 70 // initialize DMI hint: 71 trans.set_dmi_allowed(false); 72 73 if (mTransactionCount < mNrOfTransactions) 74 { 75 trans.set_address(mBaseAddress + 4*mTransactionCount); 76 mData = mTransactionCount; 77 trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 78 trans.set_command(tlm::TLM_WRITE_COMMAND); 79 80 } 81 else if (mTransactionCount < 2 * mNrOfTransactions) 82 { 83 trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions)); 84 mData = 0; 85 trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 86 trans.set_command(tlm::TLM_READ_COMMAND); 87 88 } 89 else 90 { 91 return false; 92 } 93 94 ++mTransactionCount; 95 return true; 96 } 97 98 void logStartTransation(transaction_type& trans) 99 { 100 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) 101 { 102 std::cout << name() << ": Send write request: A = 0x" 103 << std::hex << (unsigned int)trans.get_address() 104 << ", D = 0x" << mData << std::dec 105 << " @ " << sc_core::sc_time_stamp() << std::endl; 106 107 } 108 else 109 { 110 std::cout << name() << ": Send read request: A = 0x" 111 << std::hex << (unsigned int)trans.get_address() 112 << std::dec 113 << " @ " << sc_core::sc_time_stamp() << std::endl; 114 } 115 } 116 117 void logEndTransaction(transaction_type& trans) 118 { 119 if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) { 120 std::cout << name() << ": Received error response @ " 121 << sc_core::sc_time_stamp() << std::endl; 122 } 123 else 124 { 125 std::cout << name() << ": Received ok response"; 126 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 127 std::cout << ": D = 0x" << std::hex << mData << std::dec; 128 } 129 std::cout << " @ " << sc_core::sc_time_stamp() << std::endl; 130 } 131 } 132 133 void run() 134 { 135 transaction_type trans; 136 phase_type phase; 137 sc_core::sc_time t; 138 // make sure that our transaction has the proper extension: 139 my_extension* tmp_ext = new my_extension(); 140 tmp_ext->m_data = 11; 141 142 trans.set_extension(tmp_ext); 143 144 while (initTransaction(trans)) 145 { 146 // Create transaction and initialise phase and t 147 phase = tlm::BEGIN_REQ; 148 t = sc_core::SC_ZERO_TIME; 149 150 logStartTransation(trans); 151 /////////////////////////////////////////////////////////// 152 // DMI handling: 153 // We use the DMI hint to check if it makes sense to ask for 154 // DMI pointers. The pattern is: 155 // - if the address is covered by a DMI region do a DMI access 156 // - otherwise do a normal transaction 157 // -> check if we get a DMI hint and acquire the DMI pointers if it 158 // is set 159 /////////////////////////////////////////////////////////// 160 161 // Check if the address is covered by our DMI region 162 if ( (trans.get_address() >= mDMIData.get_start_address()) && 163 (trans.get_address() <= mDMIData.get_end_address()) ) 164 { 165 // We can handle the data here. As the logEndTransaction is 166 // assuming something to happen in the data structure, we really 167 // need to do this: 168 trans.set_response_status(tlm::TLM_OK_RESPONSE); 169 sc_dt::uint64 tmp = trans.get_address() - mDMIData.get_start_address(); 170 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 171 *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp] = mData; 172 173 } else { 174 mData = *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp]; 175 } 176 177 // Do the wait immediately. Note that doing the wait here eats 178 // almost all the performance anyway, so we only gain something 179 // if we're using temporal decoupling. 180 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 181 wait(mDMIData.get_write_latency()); 182 183 } else { 184 wait(mDMIData.get_read_latency()); 185 } 186 187 logEndTransaction(trans); 188 189 } else { // we need a full transaction 190 switch (socket->nb_transport_fw(trans, phase, t)) { 191 case tlm::TLM_COMPLETED: 192 // Transaction Finished, wait for the returned delay 193 wait(t); 194 break; 195 196 case tlm::TLM_ACCEPTED: 197 case tlm::TLM_UPDATED: 198 // Transaction not yet finished, wait for the end of it 199 wait(mEndEvent); 200 break; 201 202 default: 203 sc_assert(0); exit(1); 204 }; 205 206 logEndTransaction(trans); 207 208 // Acquire DMI pointer if one is available: 209 if (trans.is_dmi_allowed()) 210 { 211 trans.set_write(); 212 dmi_type tmp; 213 if (socket->get_direct_mem_ptr(trans, 214 tmp)) 215 { 216 // FIXME: No support for separate read/write ranges 217 sc_assert(tmp.is_read_write_allowed()); 218 mDMIData = tmp; 219 } 220 } 221 } 222 } 223 delete tmp_ext; 224 wait(); 225 226 } 227 228 sync_enum_type myNBTransport(transaction_type& trans, 229 phase_type& phase, 230 sc_core::sc_time& t) 231 { 232 switch (phase) { 233 case tlm::END_REQ: 234 // Request phase ended 235 return tlm::TLM_ACCEPTED; 236 237 case tlm::BEGIN_RESP: 238 sc_assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0? 239 mEndEvent.notify(t); 240 // Not needed to update the phase if true is returned 241 return tlm::TLM_COMPLETED; 242 243 case tlm::BEGIN_REQ: // fall-through 244 case tlm::END_RESP: // fall-through 245 default: 246 // A target should never call nb_transport with these phases 247 sc_assert(0); exit(1); 248// return tlm::TLM_COMPLETED; //unreachable code 249 }; 250 } 251 252 void invalidate(dmi_type& dmiData) 253 { 254 dmiData.set_start_address(1); 255 dmiData.set_end_address(0); 256 } 257 258 // Invalidate DMI pointer(s) 259 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 260 sc_dt::uint64 end_range) 261 { 262 // do the invalidation if there is an address range overlap 263 if (start_range <= mDMIData.get_end_address ()&& 264 end_range >= mDMIData.get_start_address()) { 265 std::cout << name() << ": got DMI pointer invalidation" 266 << " @ " << sc_core::sc_time_stamp() << std::endl; 267 268 invalidate(mDMIData); 269 } else { 270 std::cout << name() << ": ignored DMI invalidation for addresses " 271 << std::hex << start_range << ", " 272 << end_range << std::dec 273 << " @ " << sc_core::sc_time_stamp() << std::endl; 274 } 275 } 276 277 // Test for transport_dbg, this one should fail in bus_dmi as we address 278 // a target that doesn't support transport_dbg: 279 // FIXME: use a configurable address 280 void end_of_simulation() 281 { 282 std::cout << name() << ", <<SimpleLTInitiator1>>:" << std::endl 283 << std::endl; 284 unsigned char data[32]; 285 286 transaction_type trans; 287 trans.set_address(mBaseAddress); 288 trans.set_data_length(32); 289 trans.set_data_ptr(data); 290 trans.set_read(); 291 292 unsigned int n = socket->transport_dbg(trans); 293 294 std::cout << "Mem @" << std::hex << mBaseAddress << std::endl; 295 unsigned int j = 0; 296 297 if (n > 0) 298 { 299 // always align endianness, so that we don't get a diff when 300 // printing the raw data 301 int e_start = 0; 302 int e_end = 4; 303 int e_increment = 1; 304 if (!tlm::host_has_little_endianness()) 305 { 306 e_start = 3; 307 e_end = -1; 308 e_increment = -1; 309 } 310 311 for (unsigned int i=0; i<n; i+=4) 312 { 313 for (int k=e_start; k!=e_end; k+=e_increment) 314 { 315 std::cout << std::setw(2) << std::setfill('0') 316 << (int)data[i+k]; 317 j++; 318 if (j==16) { 319 j=0; 320 std::cout << std::endl; 321 } else { 322 std::cout << " "; 323 } 324 } 325 } 326 } 327 else 328 { 329 std::cout << "OK: debug transaction didn't give data." << std::endl; 330 } 331 std::cout << std::dec << std::endl; 332 } 333private: 334 dmi_type mDMIData; 335 336 sc_core::sc_event mEndEvent; 337 unsigned int mNrOfTransactions; 338 unsigned int mBaseAddress; 339 unsigned int mTransactionCount; 340 unsigned int mData; 341}; 342 343#endif 344