blob: 2586e2e4e772fe507f2158cefd0c764ac1e6c8b6 [file] [log] [blame]
/****************************************************************************
* wb_interconnect_NxN.sv
*
* Completely-combinatorial Wishbone interconnect
****************************************************************************/
/**
* 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 clock,
input reset,
// Target ports into the interconnect
input[(N_INITIATORS*WB_ADDR_WIDTH)-1:0] adr,
input[(N_INITIATORS*WB_DATA_WIDTH)-1:0] dat_w,
output reg[(N_INITIATORS*WB_DATA_WIDTH)-1:0] dat_r,
input[N_INITIATORS-1:0] cyc,
output[N_INITIATORS-1:0] err,
input[N_INITIATORS*(WB_DATA_WIDTH/8)-1:0] sel,
input[N_INITIATORS-1:0] stb,
output reg[N_INITIATORS-1:0] ack,
input[N_INITIATORS-1:0] we,
// Initiator ports out of the interconnect
output reg[(N_TARGETS*WB_ADDR_WIDTH)-1:0] tadr,
output reg[(N_TARGETS*WB_DATA_WIDTH)-1:0] tdat_w,
input[(N_TARGETS*WB_DATA_WIDTH)-1:0] tdat_r,
output[N_TARGETS-1:0] tcyc,
input[N_TARGETS-1:0] terr,
output reg[N_TARGETS*(WB_DATA_WIDTH/8)-1:0] tsel,
output[N_TARGETS-1:0] tstb,
input[N_TARGETS-1:0] tack,
output[N_TARGETS-1: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}};
// Each initiator has a request vector -> Which target is desired
//
// Each target has an arbiter -> Which initiator has access
//
// When the two match, the initiator and target are connected
//
//
// Decode logic
// This vector contains an element for each initiator and target,
// and are one-hot encoded.
//
// target_initiator_sel - per-target request vector. Sent to target arbiters.
// Consists of a vector of initiators wishing to access the target
// initiator_target_sel - per-initator request vector.
// Consists of a vector representing the target an initiator is accessing
wire[N_TARGETS-1:0] initiator_target_sel[N_INITIATORS-1:0];
wire[N_INITIATORS-1:0] target_initiator_sel[N_TARGETS-1:0];
generate
genvar md_i, md_t_i;
for (md_i=0; md_i<N_INITIATORS; md_i=md_i+1) begin : block_md_i
for (md_t_i=0; md_t_i<N_TARGETS; md_t_i=md_t_i+1) begin : block_md_t_i
assign target_initiator_sel[N_TARGETS-md_t_i-1][md_i] =
((adr[WB_ADDR_WIDTH*md_i+:WB_ADDR_WIDTH]&I_ADR_MASK[WB_ADDR_WIDTH*md_i+:WB_ADDR_WIDTH])
== T_ADR[WB_ADDR_WIDTH*md_t_i+:WB_ADDR_WIDTH]) && (cyc[md_i] && stb[md_i]);
assign initiator_target_sel[md_i][md_t_i] = target_initiator_sel[md_t_i][md_i];
end
end
endgenerate
// Per-target grant vector
wire[N_INITIATORS-1:0] initiator_gnt[N_TARGETS-1:0];
generate
genvar t_arb_i;
for (t_arb_i=0; t_arb_i<N_TARGETS; t_arb_i=t_arb_i+1) begin : s_arb
wb_interconnect_arb #(
.N_REQ (N_INITIATORS)
)
aw_arb (
.clock (clock ),
.reset (reset ),
// Request vector
.req (target_initiator_sel[t_arb_i]),
// One-hot grant vector
.gnt (initiator_gnt[t_arb_i])
);
end
endgenerate
reg[N_INIT_ID_BITS:0] target_active_initiator[N_TARGETS-1:0];
generate
// For each target, determine which initiator is connected
genvar t_ai_i;
integer t_ai_ii;
for (t_ai_i=0; t_ai_i<N_TARGETS; t_ai_i=t_ai_i+1) begin : block_t_ai
always @* begin
target_active_initiator[t_ai_i] = NO_INITIATOR;
for (t_ai_ii=0; t_ai_ii<N_INITIATORS; t_ai_ii=t_ai_ii+1) begin
if (initiator_gnt[t_ai_i][t_ai_ii]) begin
target_active_initiator[t_ai_i] = t_ai_ii;
end
end
end
end
endgenerate
// Per-initiator id of the selected target
// Controls response-path muxing
reg[N_TARG_ID_BITS-1:0] initiator_active_target[N_INITIATORS-1:0];
generate
// For each initiator, determine which target is selected and granted
genvar i_at_i;
integer i_at_ii;
for (i_at_i=0; i_at_i<N_INITIATORS; i_at_i=i_at_i+1) begin : block_i_at
always @* begin
initiator_active_target[i_at_i] = NO_TARGET;
for (i_at_ii=0; i_at_ii<N_TARGETS; i_at_ii=i_at_ii+1) begin
// TODO:
if (initiator_target_sel[i_at_i][i_at_ii]) begin
initiator_active_target[i_at_i] = i_at_ii;
end
end
end
end
endgenerate
// reg[N_INIT_ID_BITS:0] target_active_initiator[N_TARGETS:0];
// generate
// // For each target, determine which initiator is connected
// genvar t_ai_i;
// integer t_ai_ii;
// for (t_ai_i=0; t_ai_i<N_TARGETS; t_ai_i=t_am_i+1) begin : block_t_ai
// always @* begin
// target_active_initiator[t_ai_i] = NO_INITIATOR;
// for (t_ai_ii=0; t_ai_ii<N_INITIATORS; t_ai_ii=t_ai_ii+1) begin
// if (initiator_gnt[t_ai_i][t_ai_ii]) begin
// target_active_initiator[t_ai_i] = t_ai_ii;
// end
// end
// end
// end
// endgenerate
// WB signals from target back to initiator
generate
genvar t2i_i, t2i_j;
integer t2i_ii;
for (t2i_i=0; t2i_i<N_INITIATORS; t2i_i=t2i_i+1) begin : block_t2i_i
always @* begin
dat_r[WB_DATA_WIDTH*t2i_i+:WB_DATA_WIDTH] = {WB_DATA_WIDTH{1'b0}};
ack[t2i_i] = 1'b0;
for (t2i_ii=0; t2i_ii<N_TARGETS; t2i_ii=t2i_ii+1) begin
if (initiator_active_target[t2i_i] == t2i_ii) begin
dat_r[WB_DATA_WIDTH*t2i_i+:WB_DATA_WIDTH] =
tdat_r[WB_DATA_WIDTH*t2i_ii+:WB_DATA_WIDTH];
ack[t2i_i] = tack[t2i_ii];
end
end
end
assign err[t2i_i] = (initiator_active_target[t2i_i] != NO_TARGET)?
terr[initiator_active_target[t2i_i]]:1'b0;
end
endgenerate
// Initiator to target mux
generate
genvar i2t_mux_i;
integer i2t_mux_ii;
for (i2t_mux_i=0; i2t_mux_i<N_TARGETS; i2t_mux_i=i2t_mux_i+1) begin : i2t_mux
always @* begin
tadr[WB_ADDR_WIDTH*i2t_mux_i+:WB_ADDR_WIDTH] = {WB_ADDR_WIDTH{1'b0}};
tdat_w[WB_DATA_WIDTH*i2t_mux_i+:WB_DATA_WIDTH] = {WB_DATA_WIDTH{1'b0}};
tsel[(WB_DATA_WIDTH/8)*i2t_mux_i+:(WB_DATA_WIDTH/8)] = {(WB_DATA_WIDTH/8){1'b0}};
for (i2t_mux_ii=0; i2t_mux_ii<N_INITIATORS; i2t_mux_ii=i2t_mux_ii+1) begin
if (target_active_initiator[i2t_mux_i] == i2t_mux_ii) begin
tadr[WB_ADDR_WIDTH*i2t_mux_i+:WB_ADDR_WIDTH] =
adr[WB_ADDR_WIDTH*i2t_mux_ii+:WB_ADDR_WIDTH];
tdat_w[WB_DATA_WIDTH*i2t_mux_i+:WB_DATA_WIDTH] =
dat_w[WB_DATA_WIDTH*i2t_mux_ii+:WB_DATA_WIDTH];
tsel[(WB_DATA_WIDTH/8)*i2t_mux_i+:(WB_DATA_WIDTH/8)] =
sel[(WB_DATA_WIDTH/8)*i2t_mux_ii+:(WB_DATA_WIDTH/8)];
end
end
end
/*
assign tadr[WB_ADDR_WIDTH*i2t_mux_i+:WB_ADDR_WIDTH] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?{WB_ADDR_WIDTH{1'b0}}:
adr[{target_active_initiator[i2t_mux_i], 2'b00}+:WB_ADDR_WIDTH];
assign tadr[WB_ADDR_WIDTH*i2t_mux_i+:WB_ADDR_WIDTH] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?{WB_ADDR_WIDTH{1'b0}}:
adr[WB_ADDR_WIDTH*target_active_initiator[i2t_mux_i]+:WB_ADDR_WIDTH];
*/
/*
assign tdat_w[WB_DATA_WIDTH*i2t_mux_i+:WB_DATA_WIDTH] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?{WB_DATA_WIDTH{1'b0}}:
dat_w[WB_DATA_WIDTH*target_active_initiator[i2t_mux_i]+:WB_DATA_WIDTH];
*/
assign tcyc[i2t_mux_i] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?1'b0:
cyc[target_active_initiator[i2t_mux_i]];
/*
assign tsel[(WB_DATA_WIDTH/8)*i2t_mux_i+:(WB_DATA_WIDTH/8)] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?{(WB_DATA_WIDTH/8){1'b0}}:
sel[(WB_DATA_WIDTH/8)*target_active_initiator[i2t_mux_i]+:(WB_DATA_WIDTH/8)];
*/
assign tstb[i2t_mux_i] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?1'b0:
stb[target_active_initiator[i2t_mux_i]];
assign twe[i2t_mux_i] =
(target_active_initiator[i2t_mux_i] == NO_INITIATOR)?1'b0:
we[target_active_initiator[i2t_mux_i]];
end
endgenerate
// // Error target
// reg err_req;
// always @(posedge clock) begin
// if (reset == 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