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.