SimpleBusAT.h revision 12922
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 31template <int NR_OF_INITIATORS, int NR_OF_TARGETS> 32class SimpleBusAT : public sc_core::sc_module 33{ 34public: 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 41public: 42 target_socket_type target_socket[NR_OF_INITIATORS]; 43 initiator_socket_type initiator_socket[NR_OF_TARGETS]; 44 45public: 46 SC_HAS_PROCESS(SimpleBusAT); 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 72 unsigned int getPortId(const sc_dt::uint64& address) 73 { 74 return (unsigned int)address >> 28; 75 } 76 77 sc_dt::uint64 getAddressOffset(unsigned int portId) 78 { 79 return portId << 28; 80 } 81 82 sc_dt::uint64 getAddressMask(unsigned int portId) 83 { 84 return 0xfffffff; 85 } 86 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 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 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 #if ( ! NDEBUG ) 206 sync_enum_type r = (*it->second.to)->nb_transport_fw(*trans, phase, t); 207 #endif /* ! NDEBUG */ 208 assert(r == tlm::TLM_COMPLETED); 209 } 210 211 mPendingTransactions.erase(it); 212 trans->release(); 213 } 214 } 215 } 216 217 // 218 // interface methods 219 // 220 221 sync_enum_type initiatorNBTransport(int initiator_id, 222 transaction_type& trans, 223 phase_type& phase, 224 sc_core::sc_time& t) 225 { 226 if (phase == tlm::BEGIN_REQ) { 227 trans.acquire(); 228 addPendingTransaction(trans, 0, initiator_id); 229 230 mRequestPEQ.notify(trans, t); 231 232 } else if (phase == tlm::END_RESP) { 233 mEndResponseEvent.notify(t); 234 return tlm::TLM_COMPLETED; 235 236 } else { 237 std::cout << "ERROR: '" << name() 238 << "': Illegal phase received from initiator." << std::endl; 239 assert(false); exit(1); 240 } 241 242 return tlm::TLM_ACCEPTED; 243 } 244 245 sync_enum_type targetNBTransport(int portId, 246 transaction_type& trans, 247 phase_type& phase, 248 sc_core::sc_time& t) 249 { 250 if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) { 251 std::cout << "ERROR: '" << name() 252 << "': Illegal phase received from target." << std::endl; 253 assert(false); exit(1); 254 } 255 256 mEndRequestEvent.notify(t); 257 if (phase == tlm::BEGIN_RESP) { 258 mResponsePEQ.notify(trans, t); 259 } 260 261 return tlm::TLM_ACCEPTED; 262 } 263 264 unsigned int transportDebug(int initiator_id, transaction_type& trans) 265 { 266 unsigned int portId = decode(trans.get_address()); 267 assert(portId < NR_OF_TARGETS); 268 initiator_socket_type* decodeSocket = &initiator_socket[portId]; 269 trans.set_address( trans.get_address() & getAddressMask(portId) ); 270 271 return (*decodeSocket)->transport_dbg(trans); 272 } 273 274 bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high) 275 { 276 sc_dt::uint64 addressOffset = getAddressOffset(portId); 277 sc_dt::uint64 addressMask = getAddressMask(portId); 278 279 if (low > addressMask) { 280 // Range does not overlap with addressrange for this target 281 return false; 282 } 283 284 low += addressOffset; 285 if (high > addressMask) { 286 high = addressOffset + addressMask; 287 288 } else { 289 high += addressOffset; 290 } 291 return true; 292 } 293 294 bool getDMIPointer(int initiator_id, 295 transaction_type& trans, 296 tlm::tlm_dmi& dmi_data) 297 { 298 // FIXME: DMI not supported for AT bus? 299 sc_dt::uint64 address = trans.get_address(); 300 301 unsigned int portId = decode(address); 302 assert(portId < NR_OF_TARGETS); 303 initiator_socket_type* decodeSocket = &initiator_socket[portId]; 304 sc_dt::uint64 maskedAddress = address & getAddressMask(portId); 305 306 trans.set_address(maskedAddress); 307 308 bool result = 309 (*decodeSocket)->get_direct_mem_ptr(trans, dmi_data); 310 311 if (result) 312 { 313 // Range must contain address 314 assert(dmi_data.get_start_address() <= maskedAddress); 315 assert(dmi_data.get_end_address() >= maskedAddress); 316 } 317 318 // Should always succeed 319 sc_dt::uint64 start, end; 320 start = dmi_data.get_start_address(); 321 end = dmi_data.get_end_address(); 322 323 limitRange(portId, start, end); 324 325 dmi_data.set_start_address(start); 326 dmi_data.set_end_address(end); 327 328 return result; 329 } 330 331 void invalidateDMIPointers(int portId, 332 sc_dt::uint64 start_range, 333 sc_dt::uint64 end_range) 334 { 335 // FIXME: probably faster to always invalidate everything? 336 337 if ((portId >= 0) && !limitRange(portId, start_range, end_range)) { 338 // Range does not fall into address range of target 339 return; 340 } 341 342 for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) { 343 (target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range); 344 } 345 } 346 347private: 348 void addPendingTransaction(transaction_type& trans, 349 initiator_socket_type* to, 350 int initiatorId) 351 { 352 const ConnectionInfo info = { &target_socket[initiatorId], to }; 353 assert(mPendingTransactions.find(&trans) == mPendingTransactions.end()); 354 mPendingTransactions[&trans] = info; 355 } 356 357private: 358 struct ConnectionInfo { 359 target_socket_type* from; 360 initiator_socket_type* to; 361 }; 362 typedef std::map<transaction_type*, ConnectionInfo> PendingTransactions; 363 typedef typename PendingTransactions::iterator PendingTransactionsIterator; 364 typedef typename PendingTransactions::const_iterator PendingTransactionsConstIterator; 365 366private: 367 PendingTransactions mPendingTransactions; 368 369 tlm_utils::peq_with_get<transaction_type> mRequestPEQ; 370 sc_core::sc_event mBeginRequestEvent; 371 sc_core::sc_event mEndRequestEvent; 372 373 tlm_utils::peq_with_get<transaction_type> mResponsePEQ; 374 sc_core::sc_event mBeginResponseEvent; 375 sc_core::sc_event mEndResponseEvent; 376}; 377 378#endif 379