blob: f3b0ce31580ac941a65815875760a9fbb75472be [file] [log] [blame]
/****************************************************************************
* ${NAME}.sv
****************************************************************************/
/**
* Module: wb_interconnect_NxN
*
* TODO: Add module documentation
*/
module wb_interconnect_NxN #(
parameter WB_ADDR_WIDTH=32,
parameter WB_DATA_WIDTH=32,
parameter N_INITIATORS=1,
parameter N_TARGETS=1,
parameter [N_INITIATORS*WB_ADDR_WIDTH-1:0] I_ADR_MASK = {
{8'hFF, {24{1'b0}} }
},
parameter [N_TARGETS*WB_ADDR_WIDTH-1:0] T_ADR = {
{ 32'h2800_0000 }
}
) (
input clk,
input rst,
input[WB_ADDR_WIDTH*N_INITIATORS-1:0] ADR,
input[WB_DATA_WIDTH*N_INITIATORS-1:0] DAT_W,
output[WB_DATA_WIDTH*N_INITIATORS-1:0] DAT_R,
input[N_INITIATORS-1:0] CYC,
output[N_INITIATORS-1:0] ERR,
input[(WB_DATA_WIDTH/8)*N_INITIATORS-1:0] SEL,
input[N_INITIATORS-1:0] STB,
output[N_INITIATORS-1:0] ACK,
input[N_INITIATORS-1:0] WE,
output[WB_ADDR_WIDTH*(N_TARGETS+1)-1:0] TADR,
output[WB_DATA_WIDTH*(N_TARGETS+1)-1:0] TDAT_W,
input[WB_DATA_WIDTH*(N_TARGETS+1)-1:0] TDAT_R,
output[N_TARGETS:0] TCYC,
input[N_TARGETS:0] TERR,
output[(WB_DATA_WIDTH/8)*(N_TARGETS+1)-1:0] TSEL,
output[N_TARGETS:0] TSTB,
input[N_TARGETS:0] TACK,
output[N_TARGETS:0] TWE
);
localparam WB_DATA_MSB = (WB_DATA_WIDTH-1);
localparam N_INIT_ID_BITS = (N_INITIATORS>1)?$clog2(N_INITIATORS):1;
localparam N_TARG_ID_BITS = $clog2(N_TARGETS+1);
localparam NO_TARGET = {(N_TARG_ID_BITS+1){1'b1}};
localparam NO_INITIATOR = {(N_INIT_ID_BITS+1){1'b1}};
// Interface to the decode-fail target
// wb_if TERR();
function reg[N_TARG_ID_BITS:0] addr2targ_id(
input reg[N_INIT_ID_BITS-1:0] initiator,
input reg[WB_ADDR_WIDTH-1:0] addr
);
integer i;
begin
addr2targ_id = N_TARGETS;
// $display("addr2targ_id: 'h%08h 'h%08h", addr, ADDR_RANGES);
for (i=0; i<N_TARGETS; i+=1) begin
// $display("Address Range: %0d 'h%08h..'h%08h", i,
// ADDR_RANGES[(WB_ADDR_WIDTH*(i+2)-1)-:WB_ADDR_WIDTH],
// ADDR_RANGES[(WB_ADDR_WIDTH*(i+1)-1)-:WB_ADDR_WIDTH]);
// $display(" %0d %0d", (WB_ADDR_WIDTH*(i+2)-1), (WB_ADDR_WIDTH*(i+1)-1));
if (
(addr&I_ADR_MASK[(WB_ADDR_WIDTH*(i+1))-1-:WB_ADDR_WIDTH]) ==
(T_ADR[(WB_ADDR_WIDTH*(i+1))-1-:WB_ADDR_WIDTH])) begin
$display("Address 'h%08h: range=%0d", addr, N_TARGETS-1);
addr2targ_id = N_TARGETS-1;
end
end
end
endfunction
// Read request state machine
// Initiator state machine
reg[2:0] initiator_state[N_INITIATORS-1:0];
reg[N_TARG_ID_BITS:0] initiator_selected_target[N_INITIATORS-1:0];
wire initiator_gnt[N_TARGETS:0];
wire[$clog2(N_INITIATORS)-1:0] initiator_gnt_id[N_TARGETS:0];
wire[N_INITIATORS-1:0] initiator_target_req[N_TARGETS:0];
generate
genvar m_i;
for (m_i=0; m_i<N_INITIATORS; m_i=m_i+1) begin : block_m_i
always @(posedge clk) begin
if (rst == 1) begin
initiator_state[m_i] <= 0;
initiator_selected_target[m_i] <= NO_TARGET;
end else begin
case (initiator_state[m_i])
0: begin
if (CYC[m_i] && STB[m_i]) begin
initiator_state[m_i] <= 1;
initiator_selected_target[m_i] <= addr2targ_id(
m_i,
ADR[WB_ADDR_WIDTH*m_i+:WB_ADDR_WIDTH]
);
// $display("Master %0d => Slave %0d", m_i, addr2targ_id(m_i, ADR[m_i]));
end
end
1: begin
// Wait for the addressed target to acknowledge
if (CYC[m_i] && STB[m_i] && ACK[m_i]) begin
initiator_state[m_i] <= 0;
initiator_selected_target[m_i] <= NO_TARGET;
end
end
endcase
end
end
end
endgenerate
// Build the req vector for each target
generate
genvar m_req_i, m_req_j;
for (m_req_i=0; m_req_i <(N_TARGETS+1); m_req_i=m_req_i+1) begin : block_m_req_i
for (m_req_j=0; m_req_j < N_INITIATORS; m_req_j=m_req_j+1) begin : block_m_req_j
assign initiator_target_req[m_req_i][m_req_j] = (initiator_selected_target[m_req_j] == m_req_i);
end
end
endgenerate
generate
genvar s_arb_i;
for (s_arb_i=0; s_arb_i<(N_TARGETS+1); s_arb_i=s_arb_i+1) begin : s_arb
wb_NxN_arbiter #(
.N_REQ (N_INITIATORS)
)
aw_arb (
.clk (clk ),
.rst (rst ),
.req (initiator_target_req[s_arb_i]),
.gnt (initiator_gnt[s_arb_i]),
.gnt_id (initiator_gnt_id[s_arb_i])
);
end
endgenerate
wire[N_INIT_ID_BITS:0] target_active_initiator[N_TARGETS:0];
generate
genvar s_am_i;
for (s_am_i=0; s_am_i<(N_TARGETS+1); s_am_i=s_am_i+1) begin : block_s_am_i
assign target_active_initiator[s_am_i] =
(initiator_gnt[s_am_i])?initiator_gnt_id[s_am_i]:NO_INITIATOR;
end
endgenerate
// WB signals from target back to initiator
generate
genvar s2m_i;
for (s2m_i=0; s2m_i<N_INITIATORS; s2m_i=s2m_i+1) begin : block_s2m_i
assign DAT_R[WB_DATA_WIDTH*s2m_i+:WB_DATA_WIDTH] =
(initiator_selected_target[s2m_i] != NO_TARGET &&
initiator_gnt[initiator_selected_target[s2m_i]] &&
initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)?
TDAT_R[WB_DATA_WIDTH*initiator_selected_target[s2m_i]+:WB_DATA_WIDTH]:0;
assign ERR[s2m_i] = (initiator_selected_target[s2m_i] != NO_TARGET &&
initiator_gnt[initiator_selected_target[s2m_i]] &&
initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)?
TERR[initiator_selected_target[s2m_i]]:0;
assign ACK[s2m_i] = (initiator_selected_target[s2m_i] != NO_TARGET &&
initiator_gnt[initiator_selected_target[s2m_i]] &&
initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)?
TACK[initiator_selected_target[s2m_i]]:0;
end
endgenerate
// WB signals to target mux
generate
genvar m2s_i;
for(m2s_i=0; m2s_i<(N_TARGETS+1); m2s_i=m2s_i+1) begin : WB_M2S_assign
assign TADR[WB_ADDR_WIDTH*m2s_i+:WB_ADDR_WIDTH] =
(target_active_initiator[m2s_i] == NO_INITIATOR)?0:ADR[WB_ADDR_WIDTH*target_active_initiator[m2s_i]+:WB_ADDR_WIDTH];
assign TDAT_W[WB_DATA_WIDTH*m2s_i+:WB_DATA_WIDTH] =
(target_active_initiator[m2s_i] == NO_INITIATOR)?0:DAT_W[WB_DATA_WIDTH*target_active_initiator[m2s_i]+:WB_DATA_WIDTH];
assign TCYC[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:CYC[target_active_initiator[m2s_i]];
assign TSEL[(WB_DATA_WIDTH/8)*m2s_i+:(WB_DATA_WIDTH/8)] =
(target_active_initiator[m2s_i] == NO_INITIATOR)?0:
SEL[(WB_DATA_WIDTH/8)*target_active_initiator[m2s_i]+:(WB_DATA_WIDTH/8)];
assign TSTB[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:STB[target_active_initiator[m2s_i]];
assign TWE[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:WE[target_active_initiator[m2s_i]];
end
endgenerate
// Error target
reg err_req;
always @(posedge clk) begin
if (rst == 1) begin
err_req <= 0;
end else begin
if (TSTB[N_TARGETS] && TCYC[N_TARGETS] && !err_req) begin
err_req <= 1;
end else begin
err_req <= 0;
end
end
end
endmodule
module wb_NxN_arbiter #(
parameter N_REQ=2
) (
input clk,
input rst,
input[N_REQ-1:0] req,
output gnt,
output[$clog2(N_REQ)-1:0] gnt_id
);
reg state;
reg [N_REQ-1:0] gnt_o = 0;
reg [N_REQ-1:0] last_gnt = 0;
reg [$clog2(N_REQ)-1:0] gnt_id_o = 0;
assign gnt = |gnt_o;
assign gnt_id = gnt_id_o;
wire[N_REQ-1:0] gnt_ppc;
wire[N_REQ-1:0] gnt_ppc_next;
generate
if (N_REQ > 1) begin
assign gnt_ppc_next = {gnt_ppc[N_REQ-2:0], 1'b0};
end else begin
assign gnt_ppc_next = gnt_ppc;
end
endgenerate
generate
genvar gnt_ppc_i;
for (gnt_ppc_i=N_REQ-1; gnt_ppc_i>=0; gnt_ppc_i=gnt_ppc_i-1) begin : block_gnt_ppc_i
if (gnt_ppc_i == 0) begin
assign gnt_ppc[gnt_ppc_i] = last_gnt[0];
end else begin
assign gnt_ppc[gnt_ppc_i] = |last_gnt[gnt_ppc_i-1:0];
end
end
endgenerate
wire[N_REQ-1:0] unmasked_gnt;
generate
genvar unmasked_gnt_i;
for (unmasked_gnt_i=0; unmasked_gnt_i<N_REQ; unmasked_gnt_i=unmasked_gnt_i+1) begin : block_unmasked_gnt_i
// Prioritized unmasked grant vector. Grant to the lowest active grant
if (unmasked_gnt_i == 0) begin
assign unmasked_gnt[unmasked_gnt_i] = req[unmasked_gnt_i];
end else begin
assign unmasked_gnt[unmasked_gnt_i] = (req[unmasked_gnt_i] & ~(|req[unmasked_gnt_i-1:0]));
end
end
endgenerate
wire[N_REQ-1:0] masked_gnt;
generate
genvar masked_gnt_i;
for (masked_gnt_i=0; masked_gnt_i<N_REQ; masked_gnt_i=masked_gnt_i+1) begin : block_masked_gnt_i
if (masked_gnt_i == 0) begin
assign masked_gnt[masked_gnt_i] = (gnt_ppc_next[masked_gnt_i] & req[masked_gnt_i]);
end else begin
// Select first request above the last grant
assign masked_gnt[masked_gnt_i] = (gnt_ppc_next[masked_gnt_i] & req[masked_gnt_i] &
~(|(gnt_ppc_next[masked_gnt_i-1:0] & req[masked_gnt_i-1:0])));
end
end
endgenerate
wire[N_REQ-1:0] prioritized_gnt;
// Give priority to the 'next' request
assign prioritized_gnt = (|masked_gnt)?masked_gnt:unmasked_gnt;
always @(posedge clk) begin
if (rst == 1) begin
state <= 0;
last_gnt <= 0;
gnt_o <= 0;
gnt_id_o <= 0;
end else begin
case (state)
0: begin
if (|prioritized_gnt) begin
state <= 1;
gnt_o <= prioritized_gnt;
last_gnt <= prioritized_gnt;
gnt_id_o <= gnt2id(prioritized_gnt);
end
end
1: begin
if ((gnt_o & req) == 0) begin
state <= 0;
gnt_o <= 0;
end
end
endcase
end
end
function reg[$clog2(N_REQ)-1:0] gnt2id(input reg[N_REQ-1:0] gnt);
integer i;
begin
// reg[$clog2(N_REQ)-1:0] result;
gnt2id = 0;
for (i=0; i<N_REQ; i++) begin
if (gnt[i]) begin
gnt2id |= i;
end
end
end
endfunction
endmodule