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