Skip to content

Commit fa2f71a

Browse files
committed
fix apb pin level adapters
1. Handle strobe signals correctly 2. Free the payload after usage to avoid deadlock 3. Remove redundant code
1 parent 1f99de5 commit fa2f71a

File tree

2 files changed

+91
-90
lines changed

2 files changed

+91
-90
lines changed

src/interfaces/apb/pin/initiator.h

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,13 @@ initiator<DATA_WIDTH, ADDR_WIDTH>::initiator(const sc_core::sc_module_name& nm)
8888
}
8989

9090
template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_WIDTH, ADDR_WIDTH>::bus_task() {
91-
auto& hready = PREADY_i.read();
9291
while(true) {
9392
wait(inqueue.get_event());
9493
while(auto trans = inqueue.get_next_transaction()) {
9594
auto addr_offset = trans->get_address() & (DATA_WIDTH / 8 - 1);
9695
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;
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;
9998
tlm::tlm_phase phase{tlm::END_RESP};
10099
sc_core::sc_time delay;
101100
trans->set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
@@ -108,43 +107,51 @@ template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_W
108107
tsckt->nb_transport_bw(*trans, phase, delay);
109108
} else {
110109
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);
113-
size_t size = 0;
114-
for(; size < bytes_exp; ++size)
115-
if(trans->get_address() & (1 << size))
116-
break; // i contains the first bit not being 0
117110
auto* ext = trans->template get_extension<apb_extension>();
118111
if(trans->is_write()) {
119-
if(upper <= DATA_WIDTH / 8) {
120-
data_t data{0};
121-
strb_t strb{0};
112+
data_t data{0};
113+
strb_t strb{0};
114+
// Handle TLM byte enables if present
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);
121+
strb[i] = 1;
122+
}
123+
}
124+
}
125+
} else {
126+
// No byte enables, write contiguous data
122127
for(size_t i = 0; i < upper; ++i) {
123128
if(i >= addr_offset) {
124129
data.range(i * 8 + 7, i * 8) = *(trans->get_data_ptr() + i - addr_offset);
125130
strb[i] = 1;
126131
}
127132
}
128-
PWDATA_o.write(data);
129-
if(PSTRB_o.get_interface())
130-
PSTRB_o.write(strb);
131133
}
134+
PWDATA_o.write(data);
135+
if(PSTRB_o.get_interface())
136+
PSTRB_o.write(strb);
137+
} else if(PSTRB_o.get_interface()) {
138+
// From spec : For read transfers the bus master must drive all bits of PSTRB LOW
139+
PSTRB_o.write(0);
132140
}
133141
PWRITE_o.write(trans->is_write());
134142
PADDR_o.write(trans->get_address() - addr_offset); // adjust address to be aligned
135143
PSELx_o.write(true);
136-
if(PPROT_o.get_interface() && ext)
137-
PPROT_o.write(ext ? ext->get_protection() : 0);
144+
if(PPROT_o.get_interface())
145+
PPROT_o.write(ext ? ext->get_protection() : false);
138146
if(PNSE_o.get_interface())
139147
PNSE_o.write(ext ? ext->is_nse() : false);
140148
wait(PCLK_i.posedge_event());
141149
SCCDEBUG(SCMOD) << "APB setup phase finished, sending end req for access to addr 0x" << std::hex << trans->get_address();
142150
tlm::tlm_phase phase{tlm::END_REQ};
143151
sc_core::sc_time delay;
144-
auto res = tsckt->nb_transport_bw(*trans, phase, delay);
152+
tsckt->nb_transport_bw(*trans, phase, delay);
145153
SCCDEBUG(SCMOD) << "Starting APB access phase";
146154
PENABLE_o.write(true);
147-
wait(1_ps);
148155
while(!PREADY_i.read())
149156
wait(PREADY_i.value_changed_event());
150157
wait(PCLK_i.posedge_event());
@@ -157,10 +164,12 @@ template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_W
157164
phase = tlm::BEGIN_RESP;
158165
delay = sc_core::SC_ZERO_TIME;
159166
SCCDEBUG(SCMOD) << "Sending beg resp for access to addr 0x" << std::hex << trans->get_address();
160-
res = tsckt->nb_transport_bw(*trans, phase, delay);
167+
tsckt->nb_transport_bw(*trans, phase, delay);
161168
SCCDEBUG(SCMOD) << "APB access phase finished";
162169
PENABLE_o.write(false);
163170
PSELx_o.write(false);
171+
if(trans->has_mm())
172+
trans->release();
164173
}
165174
}
166175
}

src/interfaces/apb/pin/target.h

Lines changed: 62 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -101,88 +101,80 @@ target<DATA_WIDTH, ADDR_WIDTH>::target(const sc_core::sc_module_name& nm)
101101
template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> target<DATA_WIDTH, ADDR_WIDTH>::~target() = default;
102102

103103
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);
105104
wait(sc_core::SC_ZERO_TIME);
106-
auto& psel = PSELx_i.read();
107-
auto& penable = PENABLE_i.read();
108105
wait(PCLK_i.posedge_event());
109106
while(true) {
110107
if(!PRESETn_i.read()) {
111108
wait(PRESETn_i.posedge_event());
112109
wait(PCLK_i.posedge_event());
113110
} else {
114111
PREADY_o.write(false);
115-
wait(1_ps);
116-
if(psel) { // HTRANS/BUSY or IDLE check
117-
PREADY_o.write(false);
118-
SCCDEBUG(SCMOD) << "Starting APB setup phase";
119-
unsigned length = DATA_WIDTH / 8;
120-
auto trans = tlm::scc::tlm_mm<>::get().allocate<apb::apb_extension>(length);
121-
trans->acquire();
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()) {
131-
trans->set_write();
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();
136-
auto dptr_end = 0;
137-
for(size_t j = 0; j < DATA_WIDTH / 8; ++j) {
138-
if(strb[j]) {
139-
if(j < dptr_begin)
140-
dptr_begin = j;
141-
*(trans->get_data_ptr() + dptr_end) = data(8 * j + 7, 8 * j).to_uint();
142-
dptr_end++;
143-
}
144-
}
145-
trans->set_address((trans->get_address() & ~(DATA_WIDTH / 8 - 1)) + dptr_begin);
146-
trans->set_data_length(dptr_end);
147-
} else
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();
112+
wait(sc_core::SC_ZERO_TIME);
113+
while(!PSELx_i.read())
114+
wait(PSELx_i.value_changed_event());
115+
SCCDEBUG(SCMOD) << "Starting APB setup phase";
116+
unsigned length = DATA_WIDTH / 8;
117+
auto trans = tlm::scc::tlm_mm<>::get().allocate<apb::apb_extension>(length);
118+
tlm::scc::tlm_gp_mm::add_data_ptr(length, trans, true);
119+
trans->acquire();
120+
trans->set_streaming_width(length);
121+
trans->set_address(PADDR_i.read());
122+
auto* ext = trans->get_extension<apb_extension>();
123+
if(PPROT_i.get_interface())
124+
ext->set_protection(PPROT_i.read().to_uint());
125+
if(PNSE_i.get_interface())
126+
ext->set_nse(PNSE_i.read());
127+
if(PWRITE_i.read()) {
128+
trans->set_write();
129+
auto data = PWDATA_i.read();
130+
if(PSTRB_i.get_interface()) {
131+
auto strb = PSTRB_i.read();
132+
// Copy all data bytes and use byte enables for sparse strobes
133+
for(size_t j = 0; j < DATA_WIDTH / 8; ++j) {
134+
*(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint();
135+
*(trans->get_byte_enable_ptr() + j) = strb[j] ? 0xFF : 0x00;
136+
}
137+
trans->set_byte_enable_length(DATA_WIDTH / 8);
150138
} else {
151-
trans->set_read();
152-
}
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;
159-
wait(end_req_evt);
160-
phase = tlm::END_REQ;
161-
}
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);
169-
}
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()) {
176-
data_t data{0};
177139
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);
140+
*(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint();
141+
trans->set_byte_enable_length(0);
180142
}
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";
143+
} else {
144+
trans->set_read();
145+
}
146+
sc_core::sc_time delay;
147+
tlm::tlm_phase phase{tlm::BEGIN_REQ};
148+
SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address();
149+
auto res = isckt->nb_transport_fw(*trans, phase, delay);
150+
if(res == tlm::TLM_ACCEPTED) {
151+
waiting4end_req = true;
152+
wait(end_req_evt);
153+
phase = tlm::END_REQ;
185154
}
155+
SCCDEBUG(SCMOD) << "Recv end req for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
156+
<< trans->get_address();
157+
SCCDEBUG(SCMOD) << "APB setup phase, finished";
158+
wait(PENABLE_i.posedge_event());
159+
if(phase != tlm::BEGIN_RESP) {
160+
auto resp = wait4tx(resp_que);
161+
sc_assert(trans == resp);
162+
}
163+
SCCDEBUG(SCMOD) << "Recv beg resp for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
164+
<< trans->get_address() << ", starting access phase";
165+
delay = sc_core::SC_ZERO_TIME;
166+
phase = tlm::END_RESP;
167+
isckt->nb_transport_fw(*trans, phase, delay);
168+
if(trans->is_read()) {
169+
data_t data{0};
170+
for(size_t j = 0; j < DATA_WIDTH / 8; ++j)
171+
data.range(j * 8 + 7, j * 8) = *(trans->get_data_ptr() + j);
172+
PRDATA_o.write(data);
173+
}
174+
PREADY_o.write(true);
175+
PSLVERR_o.write(trans->get_response_status() != tlm::TLM_OK_RESPONSE);
176+
wait(PCLK_i.posedge_event());
177+
SCCDEBUG(SCMOD) << "APB access phase finished";
186178
}
187179
}
188180
}

0 commit comments

Comments
 (0)