diff --git a/bsg_misc/bsg_alloc_wavefront.sv b/bsg_misc/bsg_alloc_wavefront.sv new file mode 100644 index 000000000..734e4d7f0 --- /dev/null +++ b/bsg_misc/bsg_alloc_wavefront.sv @@ -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) + + + + + + + + + + + + + + + diff --git a/testing/bsg_misc/bsg_alloc_wavefront/.gitignore b/testing/bsg_misc/bsg_alloc_wavefront/.gitignore new file mode 100644 index 000000000..5826ea428 --- /dev/null +++ b/testing/bsg_misc/bsg_alloc_wavefront/.gitignore @@ -0,0 +1 @@ +vc_hdrs.h diff --git a/testing/bsg_misc/bsg_alloc_wavefront/Makefile b/testing/bsg_misc/bsg_alloc_wavefront/Makefile new file mode 100644 index 000000000..4f1a330a9 --- /dev/null +++ b/testing/bsg_misc/bsg_alloc_wavefront/Makefile @@ -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 diff --git a/testing/bsg_misc/bsg_alloc_wavefront/get_random.cpp b/testing/bsg_misc/bsg_alloc_wavefront/get_random.cpp new file mode 100644 index 000000000..cac0ae702 --- /dev/null +++ b/testing/bsg_misc/bsg_alloc_wavefront/get_random.cpp @@ -0,0 +1,9 @@ +#include + +extern "C" int get_random_binary() { + //static std::random_device rd; + static std::mt19937 e(0); + static std::uniform_int_distribution dis (0,1); + int rand = dis(e); + return rand; +} diff --git a/testing/bsg_misc/bsg_alloc_wavefront/sv.filelist b/testing/bsg_misc/bsg_alloc_wavefront/sv.filelist new file mode 100644 index 000000000..ae1ed1e4e --- /dev/null +++ b/testing/bsg_misc/bsg_alloc_wavefront/sv.filelist @@ -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 diff --git a/testing/bsg_misc/bsg_alloc_wavefront/testbench.sv b/testing/bsg_misc/bsg_alloc_wavefront/testbench.sv new file mode 100644 index 000000000..612bfcf3a --- /dev/null +++ b/testing/bsg_misc/bsg_alloc_wavefront/testbench.sv @@ -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