SimpleBusAT.h revision 12922
112922Sgabeblack@google.com/***************************************************************************** 212922Sgabeblack@google.com 312922Sgabeblack@google.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 412922Sgabeblack@google.com more contributor license agreements. See the NOTICE file distributed 512922Sgabeblack@google.com with this work for additional information regarding copyright ownership. 612922Sgabeblack@google.com Accellera licenses this file to you under the Apache License, Version 2.0 712922Sgabeblack@google.com (the "License"); you may not use this file except in compliance with the 812922Sgabeblack@google.com License. You may obtain a copy of the License at 912922Sgabeblack@google.com 1012922Sgabeblack@google.com http://www.apache.org/licenses/LICENSE-2.0 1112922Sgabeblack@google.com 1212922Sgabeblack@google.com Unless required by applicable law or agreed to in writing, software 1312922Sgabeblack@google.com distributed under the License is distributed on an "AS IS" BASIS, 1412922Sgabeblack@google.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1512922Sgabeblack@google.com implied. See the License for the specific language governing 1612922Sgabeblack@google.com permissions and limitations under the License. 1712922Sgabeblack@google.com 1812922Sgabeblack@google.com *****************************************************************************/ 1912922Sgabeblack@google.com 2012922Sgabeblack@google.com#ifndef __SIMPLEBUSAT_H__ 2112922Sgabeblack@google.com#define __SIMPLEBUSAT_H__ 2212922Sgabeblack@google.com 2312922Sgabeblack@google.com//#include <systemc> 2412922Sgabeblack@google.com#include "tlm.h" 2512922Sgabeblack@google.com 2612922Sgabeblack@google.com#include "tlm_utils/simple_target_socket.h" 2712922Sgabeblack@google.com#include "tlm_utils/simple_initiator_socket.h" 2812922Sgabeblack@google.com 2912922Sgabeblack@google.com#include "tlm_utils/peq_with_get.h" 3012922Sgabeblack@google.com 3112922Sgabeblack@google.comtemplate <int NR_OF_INITIATORS, int NR_OF_TARGETS> 3212922Sgabeblack@google.comclass SimpleBusAT : public sc_core::sc_module 3312922Sgabeblack@google.com{ 3412922Sgabeblack@google.compublic: 3512922Sgabeblack@google.com typedef tlm::tlm_generic_payload transaction_type; 3612922Sgabeblack@google.com typedef tlm::tlm_phase phase_type; 3712922Sgabeblack@google.com typedef tlm::tlm_sync_enum sync_enum_type; 3812922Sgabeblack@google.com typedef tlm_utils::simple_target_socket_tagged<SimpleBusAT> target_socket_type; 3912922Sgabeblack@google.com typedef tlm_utils::simple_initiator_socket_tagged<SimpleBusAT> initiator_socket_type; 4012922Sgabeblack@google.com 4112922Sgabeblack@google.compublic: 4212922Sgabeblack@google.com target_socket_type target_socket[NR_OF_INITIATORS]; 4312922Sgabeblack@google.com initiator_socket_type initiator_socket[NR_OF_TARGETS]; 4412922Sgabeblack@google.com 4512922Sgabeblack@google.compublic: 4612922Sgabeblack@google.com SC_HAS_PROCESS(SimpleBusAT); 4712922Sgabeblack@google.com SimpleBusAT(sc_core::sc_module_name name) : 4812922Sgabeblack@google.com sc_core::sc_module(name), 4912922Sgabeblack@google.com mRequestPEQ("requestPEQ"), 5012922Sgabeblack@google.com mResponsePEQ("responsePEQ") 5112922Sgabeblack@google.com { 5212922Sgabeblack@google.com for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) { 5312922Sgabeblack@google.com target_socket[i].register_nb_transport_fw(this, &SimpleBusAT::initiatorNBTransport, i); 5412922Sgabeblack@google.com target_socket[i].register_transport_dbg(this, &SimpleBusAT::transportDebug, i); 5512922Sgabeblack@google.com target_socket[i].register_get_direct_mem_ptr(this, &SimpleBusAT::getDMIPointer, i); 5612922Sgabeblack@google.com } 5712922Sgabeblack@google.com for (unsigned int i = 0; i < NR_OF_TARGETS; ++i) { 5812922Sgabeblack@google.com initiator_socket[i].register_nb_transport_bw(this, &SimpleBusAT::targetNBTransport, i); 5912922Sgabeblack@google.com initiator_socket[i].register_invalidate_direct_mem_ptr(this, &SimpleBusAT::invalidateDMIPointers, i); 6012922Sgabeblack@google.com } 6112922Sgabeblack@google.com 6212922Sgabeblack@google.com SC_THREAD(RequestThread); 6312922Sgabeblack@google.com SC_THREAD(ResponseThread); 6412922Sgabeblack@google.com } 6512922Sgabeblack@google.com 6612922Sgabeblack@google.com // 6712922Sgabeblack@google.com // Dummy decoder: 6812922Sgabeblack@google.com // - address[31-28]: portId 6912922Sgabeblack@google.com // - address[27-0]: masked address 7012922Sgabeblack@google.com // 7112922Sgabeblack@google.com 7212922Sgabeblack@google.com unsigned int getPortId(const sc_dt::uint64& address) 7312922Sgabeblack@google.com { 7412922Sgabeblack@google.com return (unsigned int)address >> 28; 7512922Sgabeblack@google.com } 7612922Sgabeblack@google.com 7712922Sgabeblack@google.com sc_dt::uint64 getAddressOffset(unsigned int portId) 7812922Sgabeblack@google.com { 7912922Sgabeblack@google.com return portId << 28; 8012922Sgabeblack@google.com } 8112922Sgabeblack@google.com 8212922Sgabeblack@google.com sc_dt::uint64 getAddressMask(unsigned int portId) 8312922Sgabeblack@google.com { 8412922Sgabeblack@google.com return 0xfffffff; 8512922Sgabeblack@google.com } 8612922Sgabeblack@google.com 8712922Sgabeblack@google.com unsigned int decode(const sc_dt::uint64& address) 8812922Sgabeblack@google.com { 8912922Sgabeblack@google.com // decode address: 9012922Sgabeblack@google.com // - return initiator socket id 9112922Sgabeblack@google.com 9212922Sgabeblack@google.com return getPortId(address); 9312922Sgabeblack@google.com } 9412922Sgabeblack@google.com 9512922Sgabeblack@google.com // 9612922Sgabeblack@google.com // AT protocol 9712922Sgabeblack@google.com // 9812922Sgabeblack@google.com 9912922Sgabeblack@google.com void RequestThread() 10012922Sgabeblack@google.com { 10112922Sgabeblack@google.com while (true) { 10212922Sgabeblack@google.com wait(mRequestPEQ.get_event()); 10312922Sgabeblack@google.com 10412922Sgabeblack@google.com transaction_type* trans; 10512922Sgabeblack@google.com while ((trans = mRequestPEQ.get_next_transaction())!=0) { 10612922Sgabeblack@google.com unsigned int portId = decode(trans->get_address()); 10712922Sgabeblack@google.com assert(portId < NR_OF_TARGETS); 10812922Sgabeblack@google.com initiator_socket_type* decodeSocket = &initiator_socket[portId]; 10912922Sgabeblack@google.com trans->set_address(trans->get_address() & getAddressMask(portId)); 11012922Sgabeblack@google.com 11112922Sgabeblack@google.com // Fill in the destination port 11212922Sgabeblack@google.com PendingTransactionsIterator it = mPendingTransactions.find(trans); 11312922Sgabeblack@google.com assert(it != mPendingTransactions.end()); 11412922Sgabeblack@google.com it->second.to = decodeSocket; 11512922Sgabeblack@google.com 11612922Sgabeblack@google.com phase_type phase = tlm::BEGIN_REQ; 11712922Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 11812922Sgabeblack@google.com 11912922Sgabeblack@google.com // FIXME: No limitation on number of pending transactions 12012922Sgabeblack@google.com // All targets (that return false) must support multiple transactions 12112922Sgabeblack@google.com switch ((*decodeSocket)->nb_transport_fw(*trans, phase, t)) { 12212922Sgabeblack@google.com case tlm::TLM_ACCEPTED: 12312922Sgabeblack@google.com case tlm::TLM_UPDATED: 12412922Sgabeblack@google.com // Transaction not yet finished 12512922Sgabeblack@google.com if (phase == tlm::BEGIN_REQ) { 12612922Sgabeblack@google.com // Request phase not yet finished 12712922Sgabeblack@google.com wait(mEndRequestEvent); 12812922Sgabeblack@google.com 12912922Sgabeblack@google.com } else if (phase == tlm::END_REQ) { 13012922Sgabeblack@google.com // Request phase finished, but response phase not yet started 13112922Sgabeblack@google.com wait(t); 13212922Sgabeblack@google.com 13312922Sgabeblack@google.com } else if (phase == tlm::BEGIN_RESP) { 13412922Sgabeblack@google.com mResponsePEQ.notify(*trans, t); 13512922Sgabeblack@google.com // Not needed to send END_REQ to initiator 13612922Sgabeblack@google.com continue; 13712922Sgabeblack@google.com 13812922Sgabeblack@google.com } else { // END_RESP 13912922Sgabeblack@google.com assert(0); exit(1); 14012922Sgabeblack@google.com } 14112922Sgabeblack@google.com 14212922Sgabeblack@google.com // only send END_REQ to initiator if BEGIN_RESP was not already send 14312922Sgabeblack@google.com if (it->second.from) { 14412922Sgabeblack@google.com phase = tlm::END_REQ; 14512922Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 14612922Sgabeblack@google.com (*it->second.from)->nb_transport_bw(*trans, phase, t); 14712922Sgabeblack@google.com } 14812922Sgabeblack@google.com 14912922Sgabeblack@google.com break; 15012922Sgabeblack@google.com 15112922Sgabeblack@google.com case tlm::TLM_COMPLETED: 15212922Sgabeblack@google.com // Transaction finished 15312922Sgabeblack@google.com mResponsePEQ.notify(*trans, t); 15412922Sgabeblack@google.com 15512922Sgabeblack@google.com // reset to destination port (we must not send END_RESP to target) 15612922Sgabeblack@google.com it->second.to = 0; 15712922Sgabeblack@google.com 15812922Sgabeblack@google.com wait(t); 15912922Sgabeblack@google.com break; 16012922Sgabeblack@google.com 16112922Sgabeblack@google.com default: 16212922Sgabeblack@google.com assert(0); exit(1); 16312922Sgabeblack@google.com }; 16412922Sgabeblack@google.com } 16512922Sgabeblack@google.com } 16612922Sgabeblack@google.com } 16712922Sgabeblack@google.com 16812922Sgabeblack@google.com void ResponseThread() 16912922Sgabeblack@google.com { 17012922Sgabeblack@google.com while (true) { 17112922Sgabeblack@google.com wait(mResponsePEQ.get_event()); 17212922Sgabeblack@google.com 17312922Sgabeblack@google.com transaction_type* trans; 17412922Sgabeblack@google.com while ((trans = mResponsePEQ.get_next_transaction())!=0) { 17512922Sgabeblack@google.com PendingTransactionsIterator it = mPendingTransactions.find(trans); 17612922Sgabeblack@google.com assert(it != mPendingTransactions.end()); 17712922Sgabeblack@google.com 17812922Sgabeblack@google.com phase_type phase = tlm::BEGIN_RESP; 17912922Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 18012922Sgabeblack@google.com 18112922Sgabeblack@google.com target_socket_type* initiatorSocket = it->second.from; 18212922Sgabeblack@google.com // if BEGIN_RESP is send first we don't have to send END_REQ anymore 18312922Sgabeblack@google.com it->second.from = 0; 18412922Sgabeblack@google.com 18512922Sgabeblack@google.com switch ((*initiatorSocket)->nb_transport_bw(*trans, phase, t)) { 18612922Sgabeblack@google.com case tlm::TLM_COMPLETED: 18712922Sgabeblack@google.com // Transaction finished 18812922Sgabeblack@google.com wait(t); 18912922Sgabeblack@google.com break; 19012922Sgabeblack@google.com 19112922Sgabeblack@google.com case tlm::TLM_ACCEPTED: 19212922Sgabeblack@google.com case tlm::TLM_UPDATED: 19312922Sgabeblack@google.com // Transaction not yet finished 19412922Sgabeblack@google.com wait(mEndResponseEvent); 19512922Sgabeblack@google.com break; 19612922Sgabeblack@google.com 19712922Sgabeblack@google.com default: 19812922Sgabeblack@google.com assert(0); exit(1); 19912922Sgabeblack@google.com }; 20012922Sgabeblack@google.com 20112922Sgabeblack@google.com // forward END_RESP to target 20212922Sgabeblack@google.com if (it->second.to) { 20312922Sgabeblack@google.com phase = tlm::END_RESP; 20412922Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 20512922Sgabeblack@google.com #if ( ! NDEBUG ) 20612922Sgabeblack@google.com sync_enum_type r = (*it->second.to)->nb_transport_fw(*trans, phase, t); 20712922Sgabeblack@google.com #endif /* ! NDEBUG */ 20812922Sgabeblack@google.com assert(r == tlm::TLM_COMPLETED); 20912922Sgabeblack@google.com } 21012922Sgabeblack@google.com 21112922Sgabeblack@google.com mPendingTransactions.erase(it); 21212922Sgabeblack@google.com trans->release(); 21312922Sgabeblack@google.com } 21412922Sgabeblack@google.com } 21512922Sgabeblack@google.com } 21612922Sgabeblack@google.com 21712922Sgabeblack@google.com // 21812922Sgabeblack@google.com // interface methods 21912922Sgabeblack@google.com // 22012922Sgabeblack@google.com 22112922Sgabeblack@google.com sync_enum_type initiatorNBTransport(int initiator_id, 22212922Sgabeblack@google.com transaction_type& trans, 22312922Sgabeblack@google.com phase_type& phase, 22412922Sgabeblack@google.com sc_core::sc_time& t) 22512922Sgabeblack@google.com { 22612922Sgabeblack@google.com if (phase == tlm::BEGIN_REQ) { 22712922Sgabeblack@google.com trans.acquire(); 22812922Sgabeblack@google.com addPendingTransaction(trans, 0, initiator_id); 22912922Sgabeblack@google.com 23012922Sgabeblack@google.com mRequestPEQ.notify(trans, t); 23112922Sgabeblack@google.com 23212922Sgabeblack@google.com } else if (phase == tlm::END_RESP) { 23312922Sgabeblack@google.com mEndResponseEvent.notify(t); 23412922Sgabeblack@google.com return tlm::TLM_COMPLETED; 23512922Sgabeblack@google.com 23612922Sgabeblack@google.com } else { 23712922Sgabeblack@google.com std::cout << "ERROR: '" << name() 23812922Sgabeblack@google.com << "': Illegal phase received from initiator." << std::endl; 23912922Sgabeblack@google.com assert(false); exit(1); 24012922Sgabeblack@google.com } 24112922Sgabeblack@google.com 24212922Sgabeblack@google.com return tlm::TLM_ACCEPTED; 24312922Sgabeblack@google.com } 24412922Sgabeblack@google.com 24512922Sgabeblack@google.com sync_enum_type targetNBTransport(int portId, 24612922Sgabeblack@google.com transaction_type& trans, 24712922Sgabeblack@google.com phase_type& phase, 24812922Sgabeblack@google.com sc_core::sc_time& t) 24912922Sgabeblack@google.com { 25012922Sgabeblack@google.com if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) { 25112922Sgabeblack@google.com std::cout << "ERROR: '" << name() 25212922Sgabeblack@google.com << "': Illegal phase received from target." << std::endl; 25312922Sgabeblack@google.com assert(false); exit(1); 25412922Sgabeblack@google.com } 25512922Sgabeblack@google.com 25612922Sgabeblack@google.com mEndRequestEvent.notify(t); 25712922Sgabeblack@google.com if (phase == tlm::BEGIN_RESP) { 25812922Sgabeblack@google.com mResponsePEQ.notify(trans, t); 25912922Sgabeblack@google.com } 26012922Sgabeblack@google.com 26112922Sgabeblack@google.com return tlm::TLM_ACCEPTED; 26212922Sgabeblack@google.com } 26312922Sgabeblack@google.com 26412922Sgabeblack@google.com unsigned int transportDebug(int initiator_id, transaction_type& trans) 26512922Sgabeblack@google.com { 26612922Sgabeblack@google.com unsigned int portId = decode(trans.get_address()); 26712922Sgabeblack@google.com assert(portId < NR_OF_TARGETS); 26812922Sgabeblack@google.com initiator_socket_type* decodeSocket = &initiator_socket[portId]; 26912922Sgabeblack@google.com trans.set_address( trans.get_address() & getAddressMask(portId) ); 27012922Sgabeblack@google.com 27112922Sgabeblack@google.com return (*decodeSocket)->transport_dbg(trans); 27212922Sgabeblack@google.com } 27312922Sgabeblack@google.com 27412922Sgabeblack@google.com bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high) 27512922Sgabeblack@google.com { 27612922Sgabeblack@google.com sc_dt::uint64 addressOffset = getAddressOffset(portId); 27712922Sgabeblack@google.com sc_dt::uint64 addressMask = getAddressMask(portId); 27812922Sgabeblack@google.com 27912922Sgabeblack@google.com if (low > addressMask) { 28012922Sgabeblack@google.com // Range does not overlap with addressrange for this target 28112922Sgabeblack@google.com return false; 28212922Sgabeblack@google.com } 28312922Sgabeblack@google.com 28412922Sgabeblack@google.com low += addressOffset; 28512922Sgabeblack@google.com if (high > addressMask) { 28612922Sgabeblack@google.com high = addressOffset + addressMask; 28712922Sgabeblack@google.com 28812922Sgabeblack@google.com } else { 28912922Sgabeblack@google.com high += addressOffset; 29012922Sgabeblack@google.com } 29112922Sgabeblack@google.com return true; 29212922Sgabeblack@google.com } 29312922Sgabeblack@google.com 29412922Sgabeblack@google.com bool getDMIPointer(int initiator_id, 29512922Sgabeblack@google.com transaction_type& trans, 29612922Sgabeblack@google.com tlm::tlm_dmi& dmi_data) 29712922Sgabeblack@google.com { 29812922Sgabeblack@google.com // FIXME: DMI not supported for AT bus? 29912922Sgabeblack@google.com sc_dt::uint64 address = trans.get_address(); 30012922Sgabeblack@google.com 30112922Sgabeblack@google.com unsigned int portId = decode(address); 30212922Sgabeblack@google.com assert(portId < NR_OF_TARGETS); 30312922Sgabeblack@google.com initiator_socket_type* decodeSocket = &initiator_socket[portId]; 30412922Sgabeblack@google.com sc_dt::uint64 maskedAddress = address & getAddressMask(portId); 30512922Sgabeblack@google.com 30612922Sgabeblack@google.com trans.set_address(maskedAddress); 30712922Sgabeblack@google.com 30812922Sgabeblack@google.com bool result = 30912922Sgabeblack@google.com (*decodeSocket)->get_direct_mem_ptr(trans, dmi_data); 31012922Sgabeblack@google.com 31112922Sgabeblack@google.com if (result) 31212922Sgabeblack@google.com { 31312922Sgabeblack@google.com // Range must contain address 31412922Sgabeblack@google.com assert(dmi_data.get_start_address() <= maskedAddress); 31512922Sgabeblack@google.com assert(dmi_data.get_end_address() >= maskedAddress); 31612922Sgabeblack@google.com } 31712922Sgabeblack@google.com 31812922Sgabeblack@google.com // Should always succeed 31912922Sgabeblack@google.com sc_dt::uint64 start, end; 32012922Sgabeblack@google.com start = dmi_data.get_start_address(); 32112922Sgabeblack@google.com end = dmi_data.get_end_address(); 32212922Sgabeblack@google.com 32312922Sgabeblack@google.com limitRange(portId, start, end); 32412922Sgabeblack@google.com 32512922Sgabeblack@google.com dmi_data.set_start_address(start); 32612922Sgabeblack@google.com dmi_data.set_end_address(end); 32712922Sgabeblack@google.com 32812922Sgabeblack@google.com return result; 32912922Sgabeblack@google.com } 33012922Sgabeblack@google.com 33112922Sgabeblack@google.com void invalidateDMIPointers(int portId, 33212922Sgabeblack@google.com sc_dt::uint64 start_range, 33312922Sgabeblack@google.com sc_dt::uint64 end_range) 33412922Sgabeblack@google.com { 33512922Sgabeblack@google.com // FIXME: probably faster to always invalidate everything? 33612922Sgabeblack@google.com 33712922Sgabeblack@google.com if ((portId >= 0) && !limitRange(portId, start_range, end_range)) { 33812922Sgabeblack@google.com // Range does not fall into address range of target 33912922Sgabeblack@google.com return; 34012922Sgabeblack@google.com } 34112922Sgabeblack@google.com 34212922Sgabeblack@google.com for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) { 34312922Sgabeblack@google.com (target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range); 34412922Sgabeblack@google.com } 34512922Sgabeblack@google.com } 34612922Sgabeblack@google.com 34712922Sgabeblack@google.comprivate: 34812922Sgabeblack@google.com void addPendingTransaction(transaction_type& trans, 34912922Sgabeblack@google.com initiator_socket_type* to, 35012922Sgabeblack@google.com int initiatorId) 35112922Sgabeblack@google.com { 35212922Sgabeblack@google.com const ConnectionInfo info = { &target_socket[initiatorId], to }; 35312922Sgabeblack@google.com assert(mPendingTransactions.find(&trans) == mPendingTransactions.end()); 35412922Sgabeblack@google.com mPendingTransactions[&trans] = info; 35512922Sgabeblack@google.com } 35612922Sgabeblack@google.com 35712922Sgabeblack@google.comprivate: 35812922Sgabeblack@google.com struct ConnectionInfo { 35912922Sgabeblack@google.com target_socket_type* from; 36012922Sgabeblack@google.com initiator_socket_type* to; 36112922Sgabeblack@google.com }; 36212922Sgabeblack@google.com typedef std::map<transaction_type*, ConnectionInfo> PendingTransactions; 36312922Sgabeblack@google.com typedef typename PendingTransactions::iterator PendingTransactionsIterator; 36412922Sgabeblack@google.com typedef typename PendingTransactions::const_iterator PendingTransactionsConstIterator; 36512922Sgabeblack@google.com 36612922Sgabeblack@google.comprivate: 36712922Sgabeblack@google.com PendingTransactions mPendingTransactions; 36812922Sgabeblack@google.com 36912922Sgabeblack@google.com tlm_utils::peq_with_get<transaction_type> mRequestPEQ; 37012922Sgabeblack@google.com sc_core::sc_event mBeginRequestEvent; 37112922Sgabeblack@google.com sc_core::sc_event mEndRequestEvent; 37212922Sgabeblack@google.com 37312922Sgabeblack@google.com tlm_utils::peq_with_get<transaction_type> mResponsePEQ; 37412922Sgabeblack@google.com sc_core::sc_event mBeginResponseEvent; 37512922Sgabeblack@google.com sc_core::sc_event mEndResponseEvent; 37612922Sgabeblack@google.com}; 37712922Sgabeblack@google.com 37812922Sgabeblack@google.com#endif 379