Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bsg_alloc_wavefront #695

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 217 additions & 0 deletions bsg_misc/bsg_alloc_wavefront.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/**
* bsg_alloc_wavefront.sv
*
* @author Tommy Jung
*
* N:N wavefront allocator;
*
* Based on "Efficient microarchitecture for network-on-chip routers",
* Daniel U Becker, PhD Thesis, Stanford University, 2012.
* (Section 3.3)
*
* This module coordinates an arbitration between N agents and N resources.
* Each agent may request for one or more resources.
* Given a request matrix (row=agent, col=resource), it generates a grant matrix, such that,
* - no resource granted for more than one agent.
* - no agent granted more than one resource.
* - no grant when there is no request.
* - if there is a request, which is not granted, it implies some other grant in the same column or row.
* It tries to maximize the number of matches between agents and resources for improved utilization.
*
*/


`include "bsg_defines.sv"



module bsg_alloc_wavefront
#(parameter `BSG_INV_PARAM(width_p) // Number of Agents/Resources;
)
(
input clk_i
, input reset_i

// 2-D bit matrix;
// [agent_idx][resource_idx]
, input [width_p-1:0][width_p-1:0] reqs_i
, output logic [width_p-1:0][width_p-1:0] grants_o

// assert yumi_i to accept the grant matrix;
, input yumi_i
);


// Rotate reqs_i so that diagonal elements end up in the same row;
logic [width_p-1:0][width_p-1:0] reqs_rotate;

for (genvar i = 0; i < width_p; i++) begin
for (genvar j = 0; j < width_p; j++) begin
assign reqs_rotate[i][j] = reqs_i[(width_p+i-j)%width_p][j];
end
end


// priority diagonal signal;;
logic [width_p-1:0] priority_diag;


// cell array;
logic [(2*width_p)-1-1:0][width_p-1:0] y_li, x_li, priority_li, req_li, y_lo, x_lo, grant_lo;

for (genvar i = 0; i < (2*width_p)-1; i++) begin: y
for (genvar j = 0; j < width_p; j++) begin: x
// wavefront cell;
bsg_alloc_wavefront_cell cell0 (
.x_i (x_li[i][j])
,.y_i (y_li[i][j])
,.priority_i (priority_li[i][j])
,.req_i (req_li[i][j])
,.y_o (y_lo[i][j])
,.x_o (x_lo[i][j])
,.grant_o (grant_lo[i][j])
);

// connect y;
if (i == 0) begin
assign y_li[i][j] = 1'b0;
end
else begin
assign y_li[i][j] = y_lo[i-1][j];
end

// connect x;
if (i == 0) begin
assign x_li[i][j] = 1'b0;
end
else begin
if (j == 0) begin
assign x_li[i][j] = x_lo[i-1][width_p-1];
end
else begin
assign x_li[i][j] = x_lo[i-1][j-1];
end
end

// connect priority;
if (i < width_p) begin
assign priority_li[i][j] = priority_diag[i];
end
else begin
assign priority_li[i][j] = 1'b0;
end

// connect req;
assign req_li[i][j] = reqs_rotate[i%width_p][j];
end
end





// Priority diagonal generator;
logic [width_p-1:0] rr_reqs;

// OR reduce;
for (genvar i = 0; i < width_p; i++) begin
assign rr_reqs[i] = |reqs_rotate[i];
end

bsg_arb_round_robin #(
.width_p(width_p)
) rr0 (
.clk_i(clk_i)
,.reset_i(reset_i)

,.reqs_i(rr_reqs)
,.grants_o(priority_diag)
,.yumi_i(yumi_i)
);


////////////////////////
// Connect grant output;
////////////////////////

// transpose grant_lo;
logic [width_p-1:0][(2*width_p)-1-1:0] grants_tp;
bsg_transpose #(
.width_p(width_p)
,.els_p((2*width_p)-1)
) tp0 (
.i(grant_lo)
,.o(grants_tp)
);

// Apply OR;
logic [width_p-1:0][width_p-1:0] grants_or;
for (genvar i = 0; i < width_p; i++) begin
assign grants_or[i] = grants_tp[i][0+:width_p] | {1'b0, grants_tp[i][width_p+:width_p-1]};
end

// rotate;
logic [width_p-1:0][width_p-1:0] grants_rotate;
for (genvar i = 0; i < width_p; i++) begin
assign grants_rotate[i] = width_p'({grants_or[i], grants_or[i]} >> i);
end


// transpose it back;
bsg_transpose #(
.width_p(width_p)
,.els_p(width_p)
) tp1 (
.i(grants_rotate)
,.o(grants_o)
);



endmodule


`BSG_ABSTRACT_MODULE(bsg_alloc_wavefront)



// private module for bsg_alloc_wavefront;
module bsg_alloc_wavefront_cell
(
input x_i
, input y_i
, input priority_i
, input req_i
, output logic y_o
, output logic x_o
, output logic grant_o
);

wire yp = y_i | priority_i;
wire xp = x_i | priority_i;

wire grant = yp & xp & req_i;
assign grant_o = grant;

assign x_o = xp & ~grant;
assign y_o = yp & ~grant;

endmodule


`BSG_ABSTRACT_MODULE(bsg_alloc_wavefront_cell)















1 change: 1 addition & 0 deletions testing/bsg_misc/bsg_alloc_wavefront/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vc_hdrs.h
32 changes: 32 additions & 0 deletions testing/bsg_misc/bsg_alloc_wavefront/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export THIS_DIR = $(abspath .)
export BASEJUMP_STL_DIR = $(shell git rev-parse --show-toplevel)
export CADENV_DIR = $(abspath $(BASEJUMP_STL_DIR)/../bsg_cadenv)

include $(CADENV_DIR)/cadenv.mk

VCS_FLAGS += -R -full64 +v2k -sverilog
VCS_FLAGS += -timescale=1ps/1ps
VCS_FLAGS += +lint=all,noSVA-UA,noSVA-NSVU,noVCDE,noNS -top testbench
VCS_FLAGS += -licqueue
VCS_FLAGS += -reportstats
VCS_FLAGS += -assert svaext
VCS_FLAGS += -l run.log
VCS_FLAGS += -debug_pp
VCS_FLAGS += +vcs+vcdpluson
#VCS_FLAGS += +vcs+nostdout

VCS_INCDIR += +incdir+$(BASEJUMP_STL_DIR)/bsg_misc

VCS_DEFINES +=

run:
vcs -R -full64 $(VCS_FLAGS) $(VCS_INCDIR) $(VCS_DEFINES) -f sv.filelist


dve:
dve -full64 -vpd vcdplus.vpd &


clean:
rm -rf csrc simv simv.daidir stack.info*
rm -rf ucli.key vc_hdrs.h vcdplus.vpd run.log
9 changes: 9 additions & 0 deletions testing/bsg_misc/bsg_alloc_wavefront/get_random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <random>

extern "C" int get_random_binary() {
//static std::random_device rd;
static std::mt19937 e(0);
static std::uniform_int_distribution<int> dis (0,1);
int rand = dis(e);
return rand;
}
9 changes: 9 additions & 0 deletions testing/bsg_misc/bsg_alloc_wavefront/sv.filelist
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
testbench.sv
get_random.cpp
$BASEJUMP_STL_DIR/bsg_test/bsg_nonsynth_clock_gen.sv
$BASEJUMP_STL_DIR/bsg_test/bsg_nonsynth_reset_gen.sv
$BASEJUMP_STL_DIR/bsg_misc/bsg_alloc_wavefront.sv
$BASEJUMP_STL_DIR/bsg_misc/bsg_cycle_counter.sv
$BASEJUMP_STL_DIR/bsg_misc/bsg_transpose.sv
$BASEJUMP_STL_DIR/bsg_misc/bsg_arb_round_robin.sv
$BASEJUMP_STL_DIR/bsg_misc/bsg_scan.sv
125 changes: 125 additions & 0 deletions testing/bsg_misc/bsg_alloc_wavefront/testbench.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
`include "bsg_defines.sv"


module testbench();

// Clock gen and reset;
bit clk, reset;

bsg_nonsynth_clock_gen #(
.cycle_time_p(10)
) cg0 (.o(clk));


bsg_nonsynth_reset_gen #(
.reset_cycles_lo_p(0)
,.reset_cycles_hi_p(4)
) rg0 (
.clk_i(clk)
,.async_reset_o(reset)
);



// Parameters;
localparam width_p = 5;


// Random number DPI;
import "DPI-C" context function int get_random_binary();


// DUT;
logic [width_p-1:0][width_p-1:0] reqs_r, grants_lo;
logic yumi_li;

bsg_alloc_wavefront #(
.width_p(width_p)
) DUT (
.clk_i(clk)
,.reset_i(reset)

,.reqs_i(reqs_r)
,.grants_o(grants_lo)

,.yumi_i(yumi_li)
);

assign yumi_li = 1'b1;

always_ff @ (posedge clk) begin
if (reset) begin
reqs_r <= '0;
end
else begin
for (integer i = 0; i < width_p; i++) begin
for (integer j = 0; j < width_p; j++) begin
reqs_r[i][j] <= get_random_binary();
end
end
end
end


// cycle counter;
integer ctr_r;
bsg_cycle_counter #(
.width_p(32)
) cc0 (
.clk_i(clk)
,.reset_i(reset)
,.ctr_r_o(ctr_r)
);

initial begin
wait(ctr_r == 100000);
$finish();
end


// transpose grants_lo;
logic [width_p-1:0][width_p-1:0] grants_lo_tp;
bsg_transpose #(
.width_p(width_p)
,.els_p(width_p)
) tp0 (
.i(grants_lo)
,.o(grants_lo_tp)
);


// assertion;;
always_ff @ (negedge clk) begin
if (~reset) begin
// Assert #1;
for (integer i = 0; i < width_p; i++) begin
for (integer j = 0; j < width_p; j++) begin
if (grants_lo[i][j]) begin
assert(reqs_r[i][j]) else $error("(%0d, %0d) grants=1, but req=0.", i, j);
end
end
end

// Assert #2;
for (integer i = 0; i < width_p; i++) begin
assert($countones(grants_lo[i]) < 2) else $error("Found more than one grant in row %d", i);
end

// Assert #3;
for (integer i = 0; i < width_p; i++) begin
assert($countones(grants_lo_tp[i]) < 2) else $error("Found more than one grant in column %d", i);
end

// Assert #4;
for (integer i = 0; i < width_p; i++) begin
for (integer j = 0; j < width_p; j++) begin
if (reqs_r[i][j] & ~grants_lo[i][j]) begin
assert ($countones(grants_lo[i] & ~(1'b1 << j)) > 0 || $countones(grants_lo_tp[j] & ~(1'b1 << i)) > 0) else $error("Req but no grant, but no col/row neighbor granted. (%d, %d)", i, j);
end
end
end
end
end


endmodule