17 #ifndef _BUS_AHB_PIN_TARGET_H_
18 #define _BUS_AHB_PIN_TARGET_H_
20 #include <interfaces/ahb/ahb_tlm.h>
22 #include <scc/report.h>
23 #include <scc/utilities.h>
24 #include <tlm/scc/initiator_mixin.h>
25 #include <tlm/scc/tlm_mm.h>
27 #include <tlm_utils/peq_with_get.h>
34 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
class target : sc_core::sc_module {
35 static constexpr
bool is_larger(
unsigned x) {
return x > 64U; }
36 using addr_t =
typename std::conditional<is_larger(ADDR_WIDTH), sc_dt::sc_biguint<ADDR_WIDTH>, sc_dt::sc_uint<ADDR_WIDTH>>::type;
37 using data_t =
typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
40 sc_core::sc_in<bool> HCLK_i{
"HCLK_i"};
41 sc_core::sc_in<bool> HRESETn_i{
"HRESETn_i"};
42 sc_core::sc_in<addr_t> HADDR_i{
"HADDR_i"};
43 sc_core::sc_in<sc_dt::sc_uint<3>> HBURST_i{
"HBURST_i"};
44 sc_core::sc_in<bool> HMASTLOCK_i{
"HMASTLOCK_i"};
45 sc_core::sc_in<sc_dt::sc_uint<4>> HPROT_i{
"HPROT_i"};
46 sc_core::sc_in<sc_dt::sc_uint<3>> HSIZE_i{
"HSIZE_i"};
47 sc_core::sc_in<sc_dt::sc_uint<2>> HTRANS_i{
"HTRANS_i"};
48 sc_core::sc_in<data_t> HWDATA_i{
"HWDATA_i"};
49 sc_core::sc_in<bool> HWRITE_i{
"HWRITE_i"};
50 sc_core::sc_in<bool> HSEL_i{
"HSEL_i"};
51 sc_core::sc_out<data_t> HRDATA_o{
"HRDATA_o"};
52 sc_core::sc_out<bool> HREADY_o{
"HREADY_o"};
53 sc_core::sc_out<bool> HRESP_o{
"HRESP_o"};
57 target(
const sc_core::sc_module_name& nm);
63 static tlm::tlm_generic_payload* wait4tx(tlm_utils::peq_with_get<tlm::tlm_generic_payload>& que) {
64 tlm::tlm_generic_payload* ret = que.get_next_transaction();
66 ::sc_core::wait(que.get_event());
67 ret = que.get_next_transaction();
71 sc_core::sc_event end_req_evt;
72 tlm_utils::peq_with_get<tlm::tlm_generic_payload> resp_que{
"resp_que"};
73 tlm_utils::peq_with_get<tlm::tlm_generic_payload> tx_in_flight{
"tx_in_flight"};
74 bool waiting4end_req{
false};
80 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
84 SC_THREAD(bus_addr_task);
85 SC_THREAD(bus_data_task);
86 isckt.
register_nb_transport_bw([
this](tlm::tlm_generic_payload& gp, 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(gp, 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_addr_task() {
104 auto const width_exp = scc::ilog2(DATA_WIDTH / 8);
105 wait(sc_core::SC_ZERO_TIME);
106 auto& htrans = HTRANS_i.read();
107 auto& hsel = HSEL_i.read();
108 auto& hready = HREADY_o.read();
109 auto& size = HSIZE_i.read();
111 if(!HRESETn_i.read()) {
112 wait(HRESETn_i.posedge_event());
114 wait(HCLK_i.posedge_event());
115 if(hsel && hready && htrans > 1) {
118 SCCERR(SCMOD) <<
"Access size (" << sz <<
") is larger than bus wDWIDTH(" << width_exp <<
")!";
119 unsigned length = (1 << sz);
122 gp->set_streaming_width(length);
123 gp->set_address(HADDR_i.read());
124 auto* ext = gp->get_extension<ahb_extension>();
125 ext->set_locked(HMASTLOCK_i.read());
126 ext->set_protection(HPROT_i.read());
127 ext->set_seq(htrans == 3);
128 ext->set_burst(
static_cast<ahb::burst_e
>(HBURST_i.read().to_uint()));
129 if(HWRITE_i.read()) {
134 tx_in_flight.notify(*gp);
140 template <
unsigned DATA_WIDTH,
unsigned ADDR_WIDTH>
void target<DATA_WIDTH, ADDR_WIDTH>::bus_data_task() {
141 auto const width = DATA_WIDTH / 8;
142 auto& wdata = HWDATA_i.read();
143 wait(sc_core::SC_ZERO_TIME);
145 if(!HRESETn_i.read()) {
146 HREADY_o.write(
false);
147 wait(HRESETn_i.posedge_event());
149 HREADY_o.write(
true);
150 auto gp = wait4tx(tx_in_flight);
151 auto ext = gp->template get_extension<ahb::ahb_extension>();
152 auto start_offs = gp->get_address() & (width - 1);
153 sc_assert((start_offs + gp->get_data_length()) <= width);
154 auto len = gp->get_data_length();
155 HREADY_o.write(
false);
157 wait(HCLK_i.negedge_event());
158 for(
size_t i = start_offs * 8, j = 0; i < DATA_WIDTH; i += 8, ++j)
159 *(uint8_t*)(gp->get_data_ptr() + j) = wdata.range(i + 7, i).to_uint();
161 SCCDEBUG(SCMOD) <<
"Send beg req for " << (gp->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
162 << gp->get_address();
163 sc_core::sc_time delay;
164 tlm::tlm_phase phase{tlm::BEGIN_REQ};
165 auto res = isckt->nb_transport_fw(*gp, phase, delay);
166 if(res == tlm::TLM_ACCEPTED) {
167 waiting4end_req =
true;
169 phase = tlm::END_REQ;
171 SCCDEBUG(SCMOD) <<
"Recv end req for " << (gp->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
172 << gp->get_address();
173 if(phase != tlm::BEGIN_RESP) {
174 auto resp = wait4tx(resp_que);
175 sc_assert(gp == resp);
177 SCCDEBUG(SCMOD) <<
"Recv beg resp for " << (gp->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
178 << gp->get_address();
181 for(
size_t i = start_offs * 8, j = 0; j < len; i += 8, ++j)
182 data.range(i + 7, i) = *(uint8_t*)(gp->get_data_ptr() + j);
183 HRDATA_o.write(data);
185 delay = sc_core::SC_ZERO_TIME;
186 phase = tlm::END_RESP;
187 SCCDEBUG(SCMOD) <<
"Send end resp for " << (gp->is_write() ?
"write to" :
"read from") <<
" addr 0x" << std::hex
188 << gp->get_address();
189 res = isckt->nb_transport_fw(*gp, phase, delay);
191 HREADY_o.write(
true);
192 wait(HCLK_i.posedge_event());
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 AHB.
static tlm_mm & get()
accessor function of the singleton