From 1f99de561ff78939018b6662d0fb03f2971d5995 Mon Sep 17 00:00:00 2001 From: ycc738 Date: Sun, 12 Oct 2025 17:06:28 +0800 Subject: [PATCH 1/2] add examples for APB --- examples/CMakeLists.txt | 1 + examples/apb_bfm/CMakeLists.txt | 10 + examples/apb_bfm/sc_main.cpp | 328 ++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 examples/apb_bfm/CMakeLists.txt create mode 100644 examples/apb_bfm/sc_main.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 12c0cff7..d8e138b5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,7 @@ if(NOT USE_CWR_SYSTEMC) add_subdirectory(ace-axi) add_subdirectory(ace-ace) + add_subdirectory(apb_bfm) add_subdirectory(axi-axi) add_subdirectory(axi4_tlm-pin-tlm) add_subdirectory(axi4lite_tlm-pin-tlm) diff --git a/examples/apb_bfm/CMakeLists.txt b/examples/apb_bfm/CMakeLists.txt new file mode 100644 index 00000000..a84256da --- /dev/null +++ b/examples/apb_bfm/CMakeLists.txt @@ -0,0 +1,10 @@ +project (apb_bfm) + +add_executable(${PROJECT_NAME} sc_main.cpp) +target_link_libraries (${PROJECT_NAME} PUBLIC scc) +target_link_libraries (${PROJECT_NAME} LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (${PROJECT_NAME} LINK_PUBLIC ${CMAKE_DL_LIBS}) +if(APPLE) + set_target_properties (${PROJECT_NAME} PROPERTIES LINK_FLAGS + -Wl,-U,_sc_main,-U,___sanitizer_start_switch_fiber,-U,___sanitizer_finish_switch_fiber) +endif() diff --git a/examples/apb_bfm/sc_main.cpp b/examples/apb_bfm/sc_main.cpp new file mode 100644 index 00000000..43b363d9 --- /dev/null +++ b/examples/apb_bfm/sc_main.cpp @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace sc_core; +using namespace scc; + +class testbench : public sc_module, public scc::traceable { +public: + enum { WIDTH = 32 }; + tlm::scc::initiator_mixin> isck{"isck"}; + apb::pin::initiator intor{"intor"}; + sc_core::sc_clock PCLK{"PCLK", 1_ns}; + sc_core::sc_signal PRESETn{"PRESETn"}; + sc_core::sc_signal> PADDR{"PADDR"}; + sc_core::sc_signal> PPROT{"PPROT"}; + sc_core::sc_signal PNSE{"PNSE"}; + sc_core::sc_signal PSELx{"PSELx"}; + sc_core::sc_signal PENABLE{"PENABLE"}; + sc_core::sc_signal PWRITE{"PWRITE"}; + sc_core::sc_signal> PWDATA{"PWDATA"}; + sc_core::sc_signal> PSTRB{"PSTRB"}; + sc_core::sc_signal PREADY{"PREADY"}; + sc_core::sc_signal> PRDATA{"PRDATA"}; + sc_core::sc_signal PSLVERR{"PSLVERR"}; + + apb::pin::target target{"target"}; + tlm::scc::target_mixin> tsck{"tsck"}; + + testbench(sc_module_name nm) + : sc_module(nm) { + SC_HAS_PROCESS(testbench); + isck(intor.tsckt); + intor.PCLK_i(PCLK); + intor.PRESETn_i(PRESETn); + intor.PADDR_o(PADDR); + intor.PPROT_o(PPROT); + intor.PNSE_o(PNSE); + intor.PSELx_o(PSELx); + intor.PENABLE_o(PENABLE); + intor.PWRITE_o(PWRITE); + intor.PWDATA_o(PWDATA); + intor.PSTRB_o(PSTRB); + intor.PREADY_i(PREADY); + intor.PRDATA_i(PRDATA); + intor.PSLVERR_i(PSLVERR); + target.PCLK_i(PCLK); + target.PRESETn_i(PRESETn); + target.PADDR_i(PADDR); + target.PPROT_i(PPROT); + target.PNSE_i(PNSE); + target.PSELx_i(PSELx); + target.PENABLE_i(PENABLE); + target.PWRITE_i(PWRITE); + target.PWDATA_i(PWDATA); + target.PSTRB_i(PSTRB); + target.PRDATA_o(PRDATA); + target.PREADY_o(PREADY); + target.PSLVERR_o(PSLVERR); + target.isckt(tsck); + SC_THREAD(run); + tsck.register_b_transport([this](tlm::tlm_generic_payload& gp, sc_time& delay) { + gp.set_response_status(tlm::TLM_OK_RESPONSE); + if(gp.is_write()) { + SCCDEBUG(SCMOD) << "Received write access to addr 0x" << std::hex << gp.get_address(); + // Print all data bytes with their byte enable values + if(gp.get_byte_enable_length() > 0) { + SCCDEBUG(SCMOD) << " Data with byte enables:"; + for(size_t i = 0; i < gp.get_data_length(); ++i) { + SCCDEBUG(SCMOD) << " Byte[" << i << "]: data=0x" << std::hex << std::setw(2) << std::setfill('0') + << (unsigned)gp.get_data_ptr()[i] << " BE=0x" << std::hex << std::setw(2) << std::setfill('0') + << (unsigned)gp.get_byte_enable_ptr()[i] + << (gp.get_byte_enable_ptr()[i] ? " (enabled)" : " (disabled)"); + } + } else { + SCCDEBUG(SCMOD) << " Data (no byte enables):"; + for(size_t i = 0; i < gp.get_data_length(); ++i) { + SCCDEBUG(SCMOD) << " Byte[" << i << "]: data=0x" << std::hex << std::setw(2) << std::setfill('0') + << (unsigned)gp.get_data_ptr()[i]; + } + } + } else { + memset(gp.get_data_ptr(), 0x55, gp.get_data_length()); + SCCDEBUG(SCMOD) << "Received read access from addr 0x" << std::hex << gp.get_address(); + } + }); + } + + void run() { + /////////////////////////////////////////////////////////////////////////// + // Test data preparation + /////////////////////////////////////////////////////////////////////////// + std::array write_data; + std::array read_data; + std::array byte_enable; + + write_data[0] = 0xAA; + write_data[1] = 0xBB; + write_data[2] = 0xCC; + write_data[3] = 0xDD; + write_data[4] = 0xEE; + write_data[5] = 0xFF; + write_data[6] = 0x66; + write_data[7] = 0x77; + + /////////////////////////////////////////////////////////////////////////// + // Reset sequence + /////////////////////////////////////////////////////////////////////////// + PRESETn.write(false); + for(size_t i = 0; i < 10; ++i) + wait(PCLK.posedge_event()); + PRESETn.write(true); + wait(PCLK.posedge_event()); + + /////////////////////////////////////////////////////////////////////////// + // Test 1: Pin-level target - Aligned write (full word, all strobes) + /////////////////////////////////////////////////////////////////////////// + PENABLE.write(0); + + for(int i = 0; i < 2; i++) { + // setup phase + PSELx.write(1); + PADDR.write(0x1000); + PWDATA.write(*reinterpret_cast(write_data.data() + i * 4)); + PWRITE.write(1); + PSTRB.write(0b1111); + wait(PCLK.posedge_event()); + + // access phase + PENABLE.write(1); + while(!PREADY.read()) + wait(PREADY.value_changed_event()); + wait(PCLK.posedge_event()); + + // cleanup + PENABLE.write(0); + PSELx.write(0); + } + + /////////////////////////////////////////////////////////////////////////// + // Test 2: Pin-level target - Aligned read (full word) + /////////////////////////////////////////////////////////////////////////// + for(int i = 0; i < 2; i++) { + // setup phase + PSELx.write(1); + PADDR.write(0x1004); + PWRITE.write(0); + PSTRB.write(0); + wait(PCLK.posedge_event()); + + // access phase + PENABLE.write(1); + while(!PREADY.read()) + wait(PREADY.value_changed_event()); + wait(PCLK.posedge_event()); + + // cleanup + PENABLE.write(0); + PSELx.write(0); + + SCCDEBUG(SCMOD) << std::hex << "read data : " << PRDATA.read(); + } + + /////////////////////////////////////////////////////////////////////////// + // Test 3: Pin-level target - Write with alternating byte strobes (0b1010) + /////////////////////////////////////////////////////////////////////////// + // setup phase + PSELx.write(1); + PADDR.write(0x1008); + PWDATA.write(*reinterpret_cast(write_data.data())); + PWRITE.write(1); + PSTRB.write(0b1010); + wait(PCLK.posedge_event()); + + // access phase + PENABLE.write(1); + while(!PREADY.read()) + wait(PREADY.value_changed_event()); + wait(PCLK.posedge_event()); + + // cleanup + PENABLE.write(0); + PSELx.write(0); + + wait(PCLK.posedge_event()); + + /////////////////////////////////////////////////////////////////////////// + // Test 4: TLM initiator via pin - Write with byte enables (BE: 0xFF, 0x00, 0x00, 0xFF) + /////////////////////////////////////////////////////////////////////////// + tlm::tlm_generic_payload gp; + sc_time delay; + + byte_enable[0] = 0xFF; + byte_enable[1] = 0x00; + byte_enable[2] = 0x00; + byte_enable[3] = 0xFF; + + gp.set_address(0x1010); + gp.set_data_length(4); + gp.set_data_ptr(write_data.data() + 2); + gp.set_byte_enable_ptr(byte_enable.data()); + gp.set_byte_enable_length(4); + gp.set_streaming_width(4); + gp.set_command(tlm::TLM_WRITE_COMMAND); + delay = SC_ZERO_TIME; + isck->b_transport(gp, delay); + + /////////////////////////////////////////////////////////////////////////// + // Test 5: TLM initiator via pin - Aligned read (full word) + /////////////////////////////////////////////////////////////////////////// + gp.set_address(0x1014); + gp.set_data_length(4); + gp.set_data_ptr(read_data.data()); + gp.set_streaming_width(4); + gp.set_command(tlm::TLM_READ_COMMAND); + delay = SC_ZERO_TIME; + isck->b_transport(gp, delay); + SCCDEBUG(SCMOD) << std::hex << "read data : " << *(uint32_t*)read_data.data(); + + /////////////////////////////////////////////////////////////////////////// + // Test 6: TLM initiator via pin - Unaligned partial write + // Note: Unaligned write (0x1016-0x1018) is converted to strobe write (0x1014-0x1018) + /////////////////////////////////////////////////////////////////////////// + gp.set_address(0x1016); + gp.set_data_length(2); + gp.set_data_ptr(write_data.data() + 2); + gp.set_byte_enable_ptr(nullptr); + gp.set_byte_enable_length(0); + gp.set_streaming_width(2); + gp.set_command(tlm::TLM_WRITE_COMMAND); + delay = SC_ZERO_TIME; + isck->b_transport(gp, delay); + + /////////////////////////////////////////////////////////////////////////// + // Test 7: Invalid case - Transaction exceeding 32-bit boundary (disabled) + // Note: This test is disabled as it tests an invalid scenario + /////////////////////////////////////////////////////////////////////////// + if(0) { + gp.set_address(0x1018); + gp.set_data_length(8); + gp.set_data_ptr(read_data.data()); + gp.set_streaming_width(8); + gp.set_command(tlm::TLM_READ_COMMAND); + delay = SC_ZERO_TIME; + isck->b_transport(gp, delay); + } + + sc_stop(); + return; + } +}; + +int sc_main(int argc, char* argv[]) { + sc_core::sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", sc_core::SC_DO_NOTHING); + sc_report_handler::set_actions(SC_ID_MORE_THAN_ONE_SIGNAL_DRIVER_, SC_DO_NOTHING); + /////////////////////////////////////////////////////////////////////////// + // configure logging + /////////////////////////////////////////////////////////////////////////// + scc::init_logging(LogConfig().logLevel(scc::log::DEBUG).logAsync(false)); + /////////////////////////////////////////////////////////////////////////// + // set up configuration and tracing + /////////////////////////////////////////////////////////////////////////// + scc::configurer cfg("apb_bfm.json"); + scc::configurable_tracer trace("apb_bfm", true, true); + /////////////////////////////////////////////////////////////////////////// + // create modules/channels and trace + /////////////////////////////////////////////////////////////////////////// + testbench tb("tb"); + + /////////////////////////////////////////////////////////////////////////// + // Create VCD trace file + /////////////////////////////////////////////////////////////////////////// + sc_trace_file *vcd_trace = sc_create_vcd_trace_file("apb_trace"); + vcd_trace->set_time_unit(1, SC_PS); // Set time unit to picoseconds + + // Trace clock and reset + sc_trace(vcd_trace, tb.PCLK, "PCLK"); + sc_trace(vcd_trace, tb.PRESETn, "PRESETn"); + + // Trace APB address phase signals + sc_trace(vcd_trace, tb.PADDR, "PADDR"); + sc_trace(vcd_trace, tb.PSELx, "PSELx"); + sc_trace(vcd_trace, tb.PENABLE, "PENABLE"); + sc_trace(vcd_trace, tb.PWRITE, "PWRITE"); + sc_trace(vcd_trace, tb.PPROT, "PPROT"); + sc_trace(vcd_trace, tb.PNSE, "PNSE"); + + // Trace APB data signals + sc_trace(vcd_trace, tb.PWDATA, "PWDATA"); + sc_trace(vcd_trace, tb.PSTRB, "PSTRB"); + sc_trace(vcd_trace, tb.PRDATA, "PRDATA"); + + // Trace APB response signals + sc_trace(vcd_trace, tb.PREADY, "PREADY"); + sc_trace(vcd_trace, tb.PSLVERR, "PSLVERR"); + cfg.configure(); + cfg.dump_configuration("apb_test.default.json"); + /////////////////////////////////////////////////////////////////////////// + // run the simulation + /////////////////////////////////////////////////////////////////////////// + try { + sc_core::sc_start(); + if(!sc_core::sc_end_of_simulation_invoked()) + sc_core::sc_stop(); + } catch(sc_report& e) { + SCCERR() << "Caught sc_report exception during simulation: " << e.what() << ":" << e.get_msg(); + } catch(std::exception& e) { + SCCERR() << "Caught exception during simulation: " << e.what(); + } catch(...) { + SCCERR() << "Caught unspecified exception during simulation"; + } + + /////////////////////////////////////////////////////////////////////////// + // Close VCD trace file + /////////////////////////////////////////////////////////////////////////// + sc_close_vcd_trace_file(vcd_trace); + + return 0; +} From fa2f71a1f2d17447a863d54e8a4930ff7f37c7e4 Mon Sep 17 00:00:00 2001 From: ycc738 Date: Sun, 12 Oct 2025 18:49:53 +0800 Subject: [PATCH 2/2] fix apb pin level adapters 1. Handle strobe signals correctly 2. Free the payload after usage to avoid deadlock 3. Remove redundant code --- src/interfaces/apb/pin/initiator.h | 49 ++++++----- src/interfaces/apb/pin/target.h | 132 ++++++++++++++--------------- 2 files changed, 91 insertions(+), 90 deletions(-) diff --git a/src/interfaces/apb/pin/initiator.h b/src/interfaces/apb/pin/initiator.h index 26d192b9..e34f2aac 100644 --- a/src/interfaces/apb/pin/initiator.h +++ b/src/interfaces/apb/pin/initiator.h @@ -88,14 +88,13 @@ initiator::initiator(const sc_core::sc_module_name& nm) } template inline void initiator::bus_task() { - auto& hready = PREADY_i.read(); while(true) { wait(inqueue.get_event()); while(auto trans = inqueue.get_next_transaction()) { auto addr_offset = trans->get_address() & (DATA_WIDTH / 8 - 1); auto upper = addr_offset + trans->get_data_length(); - if(!PSTRB_o.get_interface() && addr_offset && upper != (DATA_WIDTH / 8)) { - SCCERR(SCMOD) << "Narrow accesses are not supported as there is no PSTRB signal! Skipping " << *trans; + if(!PSTRB_o.get_interface() && (addr_offset || upper != (DATA_WIDTH / 8))) { + SCCERR(SCMOD) << "Narrow accesses are not supported before APB4 as there is no PSTRB signal! Skipping " << *trans; tlm::tlm_phase phase{tlm::END_RESP}; sc_core::sc_time delay; trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE); @@ -108,43 +107,51 @@ template inline void initiatornb_transport_bw(*trans, phase, delay); } else { SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address() << ", starting APB setup phase, "; - auto bytes_exp = scc::ilog2(trans->get_data_length()); - auto width_exp = scc::ilog2(DATA_WIDTH / 8); - size_t size = 0; - for(; size < bytes_exp; ++size) - if(trans->get_address() & (1 << size)) - break; // i contains the first bit not being 0 auto* ext = trans->template get_extension(); if(trans->is_write()) { - if(upper <= DATA_WIDTH / 8) { - data_t data{0}; - strb_t strb{0}; + data_t data{0}; + strb_t strb{0}; + // Handle TLM byte enables if present + if(trans->get_byte_enable_ptr() && trans->get_byte_enable_length() > 0) { + for(size_t i = 0; i < DATA_WIDTH / 8; ++i) { + if(i >= addr_offset && i < upper) { + auto be_idx = (i - addr_offset) % trans->get_byte_enable_length(); + if(trans->get_byte_enable_ptr()[be_idx] != 0) { + data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset); + strb[i] = 1; + } + } + } + } else { + // No byte enables, write contiguous data for(size_t i = 0; i < upper; ++i) { if(i >= addr_offset) { data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset); strb[i] = 1; } } - PWDATA_o.write(data); - if(PSTRB_o.get_interface()) - PSTRB_o.write(strb); } + PWDATA_o.write(data); + if(PSTRB_o.get_interface()) + PSTRB_o.write(strb); + } else if(PSTRB_o.get_interface()) { + // From spec : For read transfers the bus master must drive all bits of PSTRB LOW + PSTRB_o.write(0); } PWRITE_o.write(trans->is_write()); PADDR_o.write(trans->get_address() - addr_offset); // adjust address to be aligned PSELx_o.write(true); - if(PPROT_o.get_interface() && ext) - PPROT_o.write(ext ? ext->get_protection() : 0); + if(PPROT_o.get_interface()) + PPROT_o.write(ext ? ext->get_protection() : false); if(PNSE_o.get_interface()) PNSE_o.write(ext ? ext->is_nse() : false); wait(PCLK_i.posedge_event()); SCCDEBUG(SCMOD) << "APB setup phase finished, sending end req for access to addr 0x" << std::hex << trans->get_address(); tlm::tlm_phase phase{tlm::END_REQ}; sc_core::sc_time delay; - auto res = tsckt->nb_transport_bw(*trans, phase, delay); + tsckt->nb_transport_bw(*trans, phase, delay); SCCDEBUG(SCMOD) << "Starting APB access phase"; PENABLE_o.write(true); - wait(1_ps); while(!PREADY_i.read()) wait(PREADY_i.value_changed_event()); wait(PCLK_i.posedge_event()); @@ -157,10 +164,12 @@ template inline void initiatorget_address(); - res = tsckt->nb_transport_bw(*trans, phase, delay); + tsckt->nb_transport_bw(*trans, phase, delay); SCCDEBUG(SCMOD) << "APB access phase finished"; PENABLE_o.write(false); PSELx_o.write(false); + if(trans->has_mm()) + trans->release(); } } } diff --git a/src/interfaces/apb/pin/target.h b/src/interfaces/apb/pin/target.h index 68cebb59..969d26de 100644 --- a/src/interfaces/apb/pin/target.h +++ b/src/interfaces/apb/pin/target.h @@ -101,10 +101,7 @@ target::target(const sc_core::sc_module_name& nm) template target::~target() = default; template void target::bus_task() { - auto const width_exp = scc::ilog2(DATA_WIDTH / 8); wait(sc_core::SC_ZERO_TIME); - auto& psel = PSELx_i.read(); - auto& penable = PENABLE_i.read(); wait(PCLK_i.posedge_event()); while(true) { if(!PRESETn_i.read()) { @@ -112,77 +109,72 @@ template void target::get().allocate(length); - trans->acquire(); - trans->set_streaming_width(length); - trans->set_address(PADDR_i.read()); - auto* ext = trans->get_extension(); - if(PPROT_i.get_interface()) - ext->set_protection(PPROT_i.read().to_uint()); - if(PNSE_i.get_interface()) - ext->set_nse(PNSE_i.read()); - auto start_offs = trans->get_address() & (length - 1); - if(PWRITE_i.read()) { - trans->set_write(); - auto data = PWDATA_i.read(); - if(PSTRB_i.get_interface()) { - auto strb = PSTRB_i.read(); - auto dptr_begin = std::numeric_limits::max(); - auto dptr_end = 0; - for(size_t j = 0; j < DATA_WIDTH / 8; ++j) { - if(strb[j]) { - if(j < dptr_begin) - dptr_begin = j; - *(trans->get_data_ptr() + dptr_end) = data(8 * j + 7, 8 * j).to_uint(); - dptr_end++; - } - } - trans->set_address((trans->get_address() & ~(DATA_WIDTH / 8 - 1)) + dptr_begin); - trans->set_data_length(dptr_end); - } else - for(size_t j = 0; j < DATA_WIDTH / 8; ++j) - *(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint(); + wait(sc_core::SC_ZERO_TIME); + while(!PSELx_i.read()) + wait(PSELx_i.value_changed_event()); + SCCDEBUG(SCMOD) << "Starting APB setup phase"; + unsigned length = DATA_WIDTH / 8; + auto trans = tlm::scc::tlm_mm<>::get().allocate(length); + tlm::scc::tlm_gp_mm::add_data_ptr(length, trans, true); + trans->acquire(); + trans->set_streaming_width(length); + trans->set_address(PADDR_i.read()); + auto* ext = trans->get_extension(); + if(PPROT_i.get_interface()) + ext->set_protection(PPROT_i.read().to_uint()); + if(PNSE_i.get_interface()) + ext->set_nse(PNSE_i.read()); + if(PWRITE_i.read()) { + trans->set_write(); + auto data = PWDATA_i.read(); + if(PSTRB_i.get_interface()) { + auto strb = PSTRB_i.read(); + // Copy all data bytes and use byte enables for sparse strobes + for(size_t j = 0; j < DATA_WIDTH / 8; ++j) { + *(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint(); + *(trans->get_byte_enable_ptr() + j) = strb[j] ? 0xFF : 0x00; + } + trans->set_byte_enable_length(DATA_WIDTH / 8); } else { - trans->set_read(); - } - sc_core::sc_time delay; - tlm::tlm_phase phase{tlm::BEGIN_REQ}; - SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address(); - auto res = isckt->nb_transport_fw(*trans, phase, delay); - if(res == tlm::TLM_ACCEPTED) { - waiting4end_req = true; - wait(end_req_evt); - phase = tlm::END_REQ; - } - SCCDEBUG(SCMOD) << "Recv end req for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex - << trans->get_address(); - SCCDEBUG(SCMOD) << "APB setup phase, finished"; - wait(PENABLE_i.posedge_event()); - if(phase != tlm::BEGIN_RESP) { - auto resp = wait4tx(resp_que); - sc_assert(trans == resp); - } - SCCDEBUG(SCMOD) << "Recv beg resp for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex - << trans->get_address() << ", starting access phase"; - delay = sc_core::SC_ZERO_TIME; - phase = tlm::END_RESP; - res = isckt->nb_transport_fw(*trans, phase, delay); - if(trans->is_read()) { - data_t data{0}; for(size_t j = 0; j < DATA_WIDTH / 8; ++j) - data.range(j * 8 + 7, j * 8) = *(trans->get_data_ptr() + j); - PRDATA_o.write(data); + *(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint(); + trans->set_byte_enable_length(0); } - PREADY_o.write(true); - PSLVERR_o.write(trans->get_response_status() != tlm::TLM_OK_RESPONSE); - wait(PCLK_i.posedge_event()); - SCCDEBUG(SCMOD) << "APB access phase finished"; + } else { + trans->set_read(); + } + sc_core::sc_time delay; + tlm::tlm_phase phase{tlm::BEGIN_REQ}; + SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address(); + auto res = isckt->nb_transport_fw(*trans, phase, delay); + if(res == tlm::TLM_ACCEPTED) { + waiting4end_req = true; + wait(end_req_evt); + phase = tlm::END_REQ; } + SCCDEBUG(SCMOD) << "Recv end req for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex + << trans->get_address(); + SCCDEBUG(SCMOD) << "APB setup phase, finished"; + wait(PENABLE_i.posedge_event()); + if(phase != tlm::BEGIN_RESP) { + auto resp = wait4tx(resp_que); + sc_assert(trans == resp); + } + SCCDEBUG(SCMOD) << "Recv beg resp for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex + << trans->get_address() << ", starting access phase"; + delay = sc_core::SC_ZERO_TIME; + phase = tlm::END_RESP; + isckt->nb_transport_fw(*trans, phase, delay); + if(trans->is_read()) { + data_t data{0}; + for(size_t j = 0; j < DATA_WIDTH / 8; ++j) + data.range(j * 8 + 7, j * 8) = *(trans->get_data_ptr() + j); + PRDATA_o.write(data); + } + PREADY_o.write(true); + PSLVERR_o.write(trans->get_response_status() != tlm::TLM_OK_RESPONSE); + wait(PCLK_i.posedge_event()); + SCCDEBUG(SCMOD) << "APB access phase finished"; } } }