Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
75 changes: 75 additions & 0 deletions testing/bsg_dataflow/bsg_fifo_1rw_large_random/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# This file is public domain, it can be freely copied without restrictions.
# SPDX-License-Identifier: CC0-1.0

# Cadenv Include
include /home/projects/ee478.2024spr/cadenv/cadenv_ee.mk

# CAD Tool Paths
VCS_BIN = $(VCS_HOME)/bin
VERDI_BIN = $(VERDI_HOME)/bin
VCS_BIN_DIR = $(VCS_BIN)
export PATH:=$(PATH):$(VCS_BIN):$(VERDI_BIN)

# VCS Arguments
EXTRA_ARGS += +v2k -l vcs.log
EXTRA_ARGS += -debug_pp +vcs+vcdpluson
EXTRA_ARGS += +lint=all,noSVA-UA,noSVA-NSVU,noVCDE,noNS -assert svaext
EXTRA_ARGS += -cm line+fsm+branch+cond+tgl
EXTRA_ARGS += -kdb -debug_access+all

# defaults
SIM ?= vcs
TOPLEVEL_LANG ?= verilog

# basejump_stl path
export BASEJUMP_STL_DIR = $(shell git rev-parse --show-toplevel)/../basejump_stl

# basejump_stl verilog header include path
EXTRA_ARGS += +incdir+$(BASEJUMP_STL_DIR)/bsg_misc

# basejump_stl verilog filelist
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_test/bsg_nonsynth_clock_gen.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_test/bsg_nonsynth_reset_gen.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_dataflow/bsg_fifo_1r1w_small_hardened.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_dataflow/bsg_fifo_tracker.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_misc/bsg_dff_en.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_misc/bsg_circular_ptr.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_mem/bsg_mem_1rw_sync.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_mem/bsg_mem_1rw_sync_synth.sv
VERILOG_SOURCES += $(BASEJUMP_STL_DIR)/bsg_dataflow/bsg_fifo_1rw_large.sv

# testbench verilog filelist
VERILOG_SOURCES += $(PWD)/bsg_fifo_1rw_large_wrapper.sv
VERILOG_SOURCES += $(PWD)/bsg_fifo_1rw_large_cov.sv

# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = bsg_fifo_1rw_large_wrapper

# MODULE is the basename of the Python test file
MODULE = bsg_fifo_1rw_large_testbench

# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim


# VERDI open waveform
ee-verdi:
verdi -ssf novas.fsdb &

# VERDI open coverages
ee-verdi-cov:
verdi -cov -covdir sim_build/simv.vdb &

# **DEPRECATED** DVE open waveform
ee-dve:
dve -full64 -vpd vcdplus.vpd &

# **DEPRECATED** DVE open coverages
ee-dve-cov:
dve -full64 -cov -covdir sim_build/simv.vdb &

# Clean simulation files
ee-clean:
make clean
rm -rf __pycache__ DVEfiles vcs.log vcdplus.vpd results.xml
rm -rf verdiLog vdCovLog novas.conf novas.fsdb novas.rc novas_dump.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// Davis Sauer 05/2024
//
// This module defines functional coverages of module bsg_fifo_1rw_large
//
//

`include "bsg_defines.sv"
module bsg_fifo_1rw_large_cov

#(parameter els_p = "inv"
,localparam ptr_width_lp = `BSG_SAFE_CLOG2(els_p)
)

(input clk_i
,input reset_i

// interface signals
,input v_i
,input enq_not_deq_i

// internal registers
,input [ptr_width_lp-1:0] rd_ptr // registered in sub-module bsg_circular_ptr
,input [ptr_width_lp-1:0] wr_ptr // registered in sub-module bsg_circular_ptr
,input full_o // not a register
,input empty_o // not a register
,input last_op_is_read_r
);

// reset
covergroup cg_reset @(negedge clk_i);
coverpoint reset_i;
endgroup

// Partitioning covergroup into smaller ones
// empty
covergroup cg_empty @ (negedge clk_i iff ~reset_i & empty_o & ~full_o);

cp_v: coverpoint v_i;
cp_rptr: coverpoint rd_ptr;
cp_wptr: coverpoint wr_ptr;
cp_loir: coverpoint last_op_is_read_r {illegal_bins ig = {0};} // resets to 1, and then only possible to read from cp_normal to get to cp_empty
cp_end: coverpoint enq_not_deq_i;// {illegal_bins ig = {0};} // cannot deque when empty

cross_all: cross cp_v, cp_rptr, cp_wptr, cp_loir, cp_end {
// by definition, fifo empty means r/w pointers are the same
illegal_bins ig0 = cross_all with (cp_rptr != cp_wptr);
illegal_bins ig1 = cross_all with (cp_v && !cp_end); // cannot read from empty fifo
}

endgroup

// full
covergroup cg_full @ (negedge clk_i iff ~reset_i & ~empty_o & full_o);

cp_v: coverpoint v_i;
cp_rptr: coverpoint rd_ptr;
cp_wptr: coverpoint wr_ptr;
cp_loir: coverpoint last_op_is_read_r {illegal_bins ig = {1};} // cannot fill fifo by reading
cp_end: coverpoint enq_not_deq_i;// {illegal_bins ig = {1};} // cannot write to full fifo

cross_all: cross cp_v, cp_rptr, cp_wptr, cp_loir, cp_end {
// by definition, fifo full means r/w pointers are the same
illegal_bins ig0 = cross_all with (cp_rptr != cp_wptr);

illegal_bins ig1 = cross_all with (cp_v && cp_end); // cannot write to full fifo
}

endgroup

// fifo normal
covergroup cg_normal @ (negedge clk_i iff ~reset_i & ~empty_o & ~full_o);

cp_v: coverpoint v_i;
cp_rptr: coverpoint rd_ptr;
cp_wptr: coverpoint wr_ptr;
cp_loir: coverpoint last_op_is_read_r;
cp_end: coverpoint enq_not_deq_i;

cross_all: cross cp_v, cp_rptr, cp_wptr, cp_loir, cp_end {
// by definition, r/w pointers are different when fifo is non-empty & non-full
illegal_bins ig0 = cross_all with (cp_rptr == cp_wptr);
}

endgroup

// fifo impossible (fifo cannot be both empty and full at the same time)
// covergroup cg_impossible @ (negedge clk_i iff ~reset_i & empty & full);

// create cover groups
cg_reset cov_reset = new;
cg_empty cov_empty = new;
cg_full cov_full = new;
cg_normal cov_normal = new;

// print coverages when simulation is done
final
begin
$display("");
$display("Instance: %m");
$display("---------------------- Functional Coverage Results ----------------------");
$display("Reset functional coverage is %f%%", cov_reset.get_coverage());
$display("Fifo empty functional coverage is %f%%", cov_empty.cross_all.get_coverage());
$display("Fifo full functional coverage is %f%%", cov_full.cross_all.get_coverage());
$display("Fifo normal functional coverage is %f%%", cov_normal.cross_all.get_coverage());
$display("-------------------------------------------------------------------------");
$display("");
end

endmodule
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Davis Sauer
# 05/2024

# Import python libraries
import math
import time
import random

# Import cocotb libraries
import cocotb
from cocotb.clock import Clock, Timer
from cocotb.triggers import RisingEdge, FallingEdge, Timer


# Data width, matching width_p parameter in DUT
WIDTH_P = 16

# Testbench iterations
ITERATION = 1000

# Flow control random seed
# Use different seeds on input and output sides for more randomness
CTRL_INPUT_SEED = 1
CTRL_OUTPUT_SEED = 2

# Testbench clock period
CLK_PERIOD = 10


async def input_side_testbench(dut, seed):
"""Handle input traffic"""

# Create local random generator for data generation
data_random = random.Random()
data_random.seed(seed)

# Create control random generator for flow control
control_random = random.Random()
control_random.seed(CTRL_INPUT_SEED)

# Initialize DUT interface values
dut.v_i.value = 0
dut.data_i.value = 0
dut.enq_not_deq_i.value = 1

# Wait for reset deassertion
while 1:
await RisingEdge(dut.clk_i); await Timer(1, units="ps")
if dut.reset_i == 0: break

# Main iterations
i = 0
data = []
data_idx = 0
while 1:
await RisingEdge(dut.clk_i); await Timer(1, units="ps")
rng = control_random.random()
if dut.full_o.value == 0 and rng >= 0.5: # write
# Assert DUT valid signal
dut.v_i.setimmediatevalue(1)
dut.enq_not_deq_i.setimmediatevalue(1)
# Generate send data
value = math.floor(data_random.random()*pow(2, WIDTH_P))
data.append(value)
dut.data_i.setimmediatevalue(value)
await RisingEdge(dut.clk_i); await Timer(1, units="ps")
# Deassert DUT signals
dut.v_i.setimmediatevalue(0)
dut.enq_not_deq_i.setimmediatevalue(value > pow(2, WIDTH_P)/2)
# iteration increment
i += 1
# Check iteration
if i == ITERATION:
# Test finished
break
elif dut.empty_o.value == 0: # read
# Assert DUT signals
dut.v_i.setimmediatevalue(1)
dut.enq_not_deq_i.setimmediatevalue(0)
await RisingEdge(dut.clk_i); await Timer(1, units="ps")
assert dut.data_o.value == data[data_idx], "data mismatch!"
# Deassert DUT signals
dut.v_i.setimmediatevalue(0)
dut.enq_not_deq_i.setimmediatevalue(data[data_idx] > pow(2, WIDTH_P)/2)
data_idx += 1
else: # do nothing
await RisingEdge(dut.clk_i); await Timer(1, units="ps")

await RisingEdge(dut.clk_i); await Timer(1, units="ps")

# Deassert DUT valid signal
dut.v_i.value = 0

@cocotb.test()
async def testbench(dut):
"""Try accessing the design."""

# Random seed assignment
seed = "fifo"

# Create a 10ps period clock on DUT port clk_i
clock = Clock(dut.clk_i, CLK_PERIOD, units="ps")

# Start the clock. Start it low to avoid issues on the first RisingEdge
clock_thread = cocotb.start_soon(clock.start(start_high=False))

# Launch input and output testbench threads
input_thread = cocotb.start_soon(input_side_testbench(dut, seed))

# Reset initialization
dut.reset_i.value = 1

# Wait for 5 clock cycles
await Timer(CLK_PERIOD*5, units="ps")
await RisingEdge(dut.clk_i); await Timer(1, units="ps")

# Deassert reset
dut.reset_i.value = 0

# Wait for threads to finish
await input_thread

# Wait for 5 clock cycles
await Timer(CLK_PERIOD*5, units="ps")
await RisingEdge(dut.clk_i); await Timer(1, units="ps")

# Assert reset
dut.reset_i.value = 1

# Wait for 5 clock cycles
await Timer(CLK_PERIOD*5, units="ps")

# Test finished!
dut._log.info("Test finished! Current reset_i value = %s", dut.reset_i.value)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

module bsg_fifo_1rw_large_wrapper #(parameter width_p = 16
, parameter els_p = 8
)
( input clk_i
, input reset_i

, input v_i
, input [width_p-1:0] data_i
, input enq_not_deq_i

, output full_o
, output empty_o
, output [width_p-1:0] data_o
);

// Instantiate DUT
bsg_fifo_1rw_large #(.width_p(width_p)
,.els_p(els_p)
) fifo
(.*);

// Bind Covergroups
bind bsg_fifo_1rw_large bsg_fifo_1rw_large_cov
#(.els_p(els_p)
) pc_cov
(.*
);

// Dump Waveforms
initial begin
$fsdbDumpvars;
end

endmodule