Skip to content

feat: add native axi_to_apb converter - #431

Open
fischeti wants to merge 1 commit into
develfrom
apb-converter
Open

feat: add native axi_to_apb converter#431
fischeti wants to merge 1 commit into
develfrom
apb-converter

Conversation

@fischeti

@fischeti fischeti commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

This PR adds a native axi_to_apb converter, which supports both downsizing datawidth and truncating the address.

Current situation

It is already possible now to convert from AXI to APB but multiple modules are needed like 1) axi_to_axi_lite ─▶ axi_lite_to_apb or 2) axi_to_reg ─▶ reg_to_apb. Both add intermediate protocol signals and generally make the code more verbose. Further, 2) uses a non-standard protocol and pulls in register_interface as a dependency.

Also, 1) has the disadvantage that it pulls in a axi_to_axi_lite which has relatively heavy burst splitter and other components, which is overkill to convert to APB. Further, neither axi_to_axi_lite nor axi_lite_to_apb allow to natively downsize the datawidth, hence a axi_lite_dw_converter is also needed.

Exploration

I prototyped three ways to bridge AXI4+ATOP to APB4 and compared area (post-synth, gate equivalents):

Approach Area
axi_to_axi_liteaxi_lite_dw_converteraxi_lite_to_apb chain 11.6 kGE
axi_to_detailed_mem + inline APB master (this PR) 9.3 kGE ✅ chosen
Native AXI→APB FSM 8.3 kGE

The AXI4-Lite chain was the heaviest: it drags in burst splitting, and a Lite data-width converter.

A fully native FSM was the smallest (~10% below the chosen option), but it was vibecoded so not proven logic, and code complexity is higher.

The chosen axi_to_detailed_mem + inline APB master sits in between: it reuses axi_to_detailed_mem the AXI conversion. It is ~20% smaller than the Lite chain.

Verification

The adapter is verified with a tb_axi_to_apb testbench, that checks the APB interface for protocol compliancy, as well as an AXI scoreboard to check for correct data. I also added different types of slaves (ideal, random) to simulate backpressure.

@fischeti
fischeti force-pushed the apb-converter branch 3 times, most recently from 5f66dd6 to 9e222cd Compare July 3, 2026 07:48
@fischeti
fischeti marked this pull request as ready for review July 3, 2026 07:50
@fischeti
fischeti requested review from imchenwu, micprog and nikgiu July 3, 2026 07:50
@imchenwu
imchenwu changed the base branch from master to devel July 8, 2026 08:25

@nikgiu nikgiu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

While reviewing this I tried bumping OutFifoDepth to 2 in the testbench to see how the module behaves with more buffering, and the simulation blew up: Questa hits a zero-delay combinational loop (Autofindloop at 350 ns, X propagation, then vsimk SIGSEGV / exit 211). The loop it reports runs through mem_gnt/mem_rvalid in this module and back through the axi_to_detailed_mem response path (stream_join → stream_fork_dynamic).

Digging into it, I think the root cause is that bank_sel (and therefore apb_sel_idx) is purely combinational. It's the lzc output over mem_req, and it drives paddr/psel/pwdata/mem_gnt/… directly. So mem_gnt/mem_rvalid depend combinationally on mem_req, and once OutFifoDepth > 1 the front-end closes that path into a combinational cycle. With OutFifoDepth == 1 it happens to be safe only because a full depth-1 bank FIFO blocks the next beat's enqueue, so mem_req can't change mid-transfer.

I also think the same root cause can break the APB protocol even without hitting the loop: since the selection isn't frozen for the duration of a transfer, a lower-index bank asserting between SETUP and ACCESS shifts bank_sel/apb_sel_idx mid-transfer → SETUP is driven to one slave and ACCESS (penable) to another, and paddr/pwdata change while a transaction is in flight.

My suggestion would be to latch the selection at the SETUP→ACCESS transition and drive the bus from the latched values during ACCESS. That keeps the APB signals stable by construction and breaks the mem_req → bank_sel → mem_gnt combinational path, regardless of OutFifoDepth

Comment thread test/tb_axi_to_apb.sv Outdated
@fischeti

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review @nikgiu! I will dig into the issue when I find some time again. I will draft it again, until I have fixed the issue.

@fischeti
fischeti marked this pull request as ready for review July 31, 2026 11:52
@fischeti

Copy link
Copy Markdown
Contributor Author

You were right with your analysis @nikgiu! And I think your proposed fix is indeed the simplest option. I pushed some changes and also rebased to devel now.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants