17 #ifndef _BUS_APB_PIN_INITIATOR_H_
18 #define _BUS_APB_PIN_INITIATOR_H_
20 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
21 #define SC_INCLUDE_DYNAMIC_PROCESSES
24 #include <interfaces/apb/apb_tlm.h>
25 #include <scc/report.h>
26 #include <scc/signal_opt_ports.h>
27 #include <scc/utilities.h>
28 #include <tlm/scc/target_mixin.h>
30 #include <tlm_utils/peq_with_get.h>
31 #include <type_traits>
36 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH = 32>
class initiator : sc_core::sc_module {
37 static constexpr
bool is_larger(
unsigned x) {
return x > 64U; }
40 using addr_t = sc_dt::sc_uint<ADDR_WIDTH>;
41 using data_t =
typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
42 using strb_t = sc_dt::sc_uint<DATA_WIDTH / 8>;
44 sc_core::sc_in<bool> PCLK_i{
"PCLK_i"};
45 sc_core::sc_in<bool> PRESETn_i{
"PRESETn_i"};
46 sc_core::sc_out<addr_t> PADDR_o{
"PADDR_o"};
49 sc_core::sc_out<bool> PSELx_o{
"PSELx_o"};
50 sc_core::sc_out<bool> PENABLE_o{
"PENABLE_o"};
51 sc_core::sc_out<bool> PWRITE_o{
"PWRITE_o"};
52 sc_core::sc_out<data_t> PWDATA_o{
"PWDATA_o"};
54 sc_core::sc_in<bool> PREADY_i{
"PREADY_i"};
55 sc_core::sc_in<data_t> PRDATA_i{
"PRDATA_i"};
56 sc_core::sc_in<bool> PSLVERR_i{
"PSLVERR_i"};
61 initiator(
const sc_core::sc_module_name& nm);
67 tlm_utils::peq_with_get<tlm::tlm_generic_payload> inqueue{
"inqueue"};
73 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
80 [
this](tlm::tlm_generic_payload& payload, tlm::tlm_phase& phase, sc_core::sc_time& delay) -> tlm::tlm_sync_enum {
81 if(phase == tlm::BEGIN_REQ) {
84 this->inqueue.notify(payload);
86 return tlm::TLM_ACCEPTED;
91 auto& hready = PREADY_i.read();
93 wait(inqueue.get_event());
94 while(
auto trans = inqueue.get_next_transaction()) {
95 auto addr_offset = trans->get_address() & (DATA_WIDTH / 8 - 1);
96 auto upper = addr_offset + trans->get_data_length();
97 if(!PSTRB_o.get_interface() && addr_offset && upper != (DATA_WIDTH / 8)) {
98 SCCERR(SCMOD) <<
"Narrow accesses are not supported as there is no PSTRB signal! Skipping " << *trans;
99 tlm::tlm_phase phase{tlm::END_RESP};
100 sc_core::sc_time delay;
101 trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
102 tsckt->nb_transport_bw(*trans, phase, delay);
103 }
else if(upper > DATA_WIDTH / 8) {
104 SCCERR(SCMOD) <<
"Illegal length of payload since it would cause a wrap-around! Skipping " << *trans;
105 tlm::tlm_phase phase{tlm::END_RESP};
106 sc_core::sc_time delay;
107 trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
108 tsckt->nb_transport_bw(*trans, phase, delay);
110 SCCDEBUG(SCMOD) <<
"Recv beg req for read to addr 0x" << std::hex << trans->get_address() <<
", starting APB setup phase, ";
111 auto bytes_exp = scc::ilog2(trans->get_data_length());
112 auto width_exp = scc::ilog2(DATA_WIDTH / 8);
114 for(; size < bytes_exp; ++size)
115 if(trans->get_address() & (1 << size))
117 auto* ext = trans->template get_extension<apb_extension>();
118 if(trans->is_write()) {
119 if(upper <= DATA_WIDTH / 8) {
122 for(
size_t i = 0; i < upper; ++i) {
123 if(i >= addr_offset) {
124 data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset);
128 PWDATA_o.write(data);
129 if(PSTRB_o.get_interface())
133 PWRITE_o.write(trans->is_write());
134 PADDR_o.write(trans->get_address() - addr_offset);
136 if(PPROT_o.get_interface() && ext)
137 PPROT_o.write(ext ? ext->get_protection() : 0);
138 if(PNSE_o.get_interface())
139 PNSE_o.write(ext ? ext->is_nse() :
false);
140 wait(PCLK_i.posedge_event());
141 SCCDEBUG(SCMOD) <<
"APB setup phase finished, sending end req for access to addr 0x" << std::hex << trans->get_address();
142 tlm::tlm_phase phase{tlm::END_REQ};
143 sc_core::sc_time delay;
144 auto res = tsckt->nb_transport_bw(*trans, phase, delay);
145 SCCDEBUG(SCMOD) <<
"Starting APB access phase";
146 PENABLE_o.write(
true);
148 while(!PREADY_i.read())
149 wait(PREADY_i.value_changed_event());
150 wait(PCLK_i.posedge_event());
151 if(trans->is_read()) {
152 auto data = PRDATA_i.read();
153 for(
size_t j = addr_offset, i = 0; i < trans->get_data_length(); ++j, ++i)
154 *(trans->get_data_ptr() + i) = data(8 * j + 7, 8 * j).to_uint();
156 trans->set_response_status(PSLVERR_i.read() ? tlm::TLM_GENERIC_ERROR_RESPONSE : tlm::TLM_OK_RESPONSE);
157 phase = tlm::BEGIN_RESP;
158 delay = sc_core::SC_ZERO_TIME;
159 SCCDEBUG(SCMOD) <<
"Sending beg resp for access to addr 0x" << std::hex << trans->get_address();
160 res = tsckt->nb_transport_bw(*trans, phase, delay);
161 SCCDEBUG(SCMOD) <<
"APB access phase finished";
162 PENABLE_o.write(
false);
163 PSELx_o.write(
false);
initiator ID recording TLM extension
void register_nb_transport_fw(std::function< sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb)
TLM2.0 components modeling APB.