36template <
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);
62 virtual ~initiator() =
default;
67 tlm_utils::peq_with_get<tlm::tlm_generic_payload> inqueue{
"inqueue"};
73template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
74initiator<DATA_WIDTH, ADDR_WIDTH>::initiator(
const sc_core::sc_module_name& nm)
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;
90template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
inline void initiator<DATA_WIDTH, ADDR_WIDTH>::bus_task() {
92 wait(inqueue.get_event());
93 while(
auto trans = inqueue.get_next_transaction()) {
94 auto addr_offset = trans->get_address() & (DATA_WIDTH / 8 - 1);
95 auto upper = addr_offset + trans->get_data_length();
96 if(!PSTRB_o.get_interface() && (addr_offset || upper != (DATA_WIDTH / 8))) {
97 SCCERR(SCMOD) <<
"Narrow accesses are not supported before APB4 as there is no PSTRB signal! Skipping " << *trans;
98 tlm::tlm_phase phase{tlm::END_RESP};
99 sc_core::sc_time delay;
100 trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
101 tsckt->nb_transport_bw(*trans, phase, delay);
102 }
else if(upper > DATA_WIDTH / 8) {
103 SCCERR(SCMOD) <<
"Illegal length of payload since it would cause a wrap-around! Skipping " << *trans;
104 tlm::tlm_phase phase{tlm::END_RESP};
105 sc_core::sc_time delay;
106 trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
107 tsckt->nb_transport_bw(*trans, phase, delay);
109 SCCDEBUG(SCMOD) <<
"Recv beg req for read to addr 0x" << std::hex << trans->get_address() <<
", starting APB setup phase, ";
110 auto* ext = trans->template get_extension<apb_extension>();
111 if(trans->is_write()) {
115 if(trans->get_byte_enable_ptr() && trans->get_byte_enable_length() > 0) {
116 for(
size_t i = 0; i < DATA_WIDTH / 8; ++i) {
117 if(i >= addr_offset && i < upper) {
118 auto be_idx = (i - addr_offset) % trans->get_byte_enable_length();
119 if(trans->get_byte_enable_ptr()[be_idx] != 0) {
120 data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset);
127 for(
size_t i = 0; i < upper; ++i) {
128 if(i >= addr_offset) {
129 data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset);
134 PWDATA_o.write(data);
135 if(PSTRB_o.get_interface())
137 }
else if(PSTRB_o.get_interface()) {
141 PWRITE_o.write(trans->is_write());
142 PADDR_o.write(trans->get_address() - addr_offset);
144 if(PPROT_o.get_interface())
145 PPROT_o.write(ext ? ext->get_protection() :
false);
146 if(PNSE_o.get_interface())
147 PNSE_o.write(ext ? ext->is_nse() :
false);
148 wait(PCLK_i.posedge_event());
149 SCCDEBUG(SCMOD) <<
"APB setup phase finished, sending end req for access to addr 0x" << std::hex << trans->get_address();
150 tlm::tlm_phase phase{tlm::END_REQ};
151 sc_core::sc_time delay;
152 tsckt->nb_transport_bw(*trans, phase, delay);
153 SCCDEBUG(SCMOD) <<
"Starting APB access phase";
154 PENABLE_o.write(
true);
155 while(!PREADY_i.read())
156 wait(PREADY_i.value_changed_event());
157 wait(PCLK_i.posedge_event());
158 if(trans->is_read()) {
159 auto data = PRDATA_i.read();
160 for(
size_t j = addr_offset, i = 0; i < trans->get_data_length(); ++j, ++i)
161 *(trans->get_data_ptr() + i) = data(8 * j + 7, 8 * j).to_uint();
163 trans->set_response_status(PSLVERR_i.read() ? tlm::TLM_GENERIC_ERROR_RESPONSE : tlm::TLM_OK_RESPONSE);
164 phase = tlm::BEGIN_RESP;
165 delay = sc_core::SC_ZERO_TIME;
166 SCCDEBUG(SCMOD) <<
"Sending beg resp for access to addr 0x" << std::hex << trans->get_address();
167 tsckt->nb_transport_bw(*trans, phase, delay);
168 SCCDEBUG(SCMOD) <<
"APB access phase finished";
169 PENABLE_o.write(
false);
170 PSELx_o.write(
false);