scc 2026.07
SystemC components library
axi_initiator.h
1/*
2 * Copyright 2021 Arteris IP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <axi/axi_tlm.h>
20#include <axi/fsm/protocol_fsm.h>
21#include <cci_configuration>
22#include <scc/ordered_semaphore.h>
23#include <scc/peq.h>
24#include <scc/sc_variable.h>
25#include <systemc>
26#include <tlm/scc/pe/intor_if.h>
27#include <tlm_utils/peq_with_get.h>
28#include <tuple>
29#include <unordered_map>
30
31namespace axi {
32namespace pe {
33
34class axi_initiator_b : public sc_core::sc_module,
35 public axi::ace_bw_transport_if<axi::axi_protocol_types>,
37public:
38 using payload_type = axi::axi_protocol_types::tlm_payload_type;
39 using phase_type = axi::axi_protocol_types::tlm_phase_type;
40
41 sc_core::sc_in<bool> clk_i{"clk_i"};
42
43 sc_core::sc_export<tlm::scc::pe::intor_fw_b> fw_i{"fw_i"};
44
45 sc_core::sc_port<tlm::scc::pe::intor_bw_b, 1, sc_core::SC_ZERO_OR_MORE_BOUND> bw_o{"bw_o"};
46
47 void b_snoop(payload_type& trans, sc_core::sc_time& t) override;
48
49 tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override;
50
51 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) override;
52
53 size_t get_transferwith_in_bytes() const { return transfer_width_in_bytes; }
63 void transport(payload_type& trans, bool blocking) override;
70 void snoop_resp(payload_type& trans, bool sync = false) override;
71
72 axi_initiator_b(sc_core::sc_module_name nm, sc_core::sc_port_b<axi::axi_fw_transport_if<axi_protocol_types>>& port,
73 size_t transfer_width, flavor_e flavor);
74
75 virtual ~axi_initiator_b();
76
77 axi_initiator_b() = delete;
78
79 axi_initiator_b(axi_initiator_b const&) = delete;
80
81 axi_initiator_b(axi_initiator_b&&) = delete;
82
83 axi_initiator_b& operator=(axi_initiator_b const&) = delete;
84
85 axi_initiator_b& operator=(axi_initiator_b&&) = delete;
86
87 // AXI4 does not allow write data interleaving, and ncore3 only supports AXI4.
88 // However, AXI3 allows data interleaving and there may be support for AXI3 in Symphony, so keep it configurable in
89 // the testbench.
90 cci::cci_param<bool> data_interleaving{"data_interleaving", false};
92 cci::cci_param<unsigned> artv{"artv", 1};
94 cci::cci_param<unsigned> awtv{"awtv", 1};
96 cci::cci_param<unsigned> wbv{"wbv", 1};
98 cci::cci_param<unsigned> rbr{"rbr", 0};
100 cci::cci_param<unsigned> br{"br", 0};
102 cci::cci_param<unsigned> rla{"rla", 1};
104 cci::cci_param<unsigned> ba{"ba", 1};
106 cci::cci_param<bool> enable_id_serializing{"enable_id_serializing", false};
108 cci::cci_param<unsigned> outstanding_snoops{"outstanding_snoops", 8};
109
119 void add_protocol_cb(axi::fsm::protocol_time_point_e e, std::function<void(payload_type&, bool)> cb) {
120 assert(e < axi::fsm::CB_CNT);
121 protocol_cb[e] = cb;
122 }
123
124protected:
125 unsigned calculate_beats(payload_type& p) {
126 sc_assert(p.get_data_length() > 0);
127 return p.get_data_length() < transfer_width_in_bytes ? 1 : p.get_data_length() / transfer_width_in_bytes;
128 }
129
130 void snoop_thread();
131
132 const size_t transfer_width_in_bytes;
133
134 const flavor_e flavor;
135
136 sc_core::sc_port_b<axi::axi_fw_transport_if<axi_protocol_types>>& socket_fw;
137
138 struct tx_state {
139 payload_type* active_tx{nullptr};
141 };
142 std::unordered_map<void*, tx_state*> tx_state_by_tx;
143 std::unordered_map<unsigned, scc::ordered_semaphore*> id_mtx;
144
145 tlm_utils::peq_with_get<payload_type> snp_peq{"snp_peq"};
146
147 std::unordered_map<void*, tx_state*> snp_state_by_id;
148
149 scc::ordered_semaphore rd_chnl{1};
150
151 scc::ordered_semaphore wr_chnl{1};
152
153 scc::ordered_semaphore sresp_chnl{1};
154
155 sc_core::sc_event any_tx_finished;
156
157 sc_core::sc_time clk_period{10, sc_core::SC_NS};
158
159 scc::sc_variable<unsigned> rd_waiting{"RdWaiting", 0};
160 scc::sc_variable<unsigned> wr_waiting{"WrWaiting", 0};
161 scc::sc_variable<unsigned> rd_outstanding{"RdOutstanding", 0};
162 scc::sc_variable<unsigned> wr_outstanding{"WrOutstanding", 0};
163
164private:
165 sc_core::sc_clock* clk_if{nullptr};
166 void end_of_elaboration() override;
167 void clk_counter() { m_clock_counter++; }
168 unsigned get_clk_cnt() { return m_clock_counter; }
169
170 tlm::tlm_phase send(payload_type& trans, axi::pe::axi_initiator_b::tx_state* txs, tlm::tlm_phase phase);
171
172 unsigned m_clock_counter{0};
173 unsigned m_prev_clk_cnt{0};
174 unsigned snoops_in_flight{0};
175
176 std::array<std::function<void(payload_type&, bool)>, axi::fsm::CB_CNT> protocol_cb;
177};
178
182template <unsigned int BUSWIDTH = 32, typename TYPES = axi::axi_protocol_types, int N = 1,
183 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
184class axi_initiator : public axi_initiator_b {
185public:
186 using base = axi_initiator_b;
187
188 using payload_type = base::payload_type;
189 using phase_type = base::phase_type;
194 axi_initiator(const sc_core::sc_module_name& nm, axi::axi_initiator_socket<BUSWIDTH, TYPES, N, POL>& socket_)
195 : axi_initiator_b(nm, socket_.get_base_port(), BUSWIDTH, flavor_e::AXI)
196 , socket(socket_) {
197 socket(*this);
198 }
199
200 axi_initiator() = delete;
201
202 axi_initiator(axi_initiator const&) = delete;
203
204 axi_initiator(axi_initiator&&) = delete;
205
206 axi_initiator& operator=(axi_initiator const&) = delete;
207
208 axi_initiator& operator=(axi_initiator&&) = delete;
209
210private:
212};
213
217template <unsigned int BUSWIDTH = 32, typename TYPES = axi::axi_protocol_types, int N = 1,
218 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
219class ace_lite_initiator : public axi_initiator_b {
220public:
221 using base = axi_initiator_b;
222
223 using payload_type = base::payload_type;
224 using phase_type = base::phase_type;
230 : axi_initiator_b(nm, socket_.get_base_port(), BUSWIDTH, flavor_e::ACEL)
231 , socket(socket_) {
232 socket(*this);
233 }
234
235 ace_lite_initiator() = delete;
236
237 ace_lite_initiator(ace_lite_initiator const&) = delete;
238
240
241 ace_lite_initiator& operator=(ace_lite_initiator const&) = delete;
242
243 ace_lite_initiator& operator=(ace_lite_initiator&&) = delete;
244
245private:
247};
248
252template <unsigned int BUSWIDTH = 32, typename TYPES = axi::axi_protocol_types, int N = 1,
253 sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND>
254class ace_initiator : public axi_initiator_b {
255public:
256 using base = axi_initiator_b;
257
258 using payload_type = base::payload_type;
259 using phase_type = base::phase_type;
264 ace_initiator(const sc_core::sc_module_name& nm, axi::ace_initiator_socket<BUSWIDTH, TYPES, N, POL>& socket_)
265 : axi_initiator_b(nm, socket_.get_base_port(), BUSWIDTH, flavor_e::ACE)
266 , socket(socket_) {
267 socket(*this);
268 }
269
270 ace_initiator() = delete;
271
272 ace_initiator(ace_initiator const&) = delete;
273
274 ace_initiator(ace_initiator&&) = delete;
275
276 ace_initiator& operator=(ace_initiator const&) = delete;
277
278 ace_initiator& operator=(ace_initiator&&) = delete;
279
280private:
282};
283
284} /* namespace pe */
285} /* namespace axi */
ace_initiator(const sc_core::sc_module_name &nm, axi::ace_initiator_socket< BUSWIDTH, TYPES, N, POL > &socket_)
the constructor
ace_lite_initiator(const sc_core::sc_module_name &nm, axi::axi_initiator_socket< BUSWIDTH, TYPES, N, POL > &socket_)
the constructor
cci::cci_param< unsigned > rla
Read last data handshake to acknowledge.
cci::cci_param< unsigned > wbv
Write data handshake to next beat valid.
void b_snoop(payload_type &trans, sc_core::sc_time &t) override
snoop access to a snooped master
cci::cci_param< unsigned > br
Write response valid to ready.
void snoop_resp(payload_type &trans, bool sync=false) override
triggers a non-blocking snoop response if the snoop callback does not do so.
cci::cci_param< unsigned > outstanding_snoops
number of snoops which can be handled
void add_protocol_cb(axi::fsm::protocol_time_point_e e, std::function< void(payload_type &, bool)> cb)
register a callback for a certain time point
cci::cci_param< unsigned > ba
Write response handshake to acknowledge.
cci::cci_param< unsigned > rbr
Read data valid to same beat ready.
cci::cci_param< unsigned > artv
Read address valid to next read address valid.
void transport(payload_type &trans, bool blocking) override
The forward transport function. It behaves blocking and is re-entrant.
cci::cci_param< unsigned > awtv
Write address valid to next write address valid.
cci::cci_param< bool > enable_id_serializing
Quirks enable.
axi_initiator(const sc_core::sc_module_name &nm, axi::axi_initiator_socket< BUSWIDTH, TYPES, N, POL > &socket_)
the constructor
The ordered_semaphore primitive channel class.
protocol engine implementations
TLM2.0 components modeling AHB.
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
Definition axi_tlm.h:951
The AXI protocol traits class. Since the protocoll defines additional non-ignorable phases a dedicate...
Definition axi_tlm.h:919
priority event queue
Definition peq.h:42