Skip to content

Conversation

@JingJerYen
Copy link

I initially added an example for APB, but later found that the test didn’t work correctly due to several bugs. So I rewrote it to fix those issues.

Fix details:

  1. Strobe signals were not handled properly — only consecutive 0xFF values were considered, but the APB spec does not guarantee they are contiguous.

  2. A deadlock occurred due to a missing generic payload free.

  3. Removed unused variables, redundant code, and replaced wait(1_ps) with wait(SC_ZERO_TIME).

The waveform below shows the correct behavior after applying this patch.

apb

1. Handle strobe signals correctly
2. Free the payload after usage to avoid deadlock
3. Remove redundant code
@eyck
Copy link
Contributor

eyck commented Oct 16, 2025

@JingJerYen THX for the PR. I need to review the code in more detail as these are significant changes. Did you run it with a verilated design? Or coupled with a Verilog simulator?

@eyck eyck self-requested a review October 16, 2025 05:07
@eyck eyck self-assigned this Oct 16, 2025
PENABLE_o.write(false);
PSELx_o.write(false);
if(trans->has_mm())
trans->release();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line fixes the deadlock when running examples/apb

@JingJerYen
Copy link
Author

For this PR, I didn't run it with any RTL-level design. I just added the examples and found they didn't work, so I tried to fix the pin-level adapters. And the waveform was produced by examples/apb.

I can add some comments on the code to explain some parts of the commit

}

template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_WIDTH, ADDR_WIDTH>::bus_task() {
auto& hready = PREADY_i.read();
Copy link
Author

@JingJerYen JingJerYen Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the unused variable

auto upper = addr_offset + trans->get_data_length();
if(!PSTRB_o.get_interface() && addr_offset && upper != (DATA_WIDTH / 8)) {
SCCERR(SCMOD) << "Narrow accesses are not supported as there is no PSTRB signal! Skipping " << *trans;
if(!PSTRB_o.get_interface() && (addr_offset || upper != (DATA_WIDTH / 8))) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I know, both start address and size should align with bus data width before APB4 where strobe signal hasn't been introduced, so I changed this line. Correct me if i'm wrong.

tsckt->nb_transport_bw(*trans, phase, delay);
} else {
SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address() << ", starting APB setup phase, ";
auto bytes_exp = scc::ilog2(trans->get_data_length());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are dead code, so i removed them

data_t data{0};
strb_t strb{0};
// Handle TLM byte enables if present
if(trans->get_byte_enable_ptr() && trans->get_byte_enable_length() > 0) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this part to handle TLM payload with byte_enable array , this is not handled in the original code

if(PSTRB_o.get_interface())
PSTRB_o.write(strb);
} else if(PSTRB_o.get_interface()) {
// From spec : For read transfers the bus master must drive all bits of PSTRB LOW
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec states this

tsckt->nb_transport_bw(*trans, phase, delay);
SCCDEBUG(SCMOD) << "Starting APB access phase";
PENABLE_o.write(true);
wait(1_ps);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be useless ?

} else
for(size_t j = 0; j < DATA_WIDTH / 8; ++j)
*(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint();
wait(sc_core::SC_ZERO_TIME);
Copy link
Author

@JingJerYen JingJerYen Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation makes it look to be significant changes, but actually only few lines are changed. It waits for PSEL signals here. And i think wait( zero_time) is more elegant than wait(1_ps) for the log message ?

trans->set_read();
}
sc_core::sc_time delay;
tlm::tlm_phase phase{tlm::BEGIN_REQ};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the indentation changed.

@JingJerYen
Copy link
Author

螢幕擷取畫面 2025-10-17 165226 I've verified this patch using my company's Verilated CPU IP. The waveform is identical and correct before and after applying the patch, but the simulation speed is much slower before the patch when collecting waveform. I guess this is caused by the wait(1_ps) statement?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants