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 __SIMPLEBUSAT_H__ 21 #define __SIMPLEBUSAT_H__ 22 23 //#include <systemc> 24 #include "tlm.h" 25 26 #include "tlm_utils/simple_target_socket.h" 27 #include "tlm_utils/simple_initiator_socket.h" 28 29 #include "tlm_utils/peq_with_get.h" 30 31 template <int NR_OF_INITIATORS, int NR_OF_TARGETS> 32 class SimpleBusAT : public sc_core::sc_module 33 { 34 public: 35 typedef tlm::tlm_generic_payload transaction_type; 36 typedef tlm::tlm_phase phase_type; 37 typedef tlm::tlm_sync_enum sync_enum_type; 38 typedef tlm_utils::simple_target_socket_tagged<SimpleBusAT> target_socket_type; 39 typedef tlm_utils::simple_initiator_socket_tagged<SimpleBusAT> initiator_socket_type; 40 41 public: 42 target_socket_type target_socket[NR_OF_INITIATORS]; 43 initiator_socket_type initiator_socket[NR_OF_TARGETS]; 44 45 public: 46 SC_HAS_PROCESS(SimpleBusAT); SimpleBusAT(sc_core::sc_module_name name)47 SimpleBusAT(sc_core::sc_module_name name) : 48 sc_core::sc_module(name), 49 mRequestPEQ("requestPEQ"), 50 mResponsePEQ("responsePEQ") 51 { 52 for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) { 53 target_socket[i].register_nb_transport_fw(this, &SimpleBusAT::initiatorNBTransport, i); 54 target_socket[i].register_transport_dbg(this, &SimpleBusAT::transportDebug, i); 55 target_socket[i].register_get_direct_mem_ptr(this, &SimpleBusAT::getDMIPointer, i); 56 } 57 for (unsigned int i = 0; i < NR_OF_TARGETS; ++i) { 58 initiator_socket[i].register_nb_transport_bw(this, &SimpleBusAT::targetNBTransport, i); 59 initiator_socket[i].register_invalidate_direct_mem_ptr(this, &SimpleBusAT::invalidateDMIPointers, i); 60 } 61 62 SC_THREAD(RequestThread); 63 SC_THREAD(ResponseThread); 64 } 65 66 // 67 // Dummy decoder: 68 // - address[31-28]: portId 69 // - address[27-0]: masked address 70 // 71 getPortId(const sc_dt::uint64 & address)72 unsigned int getPortId(const sc_dt::uint64& address) 73 { 74 return (unsigned int)address >> 28; 75 } 76 getAddressOffset(unsigned int portId)77 sc_dt::uint64 getAddressOffset(unsigned int portId) 78 { 79 return portId << 28; 80 } 81 getAddressMask(unsigned int portId)82 sc_dt::uint64 getAddressMask(unsigned int portId) 83 { 84 return 0xfffffff; 85 } 86 decode(const sc_dt::uint64 & address)87 unsigned int decode(const sc_dt::uint64& address) 88 { 89 // decode address: 90 // - return initiator socket id 91 92 return getPortId(address); 93 } 94 95 // 96 // AT protocol 97 // 98 RequestThread()99 void RequestThread() 100 { 101 while (true) { 102 wait(mRequestPEQ.get_event()); 103 104 transaction_type* trans; 105 while ((trans = mRequestPEQ.get_next_transaction())!=0) { 106 unsigned int portId = decode(trans->get_address()); 107 assert(portId < NR_OF_TARGETS); 108 initiator_socket_type* decodeSocket = &initiator_socket[portId]; 109 trans->set_address(trans->get_address() & getAddressMask(portId)); 110 111 // Fill in the destination port 112 PendingTransactionsIterator it = mPendingTransactions.find(trans); 113 assert(it != mPendingTransactions.end()); 114 it->second.to = decodeSocket; 115 116 phase_type phase = tlm::BEGIN_REQ; 117 sc_core::sc_time t = sc_core::SC_ZERO_TIME; 118 119 // FIXME: No limitation on number of pending transactions 120 // All targets (that return false) must support multiple transactions 121 switch ((*decodeSocket)->nb_transport_fw(*trans, phase, t)) { 122 case tlm::TLM_ACCEPTED: 123 case tlm::TLM_UPDATED: 124 // Transaction not yet finished 125 if (phase == tlm::BEGIN_REQ) { 126 // Request phase not yet finished 127 wait(mEndRequestEvent); 128 129 } else if (phase == tlm::END_REQ) { 130 // Request phase finished, but response phase not yet started 131 wait(t); 132 133 } else if (phase == tlm::BEGIN_RESP) { 134 mResponsePEQ.notify(*trans, t); 135 // Not needed to send END_REQ to initiator 136 continue; 137 138 } else { // END_RESP 139 assert(0); exit(1); 140 } 141 142 // only send END_REQ to initiator if BEGIN_RESP was not already send 143 if (it->second.from) { 144 phase = tlm::END_REQ; 145 t = sc_core::SC_ZERO_TIME; 146 (*it->second.from)->nb_transport_bw(*trans, phase, t); 147 } 148 149 break; 150 151 case tlm::TLM_COMPLETED: 152 // Transaction finished 153 mResponsePEQ.notify(*trans, t); 154 155 // reset to destination port (we must not send END_RESP to target) 156 it->second.to = 0; 157 158 wait(t); 159 break; 160 161 default: 162 assert(0); exit(1); 163 }; 164 } 165 } 166 } 167 ResponseThread()168 void ResponseThread() 169 { 170 while (true) { 171 wait(mResponsePEQ.get_event()); 172 173 transaction_type* trans; 174 while ((trans = mResponsePEQ.get_next_transaction())!=0) { 175 PendingTransactionsIterator it = mPendingTransactions.find(trans); 176 assert(it != mPendingTransactions.end()); 177 178 phase_type phase = tlm::BEGIN_RESP; 179 sc_core::sc_time t = sc_core::SC_ZERO_TIME; 180 181 target_socket_type* initiatorSocket = it->second.from; 182 // if BEGIN_RESP is send first we don't have to send END_REQ anymore 183 it->second.from = 0; 184 185 switch ((*initiatorSocket)->nb_transport_bw(*trans, phase, t)) { 186 case tlm::TLM_COMPLETED: 187 // Transaction finished 188 wait(t); 189 break; 190 191 case tlm::TLM_ACCEPTED: 192 case tlm::TLM_UPDATED: 193 // Transaction not yet finished 194 wait(mEndResponseEvent); 195 break; 196 197 default: 198 assert(0); exit(1); 199 }; 200 201 // forward END_RESP to target 202 if (it->second.to) { 203 phase = tlm::END_RESP; 204 t = sc_core::SC_ZERO_TIME; 205 sync_enum_type r = (*it->second.to)->nb_transport_fw(*trans, phase, t); 206 assert(r == tlm::TLM_COMPLETED); (void)r; 207 } 208 209 mPendingTransactions.erase(it); 210 trans->release(); 211 } 212 } 213 } 214 215 // 216 // interface methods 217 // 218 initiatorNBTransport(int initiator_id,transaction_type & trans,phase_type & phase,sc_core::sc_time & t)219 sync_enum_type initiatorNBTransport(int initiator_id, 220 transaction_type& trans, 221 phase_type& phase, 222 sc_core::sc_time& t) 223 { 224 if (phase == tlm::BEGIN_REQ) { 225 trans.acquire(); 226 addPendingTransaction(trans, 0, initiator_id); 227 228 mRequestPEQ.notify(trans, t); 229 230 } else if (phase == tlm::END_RESP) { 231 mEndResponseEvent.notify(t); 232 return tlm::TLM_COMPLETED; 233 234 } else { 235 std::cout << "ERROR: '" << name() 236 << "': Illegal phase received from initiator." << std::endl; 237 assert(false); exit(1); 238 } 239 240 return tlm::TLM_ACCEPTED; 241 } 242 targetNBTransport(int portId,transaction_type & trans,phase_type & phase,sc_core::sc_time & t)243 sync_enum_type targetNBTransport(int portId, 244 transaction_type& trans, 245 phase_type& phase, 246 sc_core::sc_time& t) 247 { 248 if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) { 249 std::cout << "ERROR: '" << name() 250 << "': Illegal phase received from target." << std::endl; 251 assert(false); exit(1); 252 } 253 254 mEndRequestEvent.notify(t); 255 if (phase == tlm::BEGIN_RESP) { 256 mResponsePEQ.notify(trans, t); 257 } 258 259 return tlm::TLM_ACCEPTED; 260 } 261 transportDebug(int initiator_id,transaction_type & trans)262 unsigned int transportDebug(int initiator_id, transaction_type& trans) 263 { 264 unsigned int portId = decode(trans.get_address()); 265 assert(portId < NR_OF_TARGETS); 266 initiator_socket_type* decodeSocket = &initiator_socket[portId]; 267 trans.set_address( trans.get_address() & getAddressMask(portId) ); 268 269 return (*decodeSocket)->transport_dbg(trans); 270 } 271 limitRange(unsigned int portId,sc_dt::uint64 & low,sc_dt::uint64 & high)272 bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high) 273 { 274 sc_dt::uint64 addressOffset = getAddressOffset(portId); 275 sc_dt::uint64 addressMask = getAddressMask(portId); 276 277 if (low > addressMask) { 278 // Range does not overlap with addressrange for this target 279 return false; 280 } 281 282 low += addressOffset; 283 if (high > addressMask) { 284 high = addressOffset + addressMask; 285 286 } else { 287 high += addressOffset; 288 } 289 return true; 290 } 291 getDMIPointer(int initiator_id,transaction_type & trans,tlm::tlm_dmi & dmi_data)292 bool getDMIPointer(int initiator_id, 293 transaction_type& trans, 294 tlm::tlm_dmi& dmi_data) 295 { 296 // FIXME: DMI not supported for AT bus? 297 sc_dt::uint64 address = trans.get_address(); 298 299 unsigned int portId = decode(address); 300 assert(portId < NR_OF_TARGETS); 301 initiator_socket_type* decodeSocket = &initiator_socket[portId]; 302 sc_dt::uint64 maskedAddress = address & getAddressMask(portId); 303 304 trans.set_address(maskedAddress); 305 306 bool result = 307 (*decodeSocket)->get_direct_mem_ptr(trans, dmi_data); 308 309 if (result) 310 { 311 // Range must contain address 312 assert(dmi_data.get_start_address() <= maskedAddress); 313 assert(dmi_data.get_end_address() >= maskedAddress); 314 } 315 316 // Should always succeed 317 sc_dt::uint64 start, end; 318 start = dmi_data.get_start_address(); 319 end = dmi_data.get_end_address(); 320 321 limitRange(portId, start, end); 322 323 dmi_data.set_start_address(start); 324 dmi_data.set_end_address(end); 325 326 return result; 327 } 328 invalidateDMIPointers(int portId,sc_dt::uint64 start_range,sc_dt::uint64 end_range)329 void invalidateDMIPointers(int portId, 330 sc_dt::uint64 start_range, 331 sc_dt::uint64 end_range) 332 { 333 // FIXME: probably faster to always invalidate everything? 334 335 if ((portId >= 0) && !limitRange(portId, start_range, end_range)) { 336 // Range does not fall into address range of target 337 return; 338 } 339 340 for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) { 341 (target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range); 342 } 343 } 344 345 private: addPendingTransaction(transaction_type & trans,initiator_socket_type * to,int initiatorId)346 void addPendingTransaction(transaction_type& trans, 347 initiator_socket_type* to, 348 int initiatorId) 349 { 350 const ConnectionInfo info = { &target_socket[initiatorId], to }; 351 assert(mPendingTransactions.find(&trans) == mPendingTransactions.end()); 352 mPendingTransactions[&trans] = info; 353 } 354 355 private: 356 struct ConnectionInfo { 357 target_socket_type* from; 358 initiator_socket_type* to; 359 }; 360 typedef std::map<transaction_type*, ConnectionInfo> PendingTransactions; 361 typedef typename PendingTransactions::iterator PendingTransactionsIterator; 362 typedef typename PendingTransactions::const_iterator PendingTransactionsConstIterator; 363 364 private: 365 PendingTransactions mPendingTransactions; 366 367 tlm_utils::peq_with_get<transaction_type> mRequestPEQ; 368 sc_core::sc_event mBeginRequestEvent; 369 sc_core::sc_event mEndRequestEvent; 370 371 tlm_utils::peq_with_get<transaction_type> mResponsePEQ; 372 sc_core::sc_event mBeginResponseEvent; 373 sc_core::sc_event mEndResponseEvent; 374 }; 375 376 #endif 377