summaryrefslogtreecommitdiff
path: root/src/systemc/tests/tlm/multi_sockets
diff options
context:
space:
mode:
authorGabe Black <gabeblack@google.com>2018-05-24 01:37:55 -0700
committerGabe Black <gabeblack@google.com>2018-08-08 10:09:54 +0000
commit16fa8d7cc8c92f5ab879e4cf9c6c0bbb3567860f (patch)
tree7b6faaacb4574a555e561534aa4a8508c0624c32 /src/systemc/tests/tlm/multi_sockets
parent7235d3b5211d0ba8f528d930a4c1e7ad62eec51a (diff)
downloadgem5-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')
-rw-r--r--src/systemc/tests/tlm/multi_sockets/MultiSocketSimpleSwitchAT.h340
-rw-r--r--src/systemc/tests/tlm/multi_sockets/extensionPool.h106
-rw-r--r--src/systemc/tests/tlm/multi_sockets/golden/multi_sockets.log151
-rw-r--r--src/systemc/tests/tlm/multi_sockets/multi_sockets.cpp73
-rw-r--r--src/systemc/tests/tlm/multi_sockets/simpleAddressMap.h148
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