scc 2025.09
SystemC components library
target.h
1/*******************************************************************************
2 * Copyright 2021-2022 MINRES Technologies GmbH
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#ifndef _BUS_TLM_PIN_OCP_TARGET_H_
18#define _BUS_TLM_PIN_OCP_TARGET_H_
19
20#include <ocp/ocp_tlm.h>
21#include <scc/peq.h>
22#include <scc/report.h>
23#include <scc/utilities.h>
24#include <systemc>
25#include <tlm/scc/tlm_gp_shared.h>
26#include <tlm/scc/tlm_mm.h>
27#include <util/ities.h>
28
30namespace ocp {
32namespace pin {
33
34#define OCP_CLK_DELAY 1_ps
35
36template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH = DATA_WIDTH>
37struct target : public sc_core::sc_module, public tlm::tlm_bw_transport_if<tlm::tlm_base_protocol_types> {
38 SC_HAS_PROCESS(target);
39
40 using payload_type = tlm::tlm_base_protocol_types::tlm_payload_type;
41 using phase_type = tlm::tlm_base_protocol_types::tlm_phase_type;
42
43 sc_core::sc_in<bool> clk_i{"clk_i"};
44 sc_core::sc_in<bool> reset{""};
45
46 sc_core::sc_in<sc_uint<3>> MCmd{"MCmd"};
47 sc_core::sc_in<sc_uint<ADDR_WIDTH>> MAddr{"MAddr"};
48 sc_core::sc_in<sc_uint<DATA_WIDTH>> MData{"MData"};
49 sc_core::sc_in<sc_uint<DATA_WIDTH / 8>> MByteEn{"MByteEn"};
50 sc_core::sc_out<bool> SCmdAccept{"SCmdAccept"};
51
52 sc_core::sc_out<sc_uint<2>> SResp{"SResp"};
53 sc_core::sc_out<sc_uint<DATA_WIDTH>> SData{"SData"};
54 sc_core::sc_in<bool> MRespAccept{"MRespAccept"};
55
56 tlm::tlm_initiator_socket<BUSWIDTH> isckt{"isckt"};
57
58 target(sc_core::sc_module_name const& nm)
59 : sc_core::sc_module(nm) {
60 isckt.bind(*this);
61 SC_METHOD(clk_delay);
62 sensitive << clk_i.pos();
63 dont_initialize();
64 SC_THREAD(req);
65 SC_THREAD(resp);
66 }
67
68private:
69 tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override;
70
71 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) override;
72
73 void end_of_elaboration() override { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
74
75 void clk_delay() { clk_delayed.notify(OCP_CLK_DELAY); }
76 void req();
77 void resp();
78 sc_core::sc_clock* clk_if{nullptr};
79 sc_core::sc_event clk_delayed, end_req_received_evt, wdata_end_req_evt;
81};
82
83} // namespace pin
84} // namespace ocp
85
86template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
87inline tlm::tlm_sync_enum ocp::pin::target<DATA_WIDTH, ADDR_WIDTH, BUSWIDTH>::nb_transport_bw(payload_type& trans, phase_type& phase,
88 sc_core::sc_time& t) {
89 if(phase == tlm::END_REQ) {
90 end_req_received_evt.notify(sc_core::SC_ZERO_TIME);
91 } else if(phase == tlm::BEGIN_RESP) {
92 resp_queue.notify(tlm::scc::tlm_gp_shared_ptr(&trans), t);
93 t += clk_if->period().value() ? clk_if->period() : sc_core::SC_ZERO_TIME;
94 }
95 return tlm::TLM_ACCEPTED;
96 ;
97}
98
99template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
100inline void ocp::pin::target<DATA_WIDTH, ADDR_WIDTH, BUSWIDTH>::invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
101 sc_dt::uint64 end_range) {}
102
103template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
104inline void ocp::pin::target<DATA_WIDTH, ADDR_WIDTH, BUSWIDTH>::req() {
105 this->SCmdAccept.write(false);
106 wait(sc_core::SC_ZERO_TIME);
107 while(true) {
108 wait(clk_delayed);
109 this->SCmdAccept.write(false);
110 while(!this->MCmd.read()) {
111 wait(this->MCmd.default_event());
112 }
113 auto cmd = static_cast<ocp::cmd_e>(this->MCmd.read().to_uint());
114 auto gp = tlm::scc::tlm_mm<>::get().allocate<ocp::ocp_extension>(DATA_WIDTH / 8);
115 gp->set_streaming_width(DATA_WIDTH / 8);
116 gp->set_data_length(DATA_WIDTH / 8);
117 auto addr = this->MAddr.read().to_uint64();
118 gp->set_address(addr);
119 switch(cmd) {
120 case cmd_e::WRITE:
121 case cmd_e::WRITE_CONDITIONAL:
122 case cmd_e::WRITE_NON_POSTED: {
123 gp->set_command(tlm::TLM_WRITE_COMMAND);
124 auto data = this->MData.read();
125 auto strb = this->MByteEn.read();
126 auto dptr = gp->get_data_ptr();
127 auto len = 0;
128 for(size_t i = 0; i < DATA_WIDTH / 8; ++i) {
129 auto be = strb[i] ? 0xff : 0;
130 if(!len && !be) {
131 addr++;
132 } else if(be) {
133 *dptr = data((i << 3) + 7, i << 3).to_uint();
134 ++dptr;
135 ++len;
136 }
137 }
138 gp->set_address(addr);
139 gp->set_streaming_width(len);
140 gp->set_data_length(len);
141 } break;
142 case cmd_e::READ:
143 case cmd_e::READEX:
144 case cmd_e::READ_LINKED:
145 gp->set_command(tlm::TLM_READ_COMMAND);
146 break;
147 default:
148 SCCFATAL(SCMOD) << "not supported";
149 }
150 auto ext = gp->get_extension<ocp::ocp_extension>();
151 ext->set_mcmd(cmd);
152 SCCDEBUG(SCMOD) << "received OCP bus transaction req " << *gp;
153 tlm::tlm_phase ph = tlm::BEGIN_REQ;
154 auto t{sc_core::SC_ZERO_TIME};
155 auto status = isckt->nb_transport_fw(*gp, ph, t);
156 if(status == tlm::TLM_ACCEPTED) {
157 wait(end_req_received_evt);
158 }
159 this->SCmdAccept.write(true);
160 wait(clk_i.posedge_event());
161 }
162}
163
164template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
165inline void ocp::pin::target<DATA_WIDTH, ADDR_WIDTH, BUSWIDTH>::resp() {
166 this->SResp.write(static_cast<unsigned>(ocp::resp_e::NULL_));
167 wait(sc_core::SC_ZERO_TIME);
168 uint8_t val;
169 while(true) {
170 wait(clk_i.posedge_event());
171 this->SResp.write(static_cast<unsigned>(ocp::resp_e::NULL_));
172 if(resp_queue.has_next()) {
173 auto gp = resp_queue.get();
174 SCCDEBUG(SCMOD) << "received OCP bus transaction resp " << *gp;
175 this->SResp.write(static_cast<unsigned>(ocp::resp_e::DVA));
176 if(gp->is_read()) {
177 auto d = gp->get_data_ptr();
178 this->SData.write(bit_comb<uint32_t>(d[0], d[1], d[2], d[3]));
179 }
180 do {
181 wait(this->MRespAccept.default_event() | clk_delayed);
182 } while(!this->MRespAccept.read());
183 tlm::tlm_phase ph = tlm::END_RESP;
184 auto t{sc_core::SC_ZERO_TIME};
185 auto status = isckt->nb_transport_fw(*gp, ph, t);
186 }
187 }
188}
189
190#endif /* _BUS_TLM_PIN_OCP_TARGET_H_ */
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition tlm_mm.h:218
R bit_comb(T first, Args... args)
Definition ities.h:123
pin level adapters
Definition target.h:32
TLM2.0 components modeling OCP.
Definition ocp_tlm.cpp:20
priority event queue
Definition peq.h:41
static tlm_mm & get()
accessor function of the singleton
Definition tlm_mm.h:338