Skip to content

Commit 303037b

Browse files
committed
Merge branch 'develop' of https://github.com/JingJerYen/SystemC-Components into JingJerYen-develop
2 parents f7574ef + fa2f71a commit 303037b

File tree

5 files changed

+441
-77
lines changed

5 files changed

+441
-77
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
if(NOT USE_CWR_SYSTEMC)
22
add_subdirectory(ace-axi)
33
add_subdirectory(ace-ace)
4+
add_subdirectory(apb_bfm)
45
add_subdirectory(axi-axi)
56
add_subdirectory(axi4_tlm-pin-tlm)
67
add_subdirectory(axi4lite_tlm-pin-tlm)

examples/apb_bfm/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
project (apb_bfm)
2+
3+
add_executable(${PROJECT_NAME} sc_main.cpp)
4+
target_link_libraries (${PROJECT_NAME} PUBLIC scc)
5+
target_link_libraries (${PROJECT_NAME} LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT})
6+
target_link_libraries (${PROJECT_NAME} LINK_PUBLIC ${CMAKE_DL_LIBS})
7+
if(APPLE)
8+
set_target_properties (${PROJECT_NAME} PROPERTIES LINK_FLAGS
9+
-Wl,-U,_sc_main,-U,___sanitizer_start_switch_fiber,-U,___sanitizer_finish_switch_fiber)
10+
endif()

examples/apb_bfm/sc_main.cpp

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
#include <cci_configuration>
2+
#include <fstream>
3+
#include <interfaces/apb/pin/initiator.h>
4+
#include <interfaces/apb/pin/target.h>
5+
#include <iomanip>
6+
#include <scc/configurable_tracer.h>
7+
#include <scc/configurer.h>
8+
#include <scc/report.h>
9+
#include <scc/traceable.h>
10+
#include <scc/tracer.h>
11+
#include <tlm/scc/initiator_mixin.h>
12+
#include <tlm/scc/target_mixin.h>
13+
14+
using namespace sc_core;
15+
using namespace scc;
16+
17+
class testbench : public sc_module, public scc::traceable {
18+
public:
19+
enum { WIDTH = 32 };
20+
tlm::scc::initiator_mixin<tlm::tlm_initiator_socket<WIDTH>> isck{"isck"};
21+
apb::pin::initiator<WIDTH> intor{"intor"};
22+
sc_core::sc_clock PCLK{"PCLK", 1_ns};
23+
sc_core::sc_signal<bool> PRESETn{"PRESETn"};
24+
sc_core::sc_signal<sc_dt::sc_uint<32>> PADDR{"PADDR"};
25+
sc_core::sc_signal<sc_dt::sc_uint<3>> PPROT{"PPROT"};
26+
sc_core::sc_signal<bool> PNSE{"PNSE"};
27+
sc_core::sc_signal<bool> PSELx{"PSELx"};
28+
sc_core::sc_signal<bool> PENABLE{"PENABLE"};
29+
sc_core::sc_signal<bool> PWRITE{"PWRITE"};
30+
sc_core::sc_signal<sc_dt::sc_uint<WIDTH>> PWDATA{"PWDATA"};
31+
sc_core::sc_signal<sc_dt::sc_uint<WIDTH / 8>> PSTRB{"PSTRB"};
32+
sc_core::sc_signal<bool> PREADY{"PREADY"};
33+
sc_core::sc_signal<sc_dt::sc_uint<WIDTH>> PRDATA{"PRDATA"};
34+
sc_core::sc_signal<bool> PSLVERR{"PSLVERR"};
35+
36+
apb::pin::target<WIDTH, 32> target{"target"};
37+
tlm::scc::target_mixin<tlm::tlm_target_socket<scc::LT>> tsck{"tsck"};
38+
39+
testbench(sc_module_name nm)
40+
: sc_module(nm) {
41+
SC_HAS_PROCESS(testbench);
42+
isck(intor.tsckt);
43+
intor.PCLK_i(PCLK);
44+
intor.PRESETn_i(PRESETn);
45+
intor.PADDR_o(PADDR);
46+
intor.PPROT_o(PPROT);
47+
intor.PNSE_o(PNSE);
48+
intor.PSELx_o(PSELx);
49+
intor.PENABLE_o(PENABLE);
50+
intor.PWRITE_o(PWRITE);
51+
intor.PWDATA_o(PWDATA);
52+
intor.PSTRB_o(PSTRB);
53+
intor.PREADY_i(PREADY);
54+
intor.PRDATA_i(PRDATA);
55+
intor.PSLVERR_i(PSLVERR);
56+
target.PCLK_i(PCLK);
57+
target.PRESETn_i(PRESETn);
58+
target.PADDR_i(PADDR);
59+
target.PPROT_i(PPROT);
60+
target.PNSE_i(PNSE);
61+
target.PSELx_i(PSELx);
62+
target.PENABLE_i(PENABLE);
63+
target.PWRITE_i(PWRITE);
64+
target.PWDATA_i(PWDATA);
65+
target.PSTRB_i(PSTRB);
66+
target.PRDATA_o(PRDATA);
67+
target.PREADY_o(PREADY);
68+
target.PSLVERR_o(PSLVERR);
69+
target.isckt(tsck);
70+
target.use_byte_enable.set_value(true);
71+
SC_THREAD(run);
72+
tsck.register_b_transport([this](tlm::tlm_generic_payload& gp, sc_time& delay) {
73+
gp.set_response_status(tlm::TLM_OK_RESPONSE);
74+
if(gp.is_write()) {
75+
SCCDEBUG(SCMOD) << "Received write access to addr 0x" << std::hex << gp.get_address();
76+
// Print all data bytes with their byte enable values
77+
if(gp.get_byte_enable_length() > 0) {
78+
SCCDEBUG(SCMOD) << " Data with byte enables:";
79+
for(size_t i = 0; i < gp.get_data_length(); ++i) {
80+
SCCDEBUG(SCMOD) << " Byte[" << i << "]: data=0x" << std::hex << std::setw(2) << std::setfill('0')
81+
<< (unsigned)gp.get_data_ptr()[i] << " BE=0x" << std::hex << std::setw(2) << std::setfill('0')
82+
<< (unsigned)gp.get_byte_enable_ptr()[i]
83+
<< (gp.get_byte_enable_ptr()[i] ? " (enabled)" : " (disabled)");
84+
}
85+
} else {
86+
SCCDEBUG(SCMOD) << " Data (no byte enables):";
87+
for(size_t i = 0; i < gp.get_data_length(); ++i) {
88+
SCCDEBUG(SCMOD) << " Byte[" << i << "]: data=0x" << std::hex << std::setw(2) << std::setfill('0')
89+
<< (unsigned)gp.get_data_ptr()[i];
90+
}
91+
}
92+
} else {
93+
memset(gp.get_data_ptr(), 0x55, gp.get_data_length());
94+
SCCDEBUG(SCMOD) << "Received read access from addr 0x" << std::hex << gp.get_address();
95+
}
96+
});
97+
}
98+
99+
void run() {
100+
///////////////////////////////////////////////////////////////////////////
101+
// Test data preparation
102+
///////////////////////////////////////////////////////////////////////////
103+
std::array<uint8_t, 8> write_data;
104+
std::array<uint8_t, 8> read_data;
105+
std::array<uint8_t, 4> byte_enable;
106+
107+
write_data[0] = 0xAA;
108+
write_data[1] = 0xBB;
109+
write_data[2] = 0xCC;
110+
write_data[3] = 0xDD;
111+
write_data[4] = 0xEE;
112+
write_data[5] = 0xFF;
113+
write_data[6] = 0x66;
114+
write_data[7] = 0x77;
115+
116+
///////////////////////////////////////////////////////////////////////////
117+
// Reset sequence
118+
///////////////////////////////////////////////////////////////////////////
119+
PRESETn.write(false);
120+
for(size_t i = 0; i < 10; ++i)
121+
wait(PCLK.posedge_event());
122+
PRESETn.write(true);
123+
wait(PCLK.posedge_event());
124+
125+
///////////////////////////////////////////////////////////////////////////
126+
// Test 1: Pin-level target - Aligned write (full word, all strobes)
127+
///////////////////////////////////////////////////////////////////////////
128+
PENABLE.write(0);
129+
130+
for(int i = 0; i < 2; i++) {
131+
// setup phase
132+
PSELx.write(1);
133+
PADDR.write(0x1000);
134+
PWDATA.write(*reinterpret_cast<uint32_t*>(write_data.data() + i * 4));
135+
PWRITE.write(1);
136+
PSTRB.write(0b1111);
137+
wait(PCLK.posedge_event());
138+
139+
// access phase
140+
PENABLE.write(1);
141+
while(!PREADY.read())
142+
wait(PREADY.value_changed_event());
143+
wait(PCLK.posedge_event());
144+
145+
// cleanup
146+
PENABLE.write(0);
147+
PSELx.write(0);
148+
}
149+
150+
///////////////////////////////////////////////////////////////////////////
151+
// Test 2: Pin-level target - Aligned read (full word)
152+
///////////////////////////////////////////////////////////////////////////
153+
for(int i = 0; i < 2; i++) {
154+
// setup phase
155+
PSELx.write(1);
156+
PADDR.write(0x1004);
157+
PWRITE.write(0);
158+
PSTRB.write(0);
159+
wait(PCLK.posedge_event());
160+
161+
// access phase
162+
PENABLE.write(1);
163+
while(!PREADY.read())
164+
wait(PREADY.value_changed_event());
165+
wait(PCLK.posedge_event());
166+
167+
// cleanup
168+
PENABLE.write(0);
169+
PSELx.write(0);
170+
171+
SCCDEBUG(SCMOD) << std::hex << "read data : " << PRDATA.read();
172+
}
173+
174+
///////////////////////////////////////////////////////////////////////////
175+
// Test 3: Pin-level target - Write with alternating byte strobes (0b1010)
176+
///////////////////////////////////////////////////////////////////////////
177+
// setup phase
178+
PSELx.write(1);
179+
PADDR.write(0x1008);
180+
PWDATA.write(*reinterpret_cast<uint32_t*>(write_data.data()));
181+
PWRITE.write(1);
182+
PSTRB.write(0b1010);
183+
wait(PCLK.posedge_event());
184+
185+
// access phase
186+
PENABLE.write(1);
187+
while(!PREADY.read())
188+
wait(PREADY.value_changed_event());
189+
wait(PCLK.posedge_event());
190+
191+
// cleanup
192+
PENABLE.write(0);
193+
PSELx.write(0);
194+
195+
wait(PCLK.posedge_event());
196+
197+
///////////////////////////////////////////////////////////////////////////
198+
// Test 4: TLM initiator via pin - Write with byte enables (BE: 0xFF, 0x00, 0x00, 0xFF)
199+
///////////////////////////////////////////////////////////////////////////
200+
tlm::tlm_generic_payload gp;
201+
sc_time delay;
202+
203+
byte_enable[0] = 0xFF;
204+
byte_enable[1] = 0x00;
205+
byte_enable[2] = 0x00;
206+
byte_enable[3] = 0xFF;
207+
208+
gp.set_address(0x1010);
209+
gp.set_data_length(4);
210+
gp.set_data_ptr(write_data.data() + 2);
211+
gp.set_byte_enable_ptr(byte_enable.data());
212+
gp.set_byte_enable_length(4);
213+
gp.set_streaming_width(4);
214+
gp.set_command(tlm::TLM_WRITE_COMMAND);
215+
delay = SC_ZERO_TIME;
216+
isck->b_transport(gp, delay);
217+
218+
///////////////////////////////////////////////////////////////////////////
219+
// Test 5: TLM initiator via pin - Aligned read (full word)
220+
///////////////////////////////////////////////////////////////////////////
221+
gp.set_address(0x1014);
222+
gp.set_data_length(4);
223+
gp.set_data_ptr(read_data.data());
224+
gp.set_streaming_width(4);
225+
gp.set_command(tlm::TLM_READ_COMMAND);
226+
delay = SC_ZERO_TIME;
227+
isck->b_transport(gp, delay);
228+
SCCDEBUG(SCMOD) << std::hex << "read data : " << *(uint32_t*)read_data.data();
229+
230+
///////////////////////////////////////////////////////////////////////////
231+
// Test 6: TLM initiator via pin - Unaligned partial write
232+
// Note: Unaligned write (0x1016-0x1018) is converted to strobe write (0x1014-0x1018)
233+
///////////////////////////////////////////////////////////////////////////
234+
gp.set_address(0x1016);
235+
gp.set_data_length(2);
236+
gp.set_data_ptr(write_data.data() + 2);
237+
gp.set_byte_enable_ptr(nullptr);
238+
gp.set_byte_enable_length(0);
239+
gp.set_streaming_width(2);
240+
gp.set_command(tlm::TLM_WRITE_COMMAND);
241+
delay = SC_ZERO_TIME;
242+
isck->b_transport(gp, delay);
243+
244+
///////////////////////////////////////////////////////////////////////////
245+
// Test 7: Invalid case - Transaction exceeding 32-bit boundary (disabled)
246+
// Note: This test is disabled as it tests an invalid scenario
247+
///////////////////////////////////////////////////////////////////////////
248+
if(0) {
249+
gp.set_address(0x1018);
250+
gp.set_data_length(8);
251+
gp.set_data_ptr(read_data.data());
252+
gp.set_streaming_width(8);
253+
gp.set_command(tlm::TLM_READ_COMMAND);
254+
delay = SC_ZERO_TIME;
255+
isck->b_transport(gp, delay);
256+
}
257+
258+
sc_stop();
259+
return;
260+
}
261+
};
262+
263+
int sc_main(int argc, char* argv[]) {
264+
sc_core::sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", sc_core::SC_DO_NOTHING);
265+
sc_report_handler::set_actions(SC_ID_MORE_THAN_ONE_SIGNAL_DRIVER_, SC_DO_NOTHING);
266+
///////////////////////////////////////////////////////////////////////////
267+
// configure logging
268+
///////////////////////////////////////////////////////////////////////////
269+
scc::init_logging(LogConfig().logLevel(scc::log::DEBUG).logAsync(false));
270+
///////////////////////////////////////////////////////////////////////////
271+
// set up configuration and tracing
272+
///////////////////////////////////////////////////////////////////////////
273+
scc::configurer cfg("apb_bfm.json");
274+
scc::configurable_tracer trace("apb_bfm", true, true);
275+
///////////////////////////////////////////////////////////////////////////
276+
// create modules/channels and trace
277+
///////////////////////////////////////////////////////////////////////////
278+
testbench tb("tb");
279+
280+
///////////////////////////////////////////////////////////////////////////
281+
// Create VCD trace file
282+
///////////////////////////////////////////////////////////////////////////
283+
sc_trace_file* vcd_trace = sc_create_vcd_trace_file("apb_trace");
284+
vcd_trace->set_time_unit(1, SC_PS); // Set time unit to picoseconds
285+
286+
// Trace clock and reset
287+
sc_trace(vcd_trace, tb.PCLK, "PCLK");
288+
sc_trace(vcd_trace, tb.PRESETn, "PRESETn");
289+
290+
// Trace APB address phase signals
291+
sc_trace(vcd_trace, tb.PADDR, "PADDR");
292+
sc_trace(vcd_trace, tb.PSELx, "PSELx");
293+
sc_trace(vcd_trace, tb.PENABLE, "PENABLE");
294+
sc_trace(vcd_trace, tb.PWRITE, "PWRITE");
295+
sc_trace(vcd_trace, tb.PPROT, "PPROT");
296+
sc_trace(vcd_trace, tb.PNSE, "PNSE");
297+
298+
// Trace APB data signals
299+
sc_trace(vcd_trace, tb.PWDATA, "PWDATA");
300+
sc_trace(vcd_trace, tb.PSTRB, "PSTRB");
301+
sc_trace(vcd_trace, tb.PRDATA, "PRDATA");
302+
303+
// Trace APB response signals
304+
sc_trace(vcd_trace, tb.PREADY, "PREADY");
305+
sc_trace(vcd_trace, tb.PSLVERR, "PSLVERR");
306+
cfg.configure();
307+
cfg.dump_configuration("apb_test.default.json");
308+
///////////////////////////////////////////////////////////////////////////
309+
// run the simulation
310+
///////////////////////////////////////////////////////////////////////////
311+
try {
312+
sc_core::sc_start();
313+
if(!sc_core::sc_end_of_simulation_invoked())
314+
sc_core::sc_stop();
315+
} catch(sc_report& e) {
316+
SCCERR() << "Caught sc_report exception during simulation: " << e.what() << ":" << e.get_msg();
317+
} catch(std::exception& e) {
318+
SCCERR() << "Caught exception during simulation: " << e.what();
319+
} catch(...) {
320+
SCCERR() << "Caught unspecified exception during simulation";
321+
}
322+
323+
///////////////////////////////////////////////////////////////////////////
324+
// Close VCD trace file
325+
///////////////////////////////////////////////////////////////////////////
326+
sc_close_vcd_trace_file(vcd_trace);
327+
328+
return 0;
329+
}

0 commit comments

Comments
 (0)