17 #ifndef _BUS_APB_PIN_TARGET_H_
18 #define _BUS_APB_PIN_TARGET_H_
20 #include <interfaces/apb/apb_tlm.h>
22 #include <scc/report.h>
23 #include <scc/signal_opt_ports.h>
24 #include <scc/utilities.h>
25 #include <tlm/scc/initiator_mixin.h>
26 #include <tlm/scc/tlm_mm.h>
28 #include <tlm_utils/peq_with_get.h>
35 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
class target : sc_core::sc_module {
36 static constexpr
bool is_larger(
unsigned x) {
return x > 64U; }
39 using addr_t =
typename std::conditional<is_larger(ADDR_WIDTH), sc_dt::sc_biguint<ADDR_WIDTH>, sc_dt::sc_uint<ADDR_WIDTH>>::type;
40 using data_t =
typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
41 using strb_t = sc_dt::sc_uint<DATA_WIDTH / 8>;
43 sc_core::sc_in<bool> PCLK_i{
"PCLK_i"};
44 sc_core::sc_in<bool> PRESETn_i{
"PRESETn_i"};
45 sc_core::sc_in<addr_t> PADDR_i{
"PADDR_i"};
48 sc_core::sc_in<bool> PSELx_i{
"PSELx_i"};
49 sc_core::sc_in<bool> PENABLE_i{
"PENABLE_i"};
50 sc_core::sc_in<bool> PWRITE_i{
"PWRITE_i"};
51 sc_core::sc_in<data_t> PWDATA_i{
"PWDATA_i"};
53 sc_core::sc_out<bool> PREADY_o{
"PREADY_o"};
54 sc_core::sc_out<data_t> PRDATA_o{
"PRDATA_o"};
55 sc_core::sc_out<bool> PSLVERR_o{
"PSLVERR_o"};
60 target(
const sc_core::sc_module_name& nm);
65 static tlm::tlm_generic_payload* wait4tx(tlm_utils::peq_with_get<tlm::tlm_generic_payload>& que) {
66 tlm::tlm_generic_payload* ret = que.get_next_transaction();
68 ::sc_core::wait(que.get_event());
69 ret = que.get_next_transaction();
73 sc_core::sc_event end_req_evt;
74 tlm_utils::peq_with_get<tlm::tlm_generic_payload> resp_que{
"resp_que"};
75 bool waiting4end_req{
false};
81 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
86 isckt.
register_nb_transport_bw([
this](tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) {
87 if(phase == tlm::END_REQ) {
88 end_req_evt.notify(delay);
89 waiting4end_req =
false;
90 }
else if(phase == tlm::BEGIN_RESP) {
92 end_req_evt.notify(delay);
93 waiting4end_req =
false;
95 resp_que.notify(trans, delay);
97 return tlm::TLM_ACCEPTED;
101 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH> target<DATA_WIDTH, ADDR_WIDTH>::~target() =
default;
103 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
void target<DATA_WIDTH, ADDR_WIDTH>::bus_task() {
104 auto const width_exp = scc::ilog2(DATA_WIDTH / 8);
105 wait(sc_core::SC_ZERO_TIME);
106 auto& psel = PSELx_i.read();
107 auto& penable = PENABLE_i.read();
108 wait(PCLK_i.posedge_event());
110 if(!PRESETn_i.read()) {
111 wait(PRESETn_i.posedge_event());
112 wait(PCLK_i.posedge_event());
114 PREADY_o.write(
false);
117 PREADY_o.write(
false);
118 SCCDEBUG(SCMOD) <<
"Starting APB setup phase";
119 unsigned length = DATA_WIDTH / 8;
122 trans->set_streaming_width(length);
123 trans->set_address(PADDR_i.read());
124 auto* ext = trans->get_extension<apb_extension>();
125 if(PPROT_i.get_interface())
126 ext->set_protection(PPROT_i.read().to_uint());
127 if(PNSE_i.get_interface())
128 ext->set_nse(PNSE_i.read());
129 auto start_offs = trans->get_address() & (length - 1);
130 if(PWRITE_i.read()) {
132 auto data = PWDATA_i.read();
133 if(PSTRB_i.get_interface()) {
134 auto strb = PSTRB_i.read();
135 auto dptr_begin = std::numeric_limits<unsigned>::max();
137 for(
size_t j = 0; j < DATA_WIDTH / 8; ++j) {
141 *(trans->get_data_ptr() + dptr_end) = data(8 * j + 7, 8 * j).to_uint();
145 trans->set_address((trans->get_address() & ~(DATA_WIDTH / 8 - 1)) + dptr_begin);
146 trans->set_data_length(dptr_end);
148 for(
size_t j = 0; j < DATA_WIDTH / 8; ++j)
149 *(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint();
153 sc_core::sc_time delay;
154 tlm::tlm_phase phase{tlm::BEGIN_REQ};
155 SCCDEBUG(SCMOD) <<
"Recv beg req for read to addr 0x" << std::hex << trans->get_address();
156 auto res = isckt->nb_transport_fw(*trans, phase, delay);
157 if(res == tlm::TLM_ACCEPTED) {
158 waiting4end_req =
true;
160 phase = tlm::END_REQ;
162 SCCDEBUG(SCMOD) <<
"Recv end req for " << (trans->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
163 << trans->get_address();
164 SCCDEBUG(SCMOD) <<
"APB setup phase, finished";
165 wait(PENABLE_i.posedge_event());
166 if(phase != tlm::BEGIN_RESP) {
167 auto resp = wait4tx(resp_que);
168 sc_assert(trans == resp);
170 SCCDEBUG(SCMOD) <<
"Recv beg resp for " << (trans->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
171 << trans->get_address() <<
", starting access phase";
172 delay = sc_core::SC_ZERO_TIME;
173 phase = tlm::END_RESP;
174 res = isckt->nb_transport_fw(*trans, phase, delay);
175 if(trans->is_read()) {
177 for(
size_t j = 0; j < DATA_WIDTH / 8; ++j)
178 data.range(j * 8 + 7, j * 8) = *(trans->get_data_ptr() + j);
179 PRDATA_o.write(data);
181 PREADY_o.write(
true);
182 PSLVERR_o.write(trans->get_response_status() != tlm::TLM_OK_RESPONSE);
183 wait(PCLK_i.posedge_event());
184 SCCDEBUG(SCMOD) <<
"APB access phase finished";
void register_nb_transport_bw(std::function< sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb)
payload_type * allocate()
get a plain tlm_payload_type without extensions
TLM2.0 components modeling APB.
static tlm_mm & get()
accessor function of the singleton