Many slaves share one master read path, so their read data buses meet in a mux. Each slave word is ANDed with its select replicated across the width, and the terms are ORed together.
The qualification is the point. Only the selected slave drives the result, so two slaves can never fight on the shared bus.
Read it left to right: gate, combine, register. Each AND gate is 32 gates wide, one per bit, all driven by the same select bit.
One select high: the other two AND gates output 0, so the OR passes the selected word unchanged.
No select high: every AND outputs 0 and rdata parks at zero. That is not an error response; the default slave supplies one.
Two selects high: the OR merges two words into garbage, which is why the selects must be one-hot.
Register the mux output when many slaves fan into one master read path. The register breaks a long combinational path that grows with every added slave.
bus_rmux is an unconditional datapath fragment, not a response channel: it has no valid, owner, error status or stalled-response storage. Adding that register alone does not preserve transaction association. Capture the complete {data,status,owner} tuple only when its response slot is free or consumed; hold the tuple and valid while the receiver stalls. The response slice in the next section supplies this contract.
A response is a tuple: data, status and the owner it belongs to. Under a stall the whole tuple must wait together, and a new tuple may enter only on the edge where the old one leaves.
Each slot is one clock cycle and ends with the edge of the same number in the testbench. A tuple moves in at the end of a slot where s_valid and s_ready are high, and out where m_valid and m_ready are high. m_status 2 is SLVERR (2'b10).
Slot 0: the slot is empty, so A (owner 0, OKAY, 0x11223344) is accepted at edge 0.
Slots 1 to 3: the receiver stalls. s_ready is low, A's owner and status stay unchanged, and B's source must hold its offer.
Slot 4: m_ready rises. Edge 4 consumes A and accepts B together, so m_owner and m_status switch to B's 1 and SLVERR in slot 5.
Slot 5: B is consumed at edge 5 and the slot is empty in slot 6.
The standalone slice takes an already-selected response tuple. It neither arbitrates targets nor tracks outstanding requests; those are upstream responsibilities. Its reverse ready path is combinational (the pass-through stage in Skid Buffer and Pipeline Stages); use that page's skid buffer when the ready path must be registered. The listing below is the slice with its directed bench.
module bus_rsp_slice (
input logic clk, rst_n, s_valid, m_ready,
output logic s_ready, m_valid,
input logic [31:0] s_data,
input logic [1:0] s_status, s_owner,
output logic [31:0] m_data,
output logic [1:0] m_status, m_owner
);
assign s_ready = !m_valid || m_ready;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) begin m_valid<=0; m_data<=0; m_status<=0; m_owner<=0; end
else if (s_ready) begin
m_valid <= s_valid;
if (s_valid) begin m_data<=s_data; m_status<=s_status; m_owner<=s_owner; end
end
endmodule
Byte lanes need care at the same boundary. The mux must preserve lane order, and both sides must agree on endianness.
Read the crossing lines as the bus wiring: address A always rides lane 0, whatever the CPU's endianness. Only the interpretation of the four lanes as one number changes.
Little-endian: lane 3 is the most significant byte, so the word is 0x44332211.
Big-endian: lane 0 is the most significant byte, so the same lanes read 0x11223344.
Byte access: a byte read of address A returns 0x11 under both, which is what byte-invariant means.
Case | Lane 3 | Lane 2 | Lane 1 | Lane 0 |
|---|---|---|---|---|
Little-endian word 0x44332211 | 0x44 | 0x33 | 0x22 | 0x11 |
Byte write to lane 0 | kept | kept | kept | new byte |
Byte addresses (byte-invariant bus) | A+3 holds 0x44 | A+2 holds 0x33 | A+1 holds 0x22 | A holds 0x11 |
CPU load/store conversion or a bridge may already normalise the peripheral's word convention; do not infer a lane swap from CPU endianness alone. Check byte addresses, strobes, bus lanes and software-visible word interpretation independently.
No. Determine what its bus interface and bridge already do and what the peripheral defines. Convert only when those contracts disagree; another swap may double-convert words or corrupt byte writes. Test bytes at A..A+3 as well as a fixed word.
The bitwise OR of two slave words, which is garbage. The one-hot select invariant belongs in an assertion, not just in the testbench.
The registered mux plus a testbench that drives six fixed patterns to each select in turn, with the unselected slaves carrying inverted garbage, and checks the registered result one cycle later.
// bus_rmux: AND-OR read-data mux qualified by one-hot selects, with registered output.
module bus_rmux #(
parameter int W = 32
)(
input logic [W-1:0] rdata0, rdata1, rdata_d,
input logic sel0, sel1, sel_d,
input logic clk, rst_n,
output logic [W-1:0] rdata
);
logic [W-1:0] mux_comb;
assign mux_comb = ({W{sel0}} & rdata0) | ({W{sel1}} & rdata1) | ({W{sel_d}} & rdata_d);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) rdata <= '0;
else rdata <= mux_comb;
end
endmodule