-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
prim: Add arbiter module and testbench
Signed-off-by: Alex Forencich <[email protected]>
- Loading branch information
1 parent
5966d05
commit 46e60d3
Showing
3 changed files
with
540 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
// SPDX-License-Identifier: CERN-OHL-S-2.0 | ||
/* | ||
Copyright (c) 2014-2025 FPGA Ninja, LLC | ||
Authors: | ||
- Alex Forencich | ||
*/ | ||
|
||
`resetall | ||
`timescale 1ns / 1ps | ||
`default_nettype none | ||
|
||
/* | ||
* Arbiter module | ||
*/ | ||
module taxi_arbiter # | ||
( | ||
parameter PORTS = 4, | ||
// select round robin arbitration | ||
parameter logic ARB_ROUND_ROBIN = 1'b1, | ||
// blocking arbiter enable | ||
parameter logic ARB_BLOCK = 1'b1, | ||
// block on acknowledge assert when nonzero, request deassert when 0 | ||
parameter logic ARB_BLOCK_ACK = 1'b0, | ||
// LSB priority selection | ||
parameter logic LSB_HIGH_PRIO = 1'b0 | ||
) | ||
( | ||
input wire logic clk, | ||
input wire logic rst, | ||
|
||
input wire logic [PORTS-1:0] req, | ||
input wire logic [PORTS-1:0] ack, | ||
|
||
output wire logic grant_valid, | ||
output wire logic [PORTS-1:0] grant, | ||
output wire logic [$clog2(PORTS)-1:0] grant_index | ||
); | ||
|
||
localparam CL_PORTS = $clog2(PORTS); | ||
|
||
logic [PORTS-1:0] grant_reg = 'd0, grant_next; | ||
logic grant_valid_reg = 1'b0, grant_valid_next; | ||
logic [CL_PORTS-1:0] grant_index_reg = 'd0, grant_index_next; | ||
|
||
assign grant_valid = grant_valid_reg; | ||
assign grant = grant_reg; | ||
assign grant_index = grant_index_reg; | ||
|
||
wire req_valid; | ||
wire [CL_PORTS-1:0] req_index; | ||
wire [PORTS-1:0] req_mask; | ||
|
||
taxi_penc #( | ||
.WIDTH(PORTS), | ||
.LSB_HIGH_PRIO(LSB_HIGH_PRIO) | ||
) | ||
penc_inst ( | ||
.input_mask(req), | ||
.output_valid(req_valid), | ||
.output_index(req_index), | ||
.output_mask(req_mask) | ||
); | ||
|
||
logic [PORTS-1:0] mask_reg = 'd0, mask_next; | ||
|
||
wire masked_req_valid; | ||
wire [CL_PORTS-1:0] masked_req_index; | ||
wire [PORTS-1:0] masked_req_mask; | ||
|
||
if (ARB_ROUND_ROBIN) begin | ||
|
||
taxi_penc #( | ||
.WIDTH(PORTS), | ||
.LSB_HIGH_PRIO(LSB_HIGH_PRIO) | ||
) | ||
penc_masked ( | ||
.input_mask(req & mask_reg), | ||
.output_valid(masked_req_valid), | ||
.output_index(masked_req_index), | ||
.output_mask(masked_req_mask) | ||
); | ||
|
||
end else begin | ||
|
||
assign masked_req_valid = 1'b0; | ||
assign masked_req_index = '0; | ||
assign masked_req_mask = '0; | ||
|
||
end | ||
|
||
always_comb begin | ||
grant_next = 'd0; | ||
grant_valid_next = 1'b0; | ||
grant_index_next = 'd0; | ||
mask_next = mask_reg; | ||
|
||
if (ARB_BLOCK && !ARB_BLOCK_ACK && ((grant_reg & req) != 0)) begin | ||
// granted req still asserted; hold it | ||
grant_valid_next = grant_valid_reg; | ||
grant_next = grant_reg; | ||
grant_index_next = grant_index_reg; | ||
end else if (ARB_BLOCK && ARB_BLOCK_ACK && grant_valid && ((grant_reg & ack) == 0)) begin | ||
// granted req not yet acknowledged; hold it | ||
grant_valid_next = grant_valid_reg; | ||
grant_next = grant_reg; | ||
grant_index_next = grant_index_reg; | ||
end else if (req_valid) begin | ||
if (ARB_ROUND_ROBIN) begin | ||
if (masked_req_valid) begin | ||
grant_valid_next = 1'b1; | ||
grant_next = masked_req_mask; | ||
grant_index_next = masked_req_index; | ||
if (LSB_HIGH_PRIO) begin | ||
mask_next = {PORTS{1'b1}} << (masked_req_index + 1); | ||
end else begin | ||
mask_next = {PORTS{1'b1}} >> ((CL_PORTS+1)'(PORTS) - masked_req_index); | ||
end | ||
end else begin | ||
grant_valid_next = 1; | ||
grant_next = req_mask; | ||
grant_index_next = req_index; | ||
if (LSB_HIGH_PRIO) begin | ||
mask_next = {PORTS{1'b1}} << (req_index + 1); | ||
end else begin | ||
mask_next = {PORTS{1'b1}} >> ((CL_PORTS+1)'(PORTS) - req_index); | ||
end | ||
end | ||
end else begin | ||
grant_valid_next = 1'b1; | ||
grant_next = req_mask; | ||
grant_index_next = req_index; | ||
end | ||
end | ||
end | ||
|
||
always_ff @(posedge clk) begin | ||
grant_reg <= grant_next; | ||
grant_valid_reg <= grant_valid_next; | ||
grant_index_reg <= grant_index_next; | ||
mask_reg <= mask_next; | ||
|
||
if (rst) begin | ||
grant_reg <= 'd0; | ||
grant_valid_reg <= 1'b0; | ||
grant_index_reg <= 'd0; | ||
mask_reg <= 'd0; | ||
end | ||
end | ||
|
||
endmodule | ||
|
||
`resetall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# SPDX-License-Identifier: CERN-OHL-S-2.0 | ||
# | ||
# Copyright (c) 2025 FPGA Ninja, LLC | ||
# | ||
# Authors: | ||
# - Alex Forencich | ||
|
||
TOPLEVEL_LANG = verilog | ||
|
||
SIM ?= verilator | ||
WAVES ?= 0 | ||
|
||
COCOTB_HDL_TIMEUNIT = 1ns | ||
COCOTB_HDL_TIMEPRECISION = 1ps | ||
|
||
DUT = taxi_arbiter | ||
COCOTB_TEST_MODULES = test_$(DUT) | ||
COCOTB_TOPLEVEL = $(DUT) | ||
MODULE = $(COCOTB_TEST_MODULES) | ||
TOPLEVEL = $(COCOTB_TOPLEVEL) | ||
VERILOG_SOURCES += ../../../rtl/prim/$(DUT).sv | ||
VERILOG_SOURCES += ../../../rtl/prim/taxi_penc.sv | ||
|
||
# handle file list files | ||
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1))) | ||
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f)) | ||
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1)) | ||
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) | ||
|
||
# module parameters | ||
export PARAM_PORTS := 32 | ||
export PARAM_ARM_ROUND_ROBIN := "1'b1" | ||
export PARAM_ARM_BLOCK := "1'b1" | ||
export PARAM_ARM_BLOCK_ACK := "1'b0" | ||
export PARAM_LSB_HIGH_PRIO := "1'b0" | ||
|
||
ifeq ($(SIM), icarus) | ||
PLUSARGS += -fst | ||
|
||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) | ||
else ifeq ($(SIM), verilator) | ||
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) | ||
|
||
ifeq ($(WAVES), 1) | ||
COMPILE_ARGS += --trace-fst | ||
VERILATOR_TRACE = 1 | ||
endif | ||
endif | ||
|
||
include $(shell cocotb-config --makefiles)/Makefile.sim |
Oops, something went wrong.