1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#ifndef __SIMPLEBUSLT_H__
21#define __SIMPLEBUSLT_H__
22
23//#include <systemc>
24#include "tlm.h"
25
26#include "tlm_utils/simple_target_socket.h"
27#include "tlm_utils/simple_initiator_socket.h"
28
29template <int NR_OF_INITIATORS, int NR_OF_TARGETS>
30class SimpleBusLT : public sc_core::sc_module
31{
32public:
33  typedef tlm::tlm_generic_payload                 transaction_type;
34  typedef tlm::tlm_phase                           phase_type;
35  typedef tlm::tlm_sync_enum                       sync_enum_type;
36  typedef tlm_utils::simple_target_socket_tagged<SimpleBusLT>    target_socket_type;
37  typedef tlm_utils::simple_initiator_socket_tagged<SimpleBusLT> initiator_socket_type;
38
39public:
40  target_socket_type target_socket[NR_OF_INITIATORS];
41  initiator_socket_type initiator_socket[NR_OF_TARGETS];
42
43public:
44  SC_HAS_PROCESS(SimpleBusLT);
45  SimpleBusLT(sc_core::sc_module_name name) :
46    sc_core::sc_module(name)
47  {
48    for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
49      target_socket[i].register_b_transport(this, &SimpleBusLT::initiatorBTransport, i);
50      target_socket[i].register_transport_dbg(this, &SimpleBusLT::transportDebug, i);
51      target_socket[i].register_get_direct_mem_ptr(this, &SimpleBusLT::getDMIPointer, i);
52    }
53    for (unsigned int i = 0; i < NR_OF_TARGETS; ++i) {
54      initiator_socket[i].register_invalidate_direct_mem_ptr(this, &SimpleBusLT::invalidateDMIPointers, i);
55    }
56  }
57
58  //
59  // Dummy decoder:
60  // - address[31-28]: portId
61  // - address[27-0]: masked address
62  //
63
64  unsigned int getPortId(const sc_dt::uint64& address)
65  {
66    return (unsigned int)address >> 28;
67  }
68
69  sc_dt::uint64 getAddressOffset(unsigned int portId)
70  {
71    return portId << 28;
72  }
73
74  sc_dt::uint64 getAddressMask(unsigned int portId)
75  {
76    return 0xfffffff;
77  }
78
79  unsigned int decode(const sc_dt::uint64& address)
80  {
81    // decode address:
82    // - return initiator socket id
83
84    return getPortId(address);
85  }
86
87  //
88  // interface methods
89  //
90
91  //
92  // LT protocol
93  // - forward each call to the target/initiator
94  //
95  void initiatorBTransport(int SocketId,
96                           transaction_type& trans,
97                           sc_core::sc_time& t)
98  {
99    initiator_socket_type* decodeSocket;
100    unsigned int portId = decode(trans.get_address());
101    assert(portId < NR_OF_TARGETS);
102    decodeSocket = &initiator_socket[portId];
103    trans.set_address(trans.get_address() & getAddressMask(portId));
104
105    (*decodeSocket)->b_transport(trans, t);
106  }
107
108  unsigned int transportDebug(int SocketId,
109                              transaction_type& trans)
110  {
111    unsigned int portId = decode(trans.get_address());
112    assert(portId < NR_OF_TARGETS);
113    initiator_socket_type* decodeSocket = &initiator_socket[portId];
114    trans.set_address( trans.get_address() & getAddressMask(portId) );
115
116    return (*decodeSocket)->transport_dbg(trans);
117  }
118
119  bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high)
120  {
121    sc_dt::uint64 addressOffset = getAddressOffset(portId);
122    sc_dt::uint64 addressMask = getAddressMask(portId);
123
124    if (low > addressMask) {
125      // Range does not overlap with addressrange for this target
126      return false;
127    }
128
129    low += addressOffset;
130    if (high > addressMask) {
131      high = addressOffset + addressMask;
132
133    } else {
134      high += addressOffset;
135    }
136    return true;
137  }
138
139  bool getDMIPointer(int SocketId,
140                     transaction_type& trans,
141                     tlm::tlm_dmi&  dmi_data)
142  {
143    sc_dt::uint64 address = trans.get_address();
144
145    unsigned int portId = decode(address);
146    assert(portId < NR_OF_TARGETS);
147    initiator_socket_type* decodeSocket = &initiator_socket[portId];
148    sc_dt::uint64 maskedAddress = address & getAddressMask(portId);
149
150    trans.set_address(maskedAddress);
151
152    bool result =
153      (*decodeSocket)->get_direct_mem_ptr(trans, dmi_data);
154
155    if (result)
156    {
157      // Range must contain address
158      assert(dmi_data.get_start_address() <= maskedAddress);
159      assert(dmi_data.get_end_address() >= maskedAddress);
160    }
161
162    // Should always succeed
163	sc_dt::uint64 start, end;
164	start = dmi_data.get_start_address();
165	end = dmi_data.get_end_address();
166
167	limitRange(portId, start, end);
168
169	dmi_data.set_start_address(start);
170	dmi_data.set_end_address(end);
171
172    return result;
173  }
174
175  void invalidateDMIPointers(int port_id,
176                             sc_dt::uint64 start_range,
177                             sc_dt::uint64 end_range)
178  {
179    // FIXME: probably faster to always invalidate everything?
180
181    if (!limitRange(port_id, start_range, end_range)) {
182      // Range does not fall into address range of target
183      return;
184    }
185
186    for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
187      (target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range);
188    }
189  }
190
191};
192
193#endif
194