scc 2026.07
SystemC components library
replay_target.cpp
1#include "replay_target.h"
2
3namespace axi {
4namespace pe {
5
6const unsigned int CATCH_ALL_SEQUENCE = 0;
7
8replay_buffer::replay_buffer(const sc_core::sc_module_name& nm)
9: sc_core::sc_module(nm) {
10 fw_i.bind(*this);
11#if SYSTEMC_VERSION < 20250221
12 SC_HAS_PROCESS(replay_buffer);
13#endif
14 SC_METHOD(process_req2resp_fifos);
15 dont_initialize();
16 sensitive << clk_i.pos();
17 SC_THREAD(start_wr_resp_thread);
18 SC_THREAD(start_rd_resp_thread);
19}
20
21void replay_buffer::end_of_elaboration() { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
22
23void replay_buffer::start_of_simulation() {
24 if(replay_file_name.get_value().length()) {
25 std::ifstream ifs(replay_file_name.get_value());
26 if(ifs.is_open()) {
27 std::string line;
28 std::getline(ifs, line);
29 while(std::getline(ifs, line)) {
30 auto token = util::split(line, ',');
31 auto addr = strtoull(token[1].c_str(), nullptr, 10);
32 auto id = CATCH_ALL_SEQUENCE;
33 if(token[2].c_str()[0] != '*') {
34 id = strtoull(token[2].c_str(), nullptr, 10) + 1;
35 }
36 auto start_cycle = strtoull(token[3].c_str(), nullptr, 10);
37 auto req_resp_lat = strtoull(token[4].c_str(), nullptr, 10);
38 if(token[0] == "READ") {
39 if(id >= rd_sequence.size())
40 rd_sequence.resize(id + 1);
41 rd_sequence[id].emplace_back(addr, req_resp_lat);
42 } else if(token[0] == "WRITE") {
43 if(id >= wr_sequence.size())
44 wr_sequence.resize(id + 1);
45 wr_sequence[id].emplace_back(addr, req_resp_lat);
46 } else {
47 SCCWARN(SCMOD) << "Illegal command in replay file: " << line;
48 }
49 }
50 }
51 SCCINFO(SCMOD) << "SEQ file name of replay target = " << replay_file_name.get_value();
52 }
53}
54
55void replay_buffer::transport(tlm::tlm_generic_payload& trans, bool lt_transport) {
56 auto id = axi::get_axi_id(trans) + 1;
57 auto addr = trans.get_address();
58 auto cycle = clk_if ? sc_core::sc_time_stamp() / clk_if->period() : 0;
59
60 auto find_and_push = [&](std::vector<entry_t>& sequence, scc::fifo_w_cb<std::tuple<tlm::tlm_generic_payload*, unsigned>>& fifo) {
61 auto it = std::find_if(std::begin(sequence), std::end(sequence), [addr](entry_t const& e) { return std::get<0>(e) == addr; });
62 if(it != std::end(sequence)) {
63 fifo.push_back(std::make_tuple(&trans, std::get<1>(*it)));
64 sequence.erase(it);
65 return true;
66 }
67 return false;
68 };
69
70 if(trans.is_write()) {
71 if(id < wr_sequence.size() && wr_sequence[id].size()) {
72 if(find_and_push(wr_sequence[id], wr_req2resp_fifo)) {
73 return;
74 }
75 }
76 if(wr_sequence.size() && find_and_push(wr_sequence[CATCH_ALL_SEQUENCE], wr_req2resp_fifo)) {
77 return;
78 }
79 if(replay_file_name.get_value().length()) {
80 SCCWARN(SCMOD) << "No transaction in write sequence buffer for " << trans;
81 }
82 wr_req2resp_fifo.push_back(std::make_tuple(&trans, 0));
83 } else if(trans.is_read()) {
84 if(id < rd_sequence.size() && rd_sequence[id].size()) {
85 if(find_and_push(rd_sequence[id], rd_req2resp_fifo)) {
86 return;
87 }
88 }
89 if(rd_sequence.size() && find_and_push(rd_sequence[CATCH_ALL_SEQUENCE], rd_req2resp_fifo)) {
90 return;
91 }
92 if(replay_file_name.get_value().length()) {
93 SCCWARN(SCMOD) << "No transaction in read sequence buffer for " << trans;
94 }
95 rd_req2resp_fifo.push_back(std::make_tuple(&trans, 0));
96 }
97}
98
99void replay_buffer::process_req2resp_fifos() {
100 while(rd_req2resp_fifo.avail()) {
101 auto& entry = rd_req2resp_fifo.front();
102 if(std::get<1>(entry) == 0) {
103 rd_resp_fifo.push_back(std::get<0>(entry));
104 } else {
105 std::get<1>(entry) -= 1;
106 rd_req2resp_fifo.push_back(entry);
107 }
108 rd_req2resp_fifo.pop_front();
109 }
110 while(wr_req2resp_fifo.avail()) {
111 auto& entry = wr_req2resp_fifo.front();
112 if(std::get<1>(entry) == 0) {
113 wr_resp_fifo.push_back(std::get<0>(entry));
114 } else {
115 std::get<1>(entry) -= 1;
116 wr_req2resp_fifo.push_back(entry);
117 }
118 wr_req2resp_fifo.pop_front();
119 }
120}
121
122void replay_buffer::start_rd_resp_thread() {
123 auto residual_clocks = 0.0;
124 while(true) {
125 wait(rd_resp_fifo.data_written_event());
126 while(rd_resp_fifo.avail())
127 if(auto* trans = rd_resp_fifo.front()) {
128 if(clk_if) {
129 if(time_per_byte_total.value()) {
130 scc::ordered_semaphore::lock lck(total_arb);
131 auto clocks = trans->get_data_length() * time_per_byte_total / clk_if->period() + total_residual_clocks;
132 auto delay = static_cast<unsigned>(clocks);
133 total_residual_clocks = clocks - delay;
134 wait(delay * clk_if->period());
135 wait(clk_i.posedge_event());
136 } else if(time_per_byte_rd.value()) {
137 auto clocks = trans->get_data_length() * time_per_byte_rd / clk_if->period() + residual_clocks;
138 auto delay = static_cast<unsigned>(clocks);
139 residual_clocks = clocks - delay;
140 wait(delay * clk_if->period());
141 wait(clk_i.posedge_event());
142 }
143 }
144 while(bw_o->transport(*trans) != 0)
145 wait(clk_i.posedge_event());
146 rd_resp_fifo.pop_front();
147 }
148 }
149}
150
151void replay_buffer::start_wr_resp_thread() {
152 auto residual_clocks = 0.0;
153 while(true) {
154 wait(wr_resp_fifo.data_written_event());
155 while(wr_resp_fifo.avail())
156 if(auto* trans = wr_resp_fifo.front()) {
157 if(clk_if) {
158 if(time_per_byte_total.value()) {
159 scc::ordered_semaphore::lock lck(total_arb);
160 auto clocks = trans->get_data_length() * time_per_byte_total / clk_if->period() + total_residual_clocks;
161 auto delay = static_cast<unsigned>(clocks);
162 total_residual_clocks = clocks - delay;
163 wait(delay * clk_if->period());
164 wait(clk_i.posedge_event());
165 } else if(time_per_byte_wr.value()) {
166 auto clocks = trans->get_data_length() * time_per_byte_wr / clk_if->period() + residual_clocks;
167 auto delay = static_cast<unsigned>(clocks);
168 residual_clocks = clocks - delay;
169 wait(delay * clk_if->period());
170 wait(clk_i.posedge_event());
171 }
172 }
173 while(bw_o->transport(*trans) != 0)
174 wait(clk_i.posedge_event());
175 wr_resp_fifo.pop_front();
176 }
177 }
178}
179} // namespace pe
180} // namespace axi
void transport(tlm::tlm_generic_payload &payload, bool lt_transport=false) override
scc::fifo_w_cb< std::tuple< tlm::tlm_generic_payload *, unsigned > > rd_req2resp_fifo
queues realizing the latencies
fifo with callbacks
Definition fifo_w_cb.h:38
protocol engine implementations
TLM2.0 components modeling AHB.
std::vector< std::string > split(const std::string &s, char separator)
Definition ities.h:281
a lock for the semaphore