diff options
author | Gabe Black <gabeblack@google.com> | 2018-05-24 01:37:55 -0700 |
---|---|---|
committer | Gabe Black <gabeblack@google.com> | 2018-08-08 10:09:54 +0000 |
commit | 16fa8d7cc8c92f5ab879e4cf9c6c0bbb3567860f (patch) | |
tree | 7b6faaacb4574a555e561534aa4a8508c0624c32 /src/systemc/tests/tlm/multi_sockets | |
parent | 7235d3b5211d0ba8f528d930a4c1e7ad62eec51a (diff) | |
download | gem5-16fa8d7cc8c92f5ab879e4cf9c6c0bbb3567860f.tar.xz |
systemc: Import tests from the Accellera systemc distribution.
Change-Id: Iad76b398949a55d768a34d027a2d8e3739953da6
Reviewed-on: https://gem5-review.googlesource.com/10845
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>
Diffstat (limited to 'src/systemc/tests/tlm/multi_sockets')
5 files changed, 818 insertions, 0 deletions
diff --git a/src/systemc/tests/tlm/multi_sockets/MultiSocketSimpleSwitchAT.h b/src/systemc/tests/tlm/multi_sockets/MultiSocketSimpleSwitchAT.h new file mode 100644 index 000000000..3e03db312 --- /dev/null +++ b/src/systemc/tests/tlm/multi_sockets/MultiSocketSimpleSwitchAT.h @@ -0,0 +1,340 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +#ifndef __SIMPLESWITCHAT_H__ +#define __SIMPLESWITCHAT_H__ + +#include "tlm.h" + +#include "tlm_utils/multi_passthrough_initiator_socket.h" +#include "tlm_utils/multi_passthrough_target_socket.h" +#include "simpleAddressMap.h" +#include "extensionPool.h" +#include "tlm_utils/instance_specific_extensions.h" +#include "tlm_utils/peq_with_cb_and_phase.h" + + +/* +This class is a simple crossbar switch through which an arbitrary number of initiators +may communicate in parallel as long as they do not talk to the same target. + +If two masters address the same target at the same point of time, +the choice who will be allowed to communicate +is done non-deterministically (based on the SystemC process exectution order). + +This could be avoided by changing the fwPEQ into a priority PEQ of some kind. + +The switch ensures that the end_req and end_resp rules are not violated when +many initiator talk to the same target. +*/ +class MultiSocketSimpleSwitchAT : public sc_core::sc_module, public tlm::tlm_mm_interface +{ +public: + typedef tlm::tlm_generic_payload transaction_type; + typedef tlm::tlm_phase phase_type; + typedef tlm::tlm_sync_enum sync_enum_type; + typedef tlm_utils::multi_passthrough_target_socket<MultiSocketSimpleSwitchAT> target_socket_type; + typedef tlm_utils::multi_passthrough_initiator_socket<MultiSocketSimpleSwitchAT> initiator_socket_type; + +public: + target_socket_type target_socket; //the target multi socket + +private: + initiator_socket_type initiator_socket; //the initiator multi socket (private to enforce use of bindTarget function) + SimpleAddressMap m_addrMap; //a pretty simple address map + std::vector<std::deque<transaction_type*> > m_pendingReqs; //list of pending reqs per target + std::vector<std::deque<transaction_type*> > m_pendingResps; //list of pending resps per initiator + std::vector<sc_dt::uint64> m_masks; //address masks for each target + tlm_utils::instance_specific_extension_accessor accessMySpecificExtensions; //extension accessor to access private extensions + tlm_utils::peq_with_cb_and_phase<MultiSocketSimpleSwitchAT> m_bwPEQ; //PEQ in the fw direction + tlm_utils::peq_with_cb_and_phase<MultiSocketSimpleSwitchAT> m_fwPEQ; //PEQ in the bw direction + + + //an instance specific extension that tells us whether we are in a wrapped b_transport or not + class BTag : public tlm_utils::instance_specific_extension<BTag>{ + public: + sc_core::sc_event event; //trigger this event when transaction is done + }; + + //an instance specific extension that holds information about source and sink of a txn + // as well as information if the req still has to be cleared and if the txn is already + // complete on the target side + class ConnectionInfo : public tlm_utils::instance_specific_extension<ConnectionInfo>{ + public: + unsigned int fwID; //socket number of sink + unsigned int bwID; //socket number of source + bool clearReq; //is the txn still in req phase? + bool alreadyComplete; //has the txn already completed on the target side? + }; + + class internalPEQTypes{ //use the tpPEQ to delay connection infos + public: + typedef ConnectionInfo tlm_payload_type; + typedef tlm::tlm_phase tlm_phase_type; + }; + ExtensionPool<ConnectionInfo> m_connInfoPool; //our pool of extensions + unsigned int m_target_count; //number of connected targets (see bindTargetSocket for explanation) + +public: + SC_HAS_PROCESS(MultiSocketSimpleSwitchAT); + MultiSocketSimpleSwitchAT(sc_core::sc_module_name name) : + sc_core::sc_module(name), + target_socket("target_socket"), + initiator_socket("initiator_socket"), + m_bwPEQ(this, &MultiSocketSimpleSwitchAT::bwPEQcb), + m_fwPEQ(this, &MultiSocketSimpleSwitchAT::fwPEQcb), + m_connInfoPool(10), + m_target_count(0) + { + target_socket.register_nb_transport_fw(this, &MultiSocketSimpleSwitchAT::initiatorNBTransport); + target_socket.register_b_transport(this, &MultiSocketSimpleSwitchAT::b_transport); + initiator_socket.register_nb_transport_bw(this, &MultiSocketSimpleSwitchAT::targetNBTransport); + } + + void bindTargetSocket(initiator_socket_type::base_target_socket_type& target + ,sc_dt::uint64 low + ,sc_dt::uint64 high + ,sc_dt::uint64 mask = 0xffffffffffffffffULL){ + initiator_socket(target); //bind sockets + //insert into address map and increase target count + // (we have to count the targets manually, because target_socket.size() is only reliable during simulation + // as it gets evaluated during end_of_elaboration) + m_addrMap.insert(low, high, m_target_count++); + m_masks.push_back(mask); //add the mask for this target + } + + unsigned int decode(const sc_dt::uint64& address) + { + return m_addrMap.decode(address); + } + + void start_of_simulation(){ + //initialize the lists of pending reqs and resps + m_pendingReqs.resize(initiator_socket.size()); + m_pendingResps.resize(target_socket.size()); + } + + + void b_transport(int initiator_id, transaction_type& trans, sc_core::sc_time& t){ + //first make sure that there is no BTag (just for debugging) + BTag* btag; + accessMySpecificExtensions(trans).get_extension(btag); + sc_assert(!btag); + BTag tag; //now add our BTag + bool added_mm=!trans.has_mm(); //in case there is no MM in we add it now + if (added_mm){ + trans.set_mm(this); + trans.acquire(); //acquire the txn + } + accessMySpecificExtensions(trans).set_extension(&tag); + phase_type phase=tlm::BEGIN_REQ; //then simply use our nb implementation (respects all the rules) + initiatorNBTransport(initiator_id, trans, phase, t); + wait(tag.event); //and wait for the event to be triggered + if (added_mm){ //if we added MM + trans.release(); //we release our reference (this will not delete the txn but trigger the tag.event as soon as the ref count is zero) + if (trans.get_ref_count()) + wait(tag.event); //wait for the ref count to get to zero + trans.set_mm(NULL); //remove the MM + } + //don't forget to remove the extension (instance specific extensions are not cleared off by MM) + accessMySpecificExtensions(trans).clear_extension(&tag); + } + + void free(transaction_type* txn){ + BTag* btag; + accessMySpecificExtensions(*txn).get_extension(btag); + sc_assert(btag); + txn->reset(); //clean off all extension that were added down stream + btag->event.notify(); + } + + //do a fw transmission + void initiatorNBTransport_core(transaction_type& trans, + phase_type& phase, + sc_core::sc_time& t, + unsigned int tgtSocketNumber){ + switch (initiator_socket[tgtSocketNumber]->nb_transport_fw(trans, phase, t)) { + case tlm::TLM_ACCEPTED: + case tlm::TLM_UPDATED: + // Transaction not yet finished + if (phase != tlm::BEGIN_REQ) + { + sc_assert(phase!=tlm::END_RESP); + m_bwPEQ.notify(trans,phase,t); + } + break; + case tlm::TLM_COMPLETED: + // Transaction finished + ConnectionInfo* connInfo; + accessMySpecificExtensions(trans).get_extension(connInfo); + sc_assert(connInfo); + connInfo->alreadyComplete=true; + phase=tlm::BEGIN_RESP; + m_bwPEQ.notify(trans, phase, t); + break; + default: + sc_assert(0); exit(1); + }; + } + + //nb_transport_fw + sync_enum_type initiatorNBTransport(int initiator_id, + transaction_type& trans, + phase_type& phase, + sc_core::sc_time& t) + { + ConnectionInfo* connInfo; + accessMySpecificExtensions(trans).get_extension(connInfo); + m_fwPEQ.notify(trans,phase,t); + if (phase==tlm::BEGIN_REQ){ + //add our private information to the txn + sc_assert(!connInfo); + connInfo=m_connInfoPool.construct(); + connInfo->fwID=decode(trans.get_address()); + connInfo->bwID=initiator_id; + connInfo->clearReq=true; + connInfo->alreadyComplete=false; + accessMySpecificExtensions(trans).set_extension(connInfo); + } + else + if (phase==tlm::END_RESP){ + return tlm::TLM_COMPLETED; + } + else + {sc_assert(0); exit(1);} + return tlm::TLM_ACCEPTED; + } + + sync_enum_type targetNBTransport(int portId, + transaction_type& trans, + phase_type& phase, + sc_core::sc_time& t) + { + if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) { + std::cout << "ERROR: '" << name() + << "': Illegal phase received from target." << std::endl; + sc_assert(false); exit(1); + } + //simply stuff it into the bw PEQ + m_bwPEQ.notify(trans,phase,t); + return tlm::TLM_ACCEPTED; + } + + void bwPEQcb(transaction_type& trans, const phase_type& phase){ + //first get our private info from the txn + ConnectionInfo* connInfo; + accessMySpecificExtensions(trans).get_extension(connInfo); + sc_assert(connInfo); + phase_type p=phase; + sc_core::sc_time t=sc_core::SC_ZERO_TIME; + BTag* btag; + accessMySpecificExtensions(trans).get_extension(btag); + bool doCall=btag==NULL; //we only will do a bw call if we are not in a wrapped b_transport + if ((phase==tlm::END_REQ) | (connInfo->clearReq)){ //in case the target left out end_req clearReq reminds us to unlock the req port + sc_assert(m_pendingReqs[connInfo->fwID].size()); + sc_assert(m_pendingReqs[connInfo->fwID].front()==&trans); + m_pendingReqs[connInfo->fwID].pop_front(); //allow another req to start at this target + if (m_pendingReqs[connInfo->fwID].size()){ //there was a pending req + phase_type ph=tlm::BEGIN_REQ; + initiatorNBTransport_core(*m_pendingReqs[connInfo->fwID].front(), ph, t,connInfo->fwID); + } + connInfo->clearReq=false; + } + //no else here, since we might clear the req AND begin a resp + if (phase==tlm::BEGIN_RESP){ + m_pendingResps[connInfo->bwID].push_back(&trans); + doCall=m_pendingResps[connInfo->bwID].size()==1; //do a call in case the response socket was free + } + + if (doCall){ //we have to do a call on the bw of fw path + if (btag){ //only possible if BEGIN_RESP and resp socket was free + phase_type ph=tlm::END_RESP; + m_fwPEQ.notify(trans, ph, t); + } + else + switch (target_socket[connInfo->bwID]->nb_transport_bw(trans, p, t)){ + case tlm::TLM_ACCEPTED: + case tlm::TLM_UPDATED: + break; + case tlm::TLM_COMPLETED:{ + //covers a piggy bagged END_RESP to START_RESP + phase_type ph=tlm::END_RESP; + m_fwPEQ.notify(trans, ph, t); + } + break; + default: + sc_assert(0); exit(1); + + }; + } + } + + //the following two functions (fwPEQcb and clearPEQcb) could be one, if we were allowed + // to stick END_RESP into a PEQ + void fwPEQcb(transaction_type& trans, const phase_type& phase){ + ConnectionInfo* connInfo; + accessMySpecificExtensions(trans).get_extension(connInfo); + sc_assert(connInfo); + phase_type ph=phase; + sc_core::sc_time t=sc_core::SC_ZERO_TIME; + if (phase==tlm::BEGIN_REQ){ + trans.set_address(trans.get_address()&m_masks[connInfo->fwID]); //mask address + m_pendingReqs[connInfo->fwID].push_back(&trans); + if (m_pendingReqs[connInfo->fwID].size()==1){ //the socket is free + initiatorNBTransport_core(trans, ph, t, connInfo->fwID); + } + } + else + { + //phase is always END_RESP + BTag* btag; + accessMySpecificExtensions(trans).get_extension(btag); + accessMySpecificExtensions(trans).clear_extension(connInfo); //remove our specific extension as it is not needed any more + if (!connInfo->alreadyComplete) { + sync_enum_type tmp=initiator_socket[connInfo->fwID]->nb_transport_fw(trans, ph, t); + sc_assert(tmp==tlm::TLM_COMPLETED); + } + sc_assert(m_pendingResps[connInfo->bwID].size()); + m_pendingResps[connInfo->bwID].pop_front(); //remove current response + if (m_pendingResps[connInfo->bwID].size()){ //if there was one pending + ph=tlm::BEGIN_RESP; //schedule its transmission + m_bwPEQ.notify(*m_pendingResps[connInfo->bwID].front(),ph,t); + } + m_connInfoPool.free(connInfo); //release connInfo + if (btag) btag->event.notify(t); //release b_transport + } + } + + void dump_status(){ + std::cout<<"At "<<sc_core::sc_time_stamp()<<" status of "<<name()<<" is "<<std::endl + <<" Number of connected initiators: "<<target_socket.size()<<std::endl + <<" Number of connected targets: "<<initiator_socket.size()<<std::endl + <<" Pending requests:"<<std::endl; + for (unsigned int i=0; i<m_pendingReqs.size(); i++) + std::cout<<" "<<m_pendingReqs[i].size()<<" pending requests for target number "<<i<<std::endl; + std::cout<<" Pending responses:"<<std::endl; + for (unsigned int i=0; i<m_pendingResps.size(); i++) + std::cout<<" "<<m_pendingResps[i].size()<<" pending responses for initiator number "<<i<<std::endl; + std::cout<<" The address map is:"<<std::endl; + m_addrMap.dumpMap(); + + } +}; + +#endif diff --git a/src/systemc/tests/tlm/multi_sockets/extensionPool.h b/src/systemc/tests/tlm/multi_sockets/extensionPool.h new file mode 100644 index 000000000..2f8955fa7 --- /dev/null +++ b/src/systemc/tests/tlm/multi_sockets/extensionPool.h @@ -0,0 +1,106 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +#ifndef __EXTENSION_POOL_H__ +#define __EXTENSION_POOL_H__ + +template <class T> +class ExtensionPool{ + struct entry{ + public: + entry(T* content){ + that=content; + next=NULL; + } + T* that; + entry* next; + }; + +public: + ExtensionPool(int size): used(NULL){ + unused=new entry(new T()); //create first one + mine.push_back(unused->that); + for (int i=0; i<size-1; i++){ + entry* e=new entry(new T()); + e->next=unused; + unused=e; + mine.push_back(unused->that); + } + } + + ~ExtensionPool(){ + //delete all T* that belong to this pool + for (unsigned int i=0; i<mine.size(); i++){ + delete mine[i]; + } + + //delete all unused elements + while (unused){ + entry* e=unused; + unused=unused->next; + delete e; + } + + //delete all used elements + while (used){ + entry* e=used; + used=used->next; + delete e; + } + } + + bool is_from(T* cont){ //slow!!! + for (int i=0; i<mine.size(); i++){ + if (mine[i]==cont) return true; + } + return false; + } + + T* construct(){ + entry* e; + if (unused==NULL){ + e=new entry(new T()); + mine.push_back(e->that); + } + else{ + e=unused; + unused=unused->next; + } + e->next=used; + used=e; + return used->that; //if all elements of pool are used, just create a new one and go on + } + + void free (T* cont){ + sc_assert(used); + entry* e=used; + used=e->next; + e->that=cont; + e->next=unused; + unused=e; + } + +private: + entry* unused; + entry* used; + std::vector<T*> mine; //just for clean up and is_from +}; + +#endif + diff --git a/src/systemc/tests/tlm/multi_sockets/golden/multi_sockets.log b/src/systemc/tests/tlm/multi_sockets/golden/multi_sockets.log new file mode 100644 index 000000000..6ca308579 --- /dev/null +++ b/src/systemc/tests/tlm/multi_sockets/golden/multi_sockets.log @@ -0,0 +1,151 @@ +SystemC Simulation +AT_I1: Send write request: A = 0x10000000, D = 0x0 @ 0 s +LT_I1: Send write request: A = 0x20000000, D = 0x0 @ 0 s +LT_I2: Send write request: A = 0x30000000, D = 0x0 @ 0 s +LT_I3: Send write request: A = 0x60000000, D = 0x0 @ 0 s +AT_I2: Send write request: A = 0x50000000, D = 0x0 @ 0 s +LT_I4: Send write request: A = 0x40000000, D = 0x0 @ 0 s (0 s + 0 s) +AT_T2: Received write request: A = 0x0, D = 0x0 @ 0 s +AT_T1: Received write request: A = 0x0, D = 0x0 @ 0 s +LT_T1: Received write request: A = 0x0, D = 0x0 @ 0 s +LT_T2: Received write request: A = 0x0, D = 0x0 @ 0 s +LT_T3: Received write request: A = 0x0, D = 0x0 @ 0 s +AT_T3: Received write request: A = 0x0, D = 0x0 @ 10 ns +LT_I1: Received ok response @ 10 ns +LT_I1: Send write request: A = 0x20000004, D = 0x1 @ 10 ns +LT_T1: Received write request: A = 0x4, D = 0x1 @ 10 ns +LT_I2: Received ok response @ 10 ns +LT_I2: Send write request: A = 0x30000004, D = 0x1 @ 10 ns +LT_T2: Received write request: A = 0x4, D = 0x1 @ 10 ns +LT_I1: Received ok response @ 20 ns +LT_I1: Send write request: A = 0x20000008, D = 0x2 @ 20 ns +LT_T1: Received write request: A = 0x8, D = 0x2 @ 20 ns +LT_I2: Received ok response @ 20 ns +LT_I2: Send write request: A = 0x30000008, D = 0x2 @ 20 ns +LT_T2: Received write request: A = 0x8, D = 0x2 @ 20 ns +AT_I2: Send write request: A = 0x50000004, D = 0x1 @ 25 ns +AT_T2: Received write request: A = 0x4, D = 0x1 @ 25 ns +AT_I1: Send write request: A = 0x10000004, D = 0x1 @ 25 ns +AT_T1: Received write request: A = 0x4, D = 0x1 @ 25 ns +LT_I1: Received ok response @ 30 ns +LT_I1: Send read request: A = 0x20000000 @ 30 ns +LT_T1: Received read request: A = 0x0 @ 30 ns +LT_I2: Received ok response @ 30 ns +LT_I2: Send read request: A = 0x30000000 @ 30 ns +LT_T2: Received read request: A = 0x0 @ 30 ns +AT_I2: Send write request: A = 0x50000008, D = 0x2 @ 50 ns +AT_T2: Received write request: A = 0x8, D = 0x2 @ 50 ns +AT_I1: Send write request: A = 0x10000008, D = 0x2 @ 50 ns +AT_T1: Received write request: A = 0x8, D = 0x2 @ 50 ns +LT_I4: Received ok response @ 50 ns (50 ns + 0 s) +LT_I4: Send write request: A = 0x40000004, D = 0x1 @ 50 ns (50 ns + 0 s) +LT_T3: Received write request: A = 0x4, D = 0x1 @ 50 ns +LT_I3: Received ok response @ 60 ns +LT_I3: Send write request: A = 0x60000004, D = 0x1 @ 60 ns +AT_I2: Send read request: A = 0x50000000 @ 75 ns +AT_T2: Received read request: A = 0x0 @ 75 ns +AT_I1: Send read request: A = 0x10000000 @ 75 ns +AT_T1: Received read request: A = 0x0 @ 75 ns +AT_I2: Send read request: A = 0x50000004 @ 100 ns +AT_T2: Received read request: A = 0x4 @ 100 ns +AT_I1: Send read request: A = 0x10000004 @ 100 ns +AT_T1: Received read request: A = 0x4 @ 100 ns +LT_I4: Received ok response @ 100 ns (100 ns + 0 s) +LT_I4: Send write request: A = 0x40000008, D = 0x2 @ 100 ns (100 ns + 0 s) +LT_T3: Received write request: A = 0x8, D = 0x2 @ 100 ns +AT_I2: Received ok response @ 125 ns +AT_I2: Send read request: A = 0x50000008 @ 125 ns +AT_T2: Received read request: A = 0x8 @ 125 ns +AT_I1: Send read request: A = 0x10000008 @ 125 ns +AT_T1: Received read request: A = 0x8 @ 125 ns +AT_T3: Received write request: A = 0x4, D = 0x1 @ 130 ns +LT_I1: Received ok response: D = 0x0 @ 130 ns +LT_I1: Send read request: A = 0x20000004 @ 130 ns +LT_T1: Received read request: A = 0x4 @ 130 ns +LT_I2: Received ok response: D = 0x0 @ 130 ns +LT_I2: Send read request: A = 0x30000004 @ 130 ns +LT_T2: Received read request: A = 0x4 @ 130 ns +AT_I1: Received ok response @ 135 ns +LT_I4: Received ok response @ 150 ns (150 ns + 0 s) +LT_I4: Send read request: A = 0x40000000 @ 150 ns (150 ns + 0 s) +LT_T3: Received read request: A = 0x0 @ 150 ns +LT_I3: Received ok response @ 180 ns +LT_I3: Send write request: A = 0x60000008, D = 0x2 @ 180 ns +AT_T3: Received write request: A = 0x8, D = 0x2 @ 230 ns +LT_I1: Received ok response: D = 0x1 @ 230 ns +LT_I1: Send read request: A = 0x20000008 @ 230 ns +LT_T1: Received read request: A = 0x8 @ 230 ns +LT_I2: Received ok response: D = 0x1 @ 230 ns +LT_I2: Send read request: A = 0x30000008 @ 230 ns +LT_T2: Received read request: A = 0x8 @ 230 ns +AT_I2: Received ok response @ 235 ns +AT_I1: Received ok response @ 245 ns +LT_I4: Received ok response: D = 0x0 @ 250 ns (250 ns + 0 s) +LT_I4: Send read request: A = 0x40000004 @ 250 ns (250 ns + 0 s) +LT_T3: Received read request: A = 0x4 @ 250 ns +LT_I3: Received ok response @ 280 ns +LT_I3: Send read request: A = 0x60000000 @ 280 ns +AT_T3: Received read request: A = 0x0 @ 330 ns +LT_I1: Received ok response: D = 0x2 @ 330 ns +LT_I2: Received ok response: D = 0x2 @ 330 ns +AT_I2: Received ok response @ 345 ns +LT_I4: Received ok response: D = 0x1 @ 350 ns (350 ns + 0 s) +LT_I4: Send read request: A = 0x40000008 @ 350 ns (350 ns + 0 s) +LT_T3: Received read request: A = 0x8 @ 350 ns +AT_I1: Received ok response @ 355 ns +LT_I3: Received ok response: D = 0x0 @ 430 ns +LT_I3: Send read request: A = 0x60000004 @ 430 ns +AT_T3: Received read request: A = 0x4 @ 430 ns +LT_I4: Received ok response: D = 0x2 @ 450 ns (450 ns + 0 s) +AT_I2: Received ok response: D = 0x0 @ 455 ns +AT_I1: Received ok response: D = 0x0 @ 465 ns +LT_I3: Received ok response: D = 0x1 @ 530 ns +LT_I3: Send read request: A = 0x60000008 @ 530 ns +AT_T3: Received read request: A = 0x8 @ 530 ns +AT_I2: Received ok response: D = 0x1 @ 565 ns +AT_I1: Received ok response: D = 0x1 @ 575 ns +LT_I3: Received ok response: D = 0x2 @ 630 ns +AT_I2: Received ok response: D = 0x2 @ 675 ns +AT_I1: Received ok response: D = 0x2 @ 685 ns +At 685 ns status of bus1 is + Number of connected initiators: 4 + Number of connected targets: 3 + Pending requests: + 0 pending requests for target number 0 + 0 pending requests for target number 1 + 0 pending requests for target number 2 + Pending responses: + 0 pending responses for initiator number 0 + 0 pending responses for initiator number 1 + 0 pending responses for initiator number 2 + 0 pending responses for initiator number 3 + The address map is: +SimpleAddressMap: printing the sorted MAP: +key: 10000000 value: 255 +key: 1000ffff value: 0 +key: 20000000 value: 255 +key: 2000ffff value: 1 +key: 30000000 value: 255 +key: 6000ffff value: 2 +At 685 ns status of bus2 is + Number of connected initiators: 3 + Number of connected targets: 4 + Pending requests: + 0 pending requests for target number 0 + 0 pending requests for target number 1 + 0 pending requests for target number 2 + 0 pending requests for target number 3 + Pending responses: + 0 pending responses for initiator number 0 + 0 pending responses for initiator number 1 + 0 pending responses for initiator number 2 + The address map is: +SimpleAddressMap: printing the sorted MAP: +key: 30000000 value: 255 +key: 3000ffff value: 1 +key: 40000000 value: 255 +key: 4000ffff value: 3 +key: 50000000 value: 255 +key: 5000ffff value: 0 +key: 60000000 value: 255 +key: 6000ffff value: 2 diff --git a/src/systemc/tests/tlm/multi_sockets/multi_sockets.cpp b/src/systemc/tests/tlm/multi_sockets/multi_sockets.cpp new file mode 100644 index 000000000..fd60e8ba4 --- /dev/null +++ b/src/systemc/tests/tlm/multi_sockets/multi_sockets.cpp @@ -0,0 +1,73 @@ +#define SC_INCLUDE_DYNAMIC_PROCESSES +#include "CoreDecouplingLTInitiator.h" +#include "SimpleATInitiator1.h" +#include "SimpleATInitiator2.h" +#include "SimpleLTInitiator1.h" +#include "SimpleLTInitiator2.h" +#include "SimpleLTInitiator3.h" +#include "SimpleATTarget1.h" +#include "SimpleATTarget2.h" +#include "SimpleLTTarget1.h" +#include "SimpleLTTarget2.h" +#include "ExplicitATTarget.h" +#include "ExplicitLTTarget.h" + +#include "MultiSocketSimpleSwitchAT.h" + +/* +Connection Map: Busses are written vertically + +AT_I1-B-AT_T1 +LT_I1-U-LT_T1 +LT_I2-S +LT_I3-1-B-LT_T2 + U-LT_T3 + AT_I2-S-AT_T2 + LT_I4-2-AT_T3 +*/ +int sc_main(int argc, char* argv[]){ + + MultiSocketSimpleSwitchAT bus1("bus1"); + MultiSocketSimpleSwitchAT bus2("bus2"); + + SimpleATInitiator1 at_i1("AT_I1", 3, 0x10000000); //AT_T1 + SimpleLTInitiator1 lt_i1("LT_I1", 3, 0x20000000); //LT_T1 + SimpleLTInitiator2 lt_i2("LT_I2", 3, 0x30000000); //LT_T2 + SimpleLTInitiator3 lt_i3("LT_I3", 3, 0x60000000); //AT_T3 + + + SimpleATInitiator2 at_i2("AT_I2", 3, 0x50000000); //AT_T2 + CoreDecouplingLTInitiator lt_i4("LT_I4", 3, 0x40000000); //LT_T3 + + SimpleATTarget1 at_t1("AT_T1"); + SimpleATTarget2 at_t2("AT_T2"); + ExplicitATTarget at_t3("AT_T3"); + SimpleLTTarget1 lt_t1("LT_T1"); + SimpleLTTarget2 lt_t2("LT_T2"); + ExplicitLTTarget lt_t3("LT_T3"); + + + at_i1.socket(bus1.target_socket); + lt_i1.socket(bus1.target_socket); + lt_i2.socket(bus1.target_socket); + lt_i3.socket(bus1.target_socket); + + at_i2.socket(bus2.target_socket); + lt_i4.socket(bus2.target_socket); + + bus1.bindTargetSocket(at_t1.socket, 0x10000000,0x1000ffff, 0xfffffff); + bus1.bindTargetSocket(lt_t1.socket, 0x20000000,0x2000ffff, 0xfffffff); + bus1.bindTargetSocket(bus2.target_socket, 0x30000000,0x6000ffff); + + bus2.bindTargetSocket(at_t2.socket, 0x50000000,0x5000ffff, 0xfffffff); + bus2.bindTargetSocket(lt_t2.socket, 0x30000000,0x3000ffff, 0xfffffff); + bus2.bindTargetSocket(at_t3.socket, 0x60000000,0x6000ffff, 0xfffffff); + bus2.bindTargetSocket(lt_t3.socket, 0x40000000,0x4000ffff, 0xfffffff); + + sc_core::sc_start(); + + bus1.dump_status(); + bus2.dump_status(); + + return 0; +} diff --git a/src/systemc/tests/tlm/multi_sockets/simpleAddressMap.h b/src/systemc/tests/tlm/multi_sockets/simpleAddressMap.h new file mode 100644 index 000000000..87ef7851e --- /dev/null +++ b/src/systemc/tests/tlm/multi_sockets/simpleAddressMap.h @@ -0,0 +1,148 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +#ifndef __simpleAddressMap_h__ +#define __simpleAddressMap_h__ + +#include <systemc> +#include <map> + + +//-------------------------------------------------------------------------- +/** + * Simple address map implementation for the generic protocol. + */ +//-------------------------------------------------------------------------- +class SimpleAddressMap +{ + typedef std::map<sc_dt::uint64, unsigned int> mapType; + typedef std::map<sc_dt::uint64, unsigned int>::iterator addressMapIterator; + +public: + SimpleAddressMap() {} + + //-------------------------------------------------------------------------- + /** + * Check for overlapping address ranges + */ + //-------------------------------------------------------------------------- + void checkSanity() + { + addressMapIterator pos; + for (pos=m_addressMap.begin();pos!=m_addressMap.end();++pos){ + if(pos->second!=255) + SC_REPORT_ERROR("SimpleAddressMap","Overlapping Address Regions."); + else + ++pos; + if(pos->second==255) + SC_REPORT_ERROR("SimpleAddressMap","Overlapping Address Regions."); + } + std::cout<<"Address check successful."<<std::endl; + } + + + //-------------------------------------------------------------------------- + /** + * Print map + */ + //-------------------------------------------------------------------------- + void dumpMap() + { + std::cout<<"SimpleAddressMap: printing the sorted MAP:"<<std::endl; + addressMapIterator pos; + for (pos=m_addressMap.begin();pos!=m_addressMap.end();++pos){ + if(pos->second==255) + printf("key: %x value: %i \n", (unsigned int) ((pos->first+1)>>1)-1, pos->second); + else + printf("key: %x value: %i \n", (unsigned int) (pos->first>>1)-1, pos->second); + } + } + + + //-------------------------------------------------------------------------- + /** + * Decode slave address. + * @param address_ A slave address. + * @return The decoded slave port number. On error, the value 255 is returned. + */ + //-------------------------------------------------------------------------- + unsigned int decode(sc_dt::uint64 address_) + { + addressMapIterator lbound; + + lbound=m_addressMap.lower_bound((address_+1)<<1); + if((lbound->second == 255) | (lbound==m_addressMap.end())){ + SC_REPORT_ERROR("SimpleAddressMap", "Address does not match any registered address range."); + } + else{ + return lbound->second; + } + return 255; + } + + const sc_dt::uint64& get_max(){ + if (m_addressMap.size()){ + addressMapIterator i=(m_addressMap.end()); + i--; + retval=(i->first>>1)-1; + return retval; + } + else { + SC_REPORT_ERROR("SimpleAddressMap", "get_max() called on empty address map."); + return retval; + } + } + + const sc_dt::uint64& get_min(){ + if (m_addressMap.size()){ + addressMapIterator i=(m_addressMap.begin()); + retval=((i->first+1)>>1)-1; + return retval; + } + else { + SC_REPORT_ERROR("SimpleAddressMap", "get_min() called on empty address map."); + return retval; + } + } + + //-------------------------------------------------------------------------- + /** + * Insert a slave into the address map + */ + //-------------------------------------------------------------------------- + void insert(sc_dt::uint64 baseAddress_, sc_dt::uint64 highAddress_, unsigned int portNumber_) + { + if(baseAddress_>highAddress_) + SC_REPORT_ERROR("SimpleAddressMap", "Base address must be lower than high address."); + if(portNumber_>=255) + SC_REPORT_ERROR("SimpleAddressMap", "Only ;-) 255 targets can be handled."); + m_addressMap.insert(mapType::value_type(((baseAddress_+1)<<1)-1, 255 )); + m_addressMap.insert(mapType::value_type( (highAddress_+1)<<1 ,portNumber_)); + } + +private: + sc_dt::uint64 retval; + /// the address map + mapType m_addressMap; +}; + + + + +#endif |