Skip to content

[wishbone] burst mode: ACK is independent of STB requirement#232

Draft
ekiwi wants to merge 3 commits into
mainfrom
wishbone-burst-stb-non-det
Draft

[wishbone] burst mode: ACK is independent of STB requirement#232
ekiwi wants to merge 3 commits into
mainfrom
wishbone-burst-stb-non-det

Conversation

@ekiwi
Copy link
Copy Markdown
Collaborator

@ekiwi ekiwi commented Apr 30, 2026

Here is the section from the Wishbone spec:

OBSERVATION 4.00
To avoid the inherent wait state in synchronous termination schemes, the SERVER must generate the response as soon as possible (i.e. the next cycle). It can use the [CTI_I()] signals to determine the response for the next cycle. But it cannot determine the state of [STB_I] for the next cycle, therefore it must generate the response independent of [STB_I].

I have been trying to incorporate this rule into our protocol by setting STB to X while waiting for ACK to become high.

However, this triggers the following error in the interpreter:

> cargo interp  --transactions examples/wishbone/4.8_constant_address_burst.tx --verilog examples/wishbone/rtl/dut.v examples/wishbone/rtl/tb.v --module tb --protocol examples/wishbone/wishbone.prot 

error: Output 'self.ACK' depends on input(s) 'self.STB' which do not have assigned values
    ┌─ examples/wishbone/wishbone.prot:158:15
    │
158 │         while self.ACK == 1'b0 {
    │               ^^^^^^^^ Output 'self.ACK' depends on input(s) 'self.STB' which do not have assigned values
    ·
165 │             self.STB := X;
    │             ^^^^^^^^^^^^^^ 'self.STB' assigned DontCare here

Trace 0 execution failed.

So it seems like ACK in the RTL we have actually (sometimes) depends on STB.
Here is a simplified version of the expression that defines ACK:

OR(
  // if any of these are true, then there isn't really a dependency on STB
  eq(dut.count, 20'x00000),
  dut.basesoc_ram_bus_ack,
  dut.wishbone2csr_state,
  
  // this sub expression is directly dependent on STB and CYC
  AND(
    CYC,
    eq(ADR[29:0], 30'x34000000),
    STB,
    ite(WE,
       // write (check that fifo is not full)
       AND(
         eq(dut.testfifotransceiver_state, 2'b10)
         not(eq(dut.fifo_tx_level, 4'b1000))),
       // read (check that fifo is not empty)
       AND(
         eq(dut.testfifotransceiver_state, 2'b01)
         not(eq(dut.fifo_rx_level, 4'b0000)))
     )
   )
 )

Now the big question is: Who is to blame?

  • My interpretation of the wishbone spec?
  • Is our combinational dependency analysis too coarse?
  • Is the RTL wrong?

@ekiwi ekiwi marked this pull request as draft April 30, 2026 19:34
@ekiwi
Copy link
Copy Markdown
Collaborator Author

ekiwi commented Apr 30, 2026

This looks to be the block in the RTL that causes all of this:

https://github.com/antmicro/wishbone-interconnect-burst-mode-benchmark/blob/547fa0e9d7256059354559bbbe5d8b95272aab69/test/wrappers/fifo_transceiver.py#L32

self.comb += [
            bus_sel.eq(bus.cyc & bus.stb),
            If(bus_sel,
                If(bus.we, 
                    bus.ack.eq(wr_ack & bus.stb),
                ).Else(
                    bus.ack.eq(rd_ack & bus.stb),
                ),
            ).Else(
                bus.ack.eq(0)
            )
        ]

@ekiwi
Copy link
Copy Markdown
Collaborator Author

ekiwi commented Apr 30, 2026

I think that the additional guard with the bus_sel and the & bus.stb might be wrong when in burst mode. There is still a question around classic mode though.

@ekiwi
Copy link
Copy Markdown
Collaborator Author

ekiwi commented Apr 30, 2026

Unfortunately, the Wishbone spec does not feature any example waveform (in non-pipeline mode!) where ACK = 1 and STB = 0

@ekiwi
Copy link
Copy Markdown
Collaborator Author

ekiwi commented Apr 30, 2026

It might be time to language lawyer. Here are the relevant sections:

PERMISSION 4.15
In addition to the WISHBONE Classic rules for generating cycle termination signals [ACK_O], [RTY_O],
and [ERR_O], a SERVER MAY assert a termination cycle without checking the [STB_I] signal.

OBSERVATION 4.00
To avoid the inherent wait state in synchronous termination schemes, the SERVER must generate
the response as soon as possible (i.e. the next cycle).
It can use the [CTI_I()] signals to determine the response for the next cycle.
But it cannot determine the state of [STB_I] for the next cycle,
therefore it must generate the response independent of
[STB_I].

PERMISSION 4.20
[ACK_O], [RTY_O], and [ERR_O] MAY be asserted while [STB_O] is negated.

RULE 4.15
A cycle terminates when both the cycle termination signal and [STB_I], [STB_O] is asserted.
Even if [ACK_O], [ACK_I] is asserted, the other signals are only valid when [STB_O], [STB_I] is also asserted.

[...]

4.4.1 Classic Cycle
A Classic Cycle indicates that the current cycle is a WISHBONE Classic cycle.
The SERVER terminates the cycle as described in chapter 3.
There is no information about what the CLIENT will do the next cycle.

From the classic Wishbone section (non-burst):

RULE 3.35
In standard mode the cycle termination signals [ACK_O], [ERR_O], and [RTY_O]
must be generated in response to the logical AND of [CYC_I] and [STB_I]

RULE 3.50
SERVER interfaces MUST be designed so that the [ACK_O], [ERR_O], and [RTY_O] signals
are asserted and negated in response to the assertion and negation of [STB_I].

PERMISSION 3.30
The assertion of [ACK_O], [ERR_O], and [RTY_O] MAY be asynchronous to the [CLK_I]
signal (i.e. there is a combinatorial logic path between [STB_I] and [ACK_O]).

OBSERVATION 3.40
The asynchronous assertion of [ACK_O], [ERR_O], and [RTY_O] assures that the
interface can accomplish one data transfer per clock cycle. Furthermore, it simplifies the
design of arbiters in multi-CLIENT applications

To me this sounds like two competing rules:

  • in classic mode, ACK must depend on STB
  • in burst mode ACK must be independent of STB

Now the problem here is that a server that implements burst mode also must support "classic" cycle, where the classic rules apply.

To me it sounds like in the end, we are facing two root issues:

  1. The RTL is buggy, because even in burst mode, it will only ACK if STB is high. This violates Observation 4.00. However, since it is not a rule, that does not necessarily violate the Wishbone spec.
  2. Our combinational dependency checking is too conservative to adequatly handle this situation. There is no way we could determine that when the RTL is in a certain state (burst mode state) the STB is not considered, but when it is doing a classic cycle it is in fact considered.

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.

1 participant