├── FIFO ├── src │ ├── rtl_list.f │ └── fifo.sv ├── vip │ ├── pyuvm │ │ └── README.md │ └── uvm │ │ ├── agent │ │ ├── fifo_vip_sequencer.sv │ │ ├── fifo_vip_agent.sv │ │ ├── fifo_vip_monitor.sv │ │ └── fifo_vip_driver.sv │ │ ├── sequences │ │ ├── fifo_vip_base_seq.sv │ │ ├── fifo_vip_read_req_seq.sv │ │ └── fifo_vip_write_req_seq.sv │ │ ├── interface │ │ └── fifo_vip_if.sv │ │ ├── common │ │ ├── fifo_vip_config.sv │ │ ├── fifo_vip_pkg.sv │ │ └── fifo_vip_seq_item.sv │ │ ├── sim │ │ ├── tests │ │ │ ├── fifo_vip_simple_test.sv │ │ │ └── fifo_vip_base_test.sv │ │ └── tb_top.sv │ │ ├── env │ │ ├── fifo_vip_env.sv │ │ └── fifo_vip_scoreboard.sv │ │ └── README.md ├── tb │ ├── sv │ │ ├── Makefile │ │ └── tb.sv │ └── cocotb │ │ ├── Makefile │ │ └── tb.py └── README.md ├── LIFO ├── src │ ├── rtl_list.f │ └── lifo.sv ├── tb │ ├── sv │ │ ├── Makefile │ │ └── tb.sv │ └── cocotb │ │ ├── Makefile │ │ └── tb.py └── README.md ├── Systolic_Array ├── tb │ └── sv │ │ └── tb.sv ├── src │ ├── rtl_list.f │ └── systolic_array_top.sv └── README.md ├── Table ├── src │ ├── rtl_file.f │ └── table.sv ├── tb │ ├── sv │ │ ├── Makefile │ │ └── tb.sv │ └── cocotb │ │ ├── Makefile │ │ └── tb.py └── README.md ├── Hash_Table ├── src │ ├── rtl_list.f │ └── hash_table.sv ├── tb │ ├── sv │ │ └── Makefile │ └── cocotb │ │ ├── Makefile │ │ └── tb.py └── README.md ├── Dual_Edge_FF ├── src │ ├── rtl_list.f │ └── dual_edge_ff.sv ├── tb │ ├── cocotb │ │ ├── Makefile │ │ └── tb.py │ └── sv │ │ ├── Makefile │ │ └── tb.sv └── README.md ├── List ├── src │ ├── rtl_src.f │ ├── adder.sv │ └── sorter.sv ├── tb │ ├── cocotb │ │ └── Makefile │ └── sv │ │ └── Makefile └── README.md ├── Doubly_Linked_List ├── src │ └── rtl_list.f ├── tb │ ├── sv │ │ └── Makefile │ └── cocotb │ │ └── Makefile └── README.md ├── Singly_Linked_List ├── src │ └── rtl_file.f ├── tb │ ├── sv │ │ └── Makefile │ └── cocotb │ │ └── Makefile └── README.md ├── assets └── RTLStructLib_logo.png ├── .gitignore ├── LICENSE ├── Utils └── tb │ ├── cocotb │ └── Makefile │ └── sv │ └── Makefile └── README.md /FIFO/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | fifo.sv 2 | -------------------------------------------------------------------------------- /LIFO/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | lifo.sv 2 | -------------------------------------------------------------------------------- /Systolic_Array/tb/sv/tb.sv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Table/src/rtl_file.f: -------------------------------------------------------------------------------- 1 | table.sv 2 | -------------------------------------------------------------------------------- /Hash_Table/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | hash_table.sv 2 | -------------------------------------------------------------------------------- /Dual_Edge_FF/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | dual_edge_ff.sv 2 | -------------------------------------------------------------------------------- /FIFO/vip/pyuvm/README.md: -------------------------------------------------------------------------------- 1 | Development in Progress 2 | -------------------------------------------------------------------------------- /Systolic_Array/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | systolic_array_top.sv -------------------------------------------------------------------------------- /List/src/rtl_src.f: -------------------------------------------------------------------------------- 1 | list.sv 2 | sorter.sv 3 | adder.sv -------------------------------------------------------------------------------- /Systolic_Array/README.md: -------------------------------------------------------------------------------- 1 | # Development In Progress! 2 | -------------------------------------------------------------------------------- /Doubly_Linked_List/src/rtl_list.f: -------------------------------------------------------------------------------- 1 | doubly_linked_list.sv 2 | -------------------------------------------------------------------------------- /Singly_Linked_List/src/rtl_file.f: -------------------------------------------------------------------------------- 1 | singly_linked_list.sv 2 | -------------------------------------------------------------------------------- /assets/RTLStructLib_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weiyet/RTLStructLib/HEAD/assets/RTLStructLib_logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore simulation files 2 | *.log 3 | *.vcd 4 | *.sim 5 | XilinxUnisimLibrary 6 | *netlist.v 7 | __pycache__ 8 | iverilog_dump.v 9 | results.xml 10 | sim_build -------------------------------------------------------------------------------- /FIFO/vip/uvm/agent/fifo_vip_sequencer.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:25 PM 5 | // Module Name: fifo_vip_sequencer 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains all the components of the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | class fifo_vip_sequencer extends uvm_sequencer #(fifo_vip_seq_item); 13 | `uvm_component_utils(fifo_vip_sequencer) 14 | 15 | function new(string name = "fifo_vip_sequencer", uvm_component parent = null); 16 | super.new(name, parent); 17 | endfunction 18 | 19 | endclass -------------------------------------------------------------------------------- /Systolic_Array/src/systolic_array_top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Create Date: 07/29/2025 08:48:20 PM 5 | // Design Name: 6 | // Module Name: systolic_array_top 7 | // Project Name: 8 | // Target Devices: 9 | // Tool Versions: 10 | // Description: 11 | // 12 | // Dependencies: 13 | // 14 | // Revision: 15 | // Revision 0.01 - File Created 16 | // Additional Comments: 17 | // 18 | ////////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | module systolic_array_top #( 22 | parameter LEFT_MATRIX_ROW = 50, 23 | parameter INNER_DIMENSION = 50, 24 | parameter RIGHT_MATRIX_COL = 50, 25 | parameter DATA_WIDTH = 8 26 | )( 27 | ); 28 | endmodule 29 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/sequences/fifo_vip_base_seq.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:27 PM 5 | // Module Name: fifo_vip_base_seq 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This sequence serves as a base class for FIFO VIP sequences. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_base_seq extends uvm_sequence #(fifo_vip_seq_item); 12 | `uvm_object_utils(fifo_vip_base_seq) 13 | 14 | fifo_vip_config cfg; 15 | 16 | function new(string name = "fifo_vip_base_seq"); 17 | super.new(name); 18 | endfunction 19 | 20 | task pre_body(); 21 | if (!uvm_config_db#(fifo_vip_config)::get(m_sequencer, "", "fifo_vip_cfg", cfg)) begin 22 | `uvm_warning("SEQ", "No config found") 23 | end 24 | endtask 25 | 26 | endclass -------------------------------------------------------------------------------- /LIFO/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DUT = lifo 3 | SIM_OPTS ?= ../../src/lifo.sv 4 | SEED ?= $$(shuf -i 1-10000 -n 1) 5 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 6 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 7 | 8 | sim: gen_sim 9 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 10 | 11 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 12 | iverilog -g2012 -s tb -o ${DUT}.sim $^ 13 | 14 | synth: ${SIM_OPTS} 15 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 16 | #timeout 17 | 18 | netlist_sim: gen_netlist_sim 19 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 20 | 21 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 22 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS -o ${DUT}.netlist.sim $^ 23 | 24 | ${XILINX_LIBS_DIR}/.git: 25 | git clone ${XILINX_LIB_URL} 26 | 27 | clean: 28 | rm -f ${DUT}_sim sim.log sim.vcd 29 | rm -f ${DUT}.netlist.v synth.log 30 | -------------------------------------------------------------------------------- /FIFO/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | DUT = fifo 2 | SIM_OPTS ?= ../../src/fifo.sv 3 | SEED ?= $$(shuf -i 1-10000 -n 1) 4 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 5 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 6 | 7 | sim: gen_sim 8 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 9 | 10 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 11 | iverilog -g2012 -s tb -o ${DUT}.sim $^ 12 | 13 | synth: ${SIM_OPTS} 14 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 15 | #timeout 16 | 17 | netlist_sim: gen_netlist_sim 18 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 19 | 20 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIB_DIR}/.git 21 | iverilog -g2012 -DXILINX_GLS -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS -o ${DUT}.netlist.sim tb.sv ${DUT}.netlist.v 22 | 23 | ${XILINX_LIB_DIR}/.git: 24 | git clone ${XILINX_LIB_URL} 25 | 26 | clean: 27 | rm -f ${DUT}_sim sim.log sim.vcd 28 | rm -f ${DUT}.netlist.v synth.log 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [Wei Yet Ng] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/interface/fifo_vip_if.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:28 PM 5 | // Module Name: fifo_vip_if 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the FIFO VIP interface. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | interface fifo_vip_if(input logic wr_clk, input logic rd_clk); 13 | 14 | // Signals matching your FIFO 15 | logic rst; 16 | logic [7:0] data_wr; 17 | logic wr_en; 18 | logic fifo_full; 19 | logic [7:0] data_rd; 20 | logic rd_en; 21 | logic fifo_empty; 22 | 23 | // Simple clocking blocks 24 | clocking wr_cb @(posedge wr_clk); 25 | output data_wr, wr_en; 26 | input fifo_full; 27 | endclocking 28 | 29 | clocking rd_cb @(posedge rd_clk); 30 | output rd_en; 31 | input data_rd, fifo_empty; 32 | endclocking 33 | 34 | // Modports 35 | modport wr_drv (clocking wr_cb, input rst); 36 | modport rd_drv (clocking rd_cb, input rst); 37 | 38 | endinterface -------------------------------------------------------------------------------- /FIFO/vip/uvm/sequences/fifo_vip_read_req_seq.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:04 PM 5 | // Module Name: fifo_vip_read_req_seq 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This sequence generates read requests for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_read_req_seq extends fifo_vip_base_seq; 12 | `uvm_object_utils(fifo_vip_read_req_seq) 13 | 14 | rand int num_reads; 15 | 16 | constraint num_reads_c { 17 | num_reads inside {[1:20]}; 18 | } 19 | 20 | function new(string name = "fifo_vip_read_req_seq"); 21 | super.new(name); 22 | endfunction 23 | 24 | task body(); 25 | fifo_vip_seq_item item; 26 | 27 | `uvm_info("RD_SEQ", $sformatf("Starting %0d reads", num_reads), UVM_MEDIUM) 28 | 29 | repeat(num_reads) begin 30 | item = fifo_vip_seq_item::type_id::create("item"); 31 | start_item(item); 32 | assert(item.randomize() with {op == READ;}); 33 | finish_item(item); 34 | end 35 | endtask 36 | 37 | endclass -------------------------------------------------------------------------------- /FIFO/vip/uvm/sequences/fifo_vip_write_req_seq.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:25 PM 5 | // Module Name: fifo_vip_write_req_seq 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This sequence generates write requests for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | class fifo_vip_write_req_seq extends fifo_vip_base_seq; 13 | `uvm_object_utils(fifo_vip_write_req_seq) 14 | 15 | rand int num_writes; 16 | 17 | constraint num_writes_c { 18 | num_writes inside {[1:20]}; 19 | } 20 | 21 | function new(string name = "fifo_vip_write_req_seq"); 22 | super.new(name); 23 | endfunction 24 | 25 | task body(); 26 | fifo_vip_seq_item item; 27 | 28 | `uvm_info("WR_SEQ", $sformatf("Starting %0d writes", num_writes), UVM_MEDIUM) 29 | 30 | repeat(num_writes) begin 31 | item = fifo_vip_seq_item::type_id::create("item"); 32 | start_item(item); 33 | assert(item.randomize() with {op == WRITE;}); 34 | finish_item(item); 35 | end 36 | endtask 37 | 38 | endclass -------------------------------------------------------------------------------- /FIFO/vip/uvm/common/fifo_vip_config.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 08:41 PM 5 | // Module Name: fifo_vip_config 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the configuration class for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_config extends uvm_object; 12 | `uvm_object_utils(fifo_vip_config) 13 | 14 | // DUT parameters - CHANGE THESE FOR YOUR FIFO 15 | int DEPTH = 12; 16 | int DATA_WIDTH = 8; 17 | bit ASYNC = 1; 18 | bit RD_BUFFER = 1; 19 | 20 | // VIP control 21 | bit has_wr_agent = 1; 22 | bit has_rd_agent = 1; 23 | bit enable_scoreboard = 1; 24 | 25 | // Agent modes 26 | fifo_agent_mode_e wr_agent_mode = MASTER; 27 | fifo_agent_mode_e rd_agent_mode = MASTER; 28 | 29 | function new(string name = "fifo_vip_config"); 30 | super.new(name); 31 | endfunction 32 | 33 | function void print_config(); 34 | `uvm_info("CFG", $sformatf("DEPTH=%0d, DATA_WIDTH=%0d, ASYNC=%0b, RD_BUFFER=%0b", 35 | DEPTH, DATA_WIDTH, ASYNC, RD_BUFFER), UVM_LOW) 36 | endfunction 37 | 38 | endclass -------------------------------------------------------------------------------- /Table/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DUT ?= table_top 3 | SIM_OPTS ?= ../../src/table.sv 4 | SEED ?= $$(shuf -i 1-10000 -n 1) 5 | 6 | # DUT parameter #"-p" iverilog command flags 7 | COMPILE_ARGS = -P tb.TABLE_SIZE=32 8 | COMPILE_ARGS += -P tb.DATA_WIDTH=8 9 | COMPILE_ARGS += -P tb.INPUT_RATE=2 10 | COMPILE_ARGS += -P tb.OUTPUT_RATE=2 11 | COMPILE_ARGS += -P tb.TB_CLK_PERIOD=100 12 | COMPILE_ARGS += -P tb.TB_TEST_WEIGHT=1 13 | COMPILE_ARGS += -P tb.TB_SIM_TIMEOUT=30 #//ms. 14 | 15 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 16 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 17 | 18 | sim: gen_sim 19 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 20 | 21 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 22 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 23 | 24 | synth: ${SIM_OPTS} 25 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 26 | #timeout 27 | 28 | netlist_sim: gen_netlist_sim 29 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 30 | 31 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 32 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 33 | 34 | ${XILINX_LIBS_DIR}/.git: 35 | git clone ${XILINX_LIB_URL} 36 | 37 | clean: 38 | rm -f ${DUT}_sim sim.log sim.vcd 39 | rm -f ${DUT}.netlist.v synth.log 40 | -------------------------------------------------------------------------------- /Doubly_Linked_List/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DUT ?= doubly_linked_list 3 | SIM_OPTS ?= ../../src/doubly_linked_list.sv 4 | SEED ?= $$(shuf -i 1-10000 -n 1) 5 | 6 | # DUT parameter #"-p" iverilog command flags 7 | # COMPILE_ARGS = -P tb.DUT_DATA_WIDTH=8 8 | # COMPILE_ARGS += -P tb.DUT_MAX_NODE=8 9 | # COMPILE_ARGS += -P tb.TB_CLK_PERIOD=25 10 | # COMPILE_ARGS += -P tb.TB_TEST_WEIGHT=1 11 | # COMPILE_ARGS += -P tb.TB_CLK_PERIOD=100 12 | # COMPILE_ARGS += -P tb.SIM_TIMEOUT=500000 13 | 14 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 15 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 16 | 17 | sim: gen_sim 18 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 19 | 20 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 21 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 22 | 23 | synth: ${SIM_OPTS} 24 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 25 | #timeout 26 | 27 | netlist_sim: gen_netlist_sim 28 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 29 | 30 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.got 31 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 32 | 33 | ${XILINX_LIBS_DIR}/.git: 34 | git clone ${XILINX_LIB_URL} 35 | 36 | clean: 37 | rm -f ${DUT}_sim sim.log sim.vcd 38 | rm -f ${DUT}.netlist.v synth.log 39 | -------------------------------------------------------------------------------- /Singly_Linked_List/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DUT ?= singly_linked_list 3 | SIM_OPTS ?= ../../src/singly_linked_list.sv 4 | SEED ?= $$(shuf -i 1-10000 -n 1) 5 | 6 | # DUT parameter #"-p" iverilog command flags 7 | # COMPILE_ARGS = -P tb.DUT_DATA_WIDTH=8 8 | # COMPILE_ARGS += -P tb.DUT_MAX_NODE=8 9 | # COMPILE_ARGS += -P tb.TB_CLK_PERIOD=25 10 | # COMPILE_ARGS += -P tb.TB_TEST_WEIGHT=1 11 | # COMPILE_ARGS += -P tb.TB_CLK_PERIOD=100 12 | # COMPILE_ARGS += -P tb.SIM_TIMEOUT=500000 13 | 14 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 15 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 16 | 17 | sim: gen_sim 18 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 19 | 20 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 21 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 22 | 23 | synth: ${SIM_OPTS} 24 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 25 | #timeout 26 | 27 | netlist_sim: gen_netlist_sim 28 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 29 | 30 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 31 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 32 | 33 | ${XILINX_LIBS_DIR}/.git: 34 | git clone ${XILINX_LIB_URL} 35 | 36 | clean: 37 | rm -f ${DUT}_sim sim.log sim.vcd 38 | rm -f ${DUT}.netlist.v synth.log 39 | -------------------------------------------------------------------------------- /List/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | SRC_DIR ?= $(PWD)/../../src 9 | VERILOG_SOURCES ?= $(addprefix $(SRC_DIR)/, $(shell cat $(SRC_DIR)/rtl_src.f)) 10 | 11 | 12 | # DUT Top 13 | TOPLEVEL = list 14 | # top python file name 15 | MODULE = tb 16 | 17 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 18 | #TESTCASE = index_op_test , addr_op_test 19 | 20 | COMPILE_ARGS ?= -P list.DATA_WIDTH=8 21 | COMPILE_ARGS += -P list.LENGTH=8 22 | COMPILE_ARGS += -P list.SUM_METHOD=0 23 | #"-P" (parameter) iverilog command flags 24 | #run make clean before running with new parameter. 25 | 26 | #Set RANDOM_SEED number 27 | #PLUSARGS = +seed=1716033254 28 | COCOTB_HDL_TIMEUNIT = 1ns 29 | COCOTB_HDL_TIMEPRECISION = 1ps 30 | 31 | ifeq ($(SIM), icarus) 32 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 33 | $(shell echo 'initial begin' >> iverilog_dump.v) 34 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 35 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 36 | $(shell echo 'end' >> iverilog_dump.v) 37 | $(shell echo 'endmodule' >> iverilog_dump.v) 38 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 39 | COMPILE_ARGS += -s iverilog_dump 40 | endif 41 | 42 | include $(shell cocotb-config --makefiles)/Makefile.sim 43 | 44 | 45 | -------------------------------------------------------------------------------- /Doubly_Linked_List/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/doubly_linked_list.sv 10 | 11 | # DUT Top 12 | TOPLEVEL = doubly_linked_list 13 | # top python file name 14 | MODULE = tb 15 | 16 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 17 | #TESTCASE = index_op_test , addr_op_test 18 | 19 | COMPILE_ARGS = -Ptable_top.DATA_WIDTH=8 # DUT parameter #"-p" (parameter) iverilog command flags 20 | COMPILE_ARGS += -Ptable_top.MAX_NODE=8 # DUT parameter #"-p" (parameter) iverilog command flags 21 | #run make clean before running with new parameter. 22 | 23 | #Set RANDOM_SEED number 24 | #PLUSARGS = +seed=1716033254 25 | COCOTB_HDL_TIMEUNIT = 1ns 26 | COCOTB_HDL_TIMEPRECISION = 1ps 27 | 28 | ifeq ($(SIM), icarus) 29 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 30 | $(shell echo 'initial begin' >> iverilog_dump.v) 31 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 32 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 33 | $(shell echo 'end' >> iverilog_dump.v) 34 | $(shell echo 'endmodule' >> iverilog_dump.v) 35 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 36 | COMPILE_ARGS += -s iverilog_dump 37 | endif 38 | 39 | include $(shell cocotb-config --makefiles)/Makefile.sim 40 | 41 | 42 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/sim/tests/fifo_vip_simple_test.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 10:04 PM 5 | // Module Name: fifo_vip_base_test 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the base test for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class simple_test extends base_test; 12 | `uvm_component_utils(simple_test) 13 | 14 | function new(string name = "simple_test", uvm_component parent = null); 15 | super.new(name, parent); 16 | endfunction 17 | 18 | task run_phase(uvm_phase phase); 19 | fifo_vip_write_req_seq wr_seq; 20 | fifo_vip_read_req_seq rd_seq; 21 | 22 | phase.raise_objection(this); 23 | 24 | // Write some data 25 | wr_seq = fifo_vip_write_req_seq::type_id::create("wr_seq"); 26 | wr_seq.num_writes = 8; 27 | wr_seq.start(env.get_wr_sequencer()); 28 | 29 | #200ns; 30 | 31 | // Read it back 32 | rd_seq = fifo_vip_read_req_seq::type_id::create("rd_seq"); 33 | rd_seq.num_reads = 8; 34 | rd_seq.start(env.get_rd_sequencer()); 35 | 36 | #200ns; 37 | phase.drop_objection(this); 38 | endtask 39 | 40 | endclass -------------------------------------------------------------------------------- /LIFO/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/lifo.sv 10 | 11 | # DUT Top 12 | TOPLEVEL = lifo 13 | # top python file 14 | MODULE = tb 15 | 16 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 17 | #TESTCASE = lifo_rand_op_test 18 | TESTCASE = lifo_rand_op_test 19 | 20 | COMPILE_ARGS = -Plifo.DEPTH=12 # DUT parameter #"-p" iverilog command flags 21 | COMPILE_ARGS += -Plifo.DATA_WIDTH=8 # DUT parameter #"-p" iverilog command flags 22 | #run make clean before running with new parameter. 23 | 24 | #Set RANDOM_SEED number 25 | #PLUSARGS = +seed=1716033254 26 | COCOTB_HDL_TIMEUNIT = 1ns 27 | COCOTB_HDL_TIMEPRECISION = 1ps 28 | 29 | ifeq ($(SIM), icarus) 30 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 31 | $(shell echo 'initial begin' >> iverilog_dump.v) 32 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 33 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 34 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 35 | $(shell echo 'end' >> iverilog_dump.v) 36 | $(shell echo 'endmodule' >> iverilog_dump.v) 37 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 38 | COMPILE_ARGS += -s iverilog_dump 39 | endif 40 | 41 | include $(shell cocotb-config --makefiles)/Makefile.sim 42 | 43 | 44 | -------------------------------------------------------------------------------- /Singly_Linked_List/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/singly_linked_list.sv 10 | 11 | # DUT Top 12 | TOPLEVEL = singly_linked_list 13 | # top python file name 14 | MODULE = tb 15 | 16 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 17 | #TESTCASE = direct_index_op_test , direct_addr_op_test 18 | 19 | COMPILE_ARGS = -Ptable_top.DATA_WIDTH=8 # DUT parameter #"-p" (parameter) iverilog command flags 20 | COMPILE_ARGS += -Ptable_top.MAX_NODE=8 # DUT parameter #"-p" (parameter) iverilog command flags 21 | #run make clean before running with new parameter. 22 | 23 | #Set RANDOM_SEED number 24 | #PLUSARGS = +seed=1716033254 25 | COCOTB_HDL_TIMEUNIT = 1ns 26 | COCOTB_HDL_TIMEPRECISION = 1ps 27 | 28 | ifeq ($(SIM), icarus) 29 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 30 | $(shell echo 'initial begin' >> iverilog_dump.v) 31 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 32 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 33 | $(shell echo 'end' >> iverilog_dump.v) 34 | $(shell echo 'endmodule' >> iverilog_dump.v) 35 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 36 | COMPILE_ARGS += -s iverilog_dump 37 | endif 38 | 39 | include $(shell cocotb-config --makefiles)/Makefile.sim 40 | 41 | 42 | -------------------------------------------------------------------------------- /Dual_Edge_FF/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | SRC_DIR = ../../src 10 | VERILOG_SOURCES = $(addprefix $(SRC_DIR)/, $(shell cat ../../src/rtl_list.f)) 11 | 12 | # DUT Top 13 | TOPLEVEL = dual_edge_ff 14 | # top python file name 15 | MODULE = tb 16 | 17 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 18 | TESTCASE = direct_test 19 | 20 | COMPILE_ARGS = -Pdual_edge_ff.DATA_WIDTH=8 # DUT parameter #"-p" (parameter) iverilog command flags 21 | COMPILE_ARGS += -Pdual_edge_ff.RESET_VALUE=0 # DUT parameter #"-p" (parameter) iverilog command flags 22 | #run make clean before running with new parameter. 23 | 24 | #Set RANDOM_SEED number 25 | #PLUSARGS = +seed=1716033254 26 | COCOTB_HDL_TIMEUNIT = 1ns 27 | COCOTB_HDL_TIMEPRECISION = 1ps 28 | 29 | ifeq ($(SIM), icarus) 30 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 31 | $(shell echo 'initial begin' >> iverilog_dump.v) 32 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 33 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 34 | $(shell echo 'end' >> iverilog_dump.v) 35 | $(shell echo 'endmodule' >> iverilog_dump.v) 36 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 37 | COMPILE_ARGS += -s iverilog_dump 38 | endif 39 | 40 | include $(shell cocotb-config --makefiles)/Makefile.sim 41 | 42 | 43 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/common/fifo_vip_pkg.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 10:37 PM 5 | // Module Name: fifo_vip_pkg 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains all the components of the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | package fifo_vip_pkg; 12 | 13 | import uvm_pkg::*; 14 | `include "uvm_macros.svh" 15 | 16 | // Types and enums defined directly in package 17 | typedef enum { 18 | WRITE, 19 | READ, 20 | IDLE 21 | } fifo_op_e; 22 | 23 | typedef enum { 24 | MASTER, 25 | SLAVE, 26 | MONITOR_ONLY 27 | } fifo_agent_mode_e; 28 | 29 | // Include files in order 30 | `include "../src/fifo_vip_config.sv" 31 | `include "../src/fifo_vip_seq_item.sv" 32 | `include "../agent/fifo_vip_driver.sv" 33 | `include "../agent/fifo_vip_monitor.sv" 34 | `include "../agent/fifo_vip_sequencer.sv" 35 | `include "../agent/fifo_vip_agent.sv" 36 | `include "../env/fifo_vip_scoreboard.sv" 37 | `include "../env/fifo_vip_env.sv" 38 | `include "../sequences/fifo_vip_base_seq.sv" 39 | `include "../sequences/fifo_vip_write_req_seq.sv" 40 | `include "../sequences/fifo_vip_read_req_seq.sv" 41 | 42 | endpackage -------------------------------------------------------------------------------- /FIFO/vip/uvm/common/fifo_vip_seq_item.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 08:37 PM 5 | // Module Name: fifo_vip_seq_item 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the sequence item for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_seq_item extends uvm_sequence_item; 12 | `uvm_object_utils(fifo_vip_seq_item) 13 | 14 | // Transaction fields 15 | rand fifo_op_e op; 16 | rand bit [31:0] data; 17 | 18 | // Response fields 19 | bit [31:0] read_data; 20 | bit full; 21 | bit empty; 22 | bit success; 23 | 24 | // Config reference 25 | fifo_vip_config cfg; 26 | 27 | // Simple constraints 28 | constraint op_dist { 29 | op dist {WRITE := 50, READ := 50}; 30 | } 31 | 32 | constraint data_c { 33 | if (cfg != null) { 34 | data < (1 << cfg.DATA_WIDTH); 35 | } else { 36 | data < 256; // 8-bit default 37 | } 38 | } 39 | 40 | function new(string name = "fifo_vip_seq_item"); 41 | super.new(name); 42 | success = 1; 43 | endfunction 44 | 45 | function string convert2string(); 46 | return $sformatf("Op:%s Data:0x%0h ReadData:0x%0h Full:%0b Empty:%0b Success:%0b", 47 | op.name(), data, read_data, full, empty, success); 48 | endfunction 49 | 50 | endclass -------------------------------------------------------------------------------- /FIFO/vip/uvm/sim/tests/fifo_vip_base_test.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 10:04 PM 5 | // Module Name: fifo_vip_base_test 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the base test for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class base_test extends uvm_test; 12 | `uvm_component_utils(base_test) 13 | 14 | fifo_vip_env env; 15 | fifo_vip_config cfg; 16 | 17 | function new(string name = "base_test", uvm_component parent = null); 18 | super.new(name, parent); 19 | endfunction 20 | 21 | function void build_phase(uvm_phase phase); 22 | super.build_phase(phase); 23 | 24 | // Create config - MODIFY FOR YOUR FIFO 25 | cfg = fifo_vip_config::type_id::create("cfg"); 26 | cfg.DEPTH = 12; // Change this 27 | cfg.DATA_WIDTH = 8; // Change this 28 | cfg.ASYNC = 1; // Change this 29 | cfg.RD_BUFFER = 1; // Change this 30 | 31 | // Set config in database with better field name 32 | uvm_config_db#(fifo_vip_config)::set(this, "*", "fifo_vip_cfg", cfg); 33 | 34 | env = fifo_vip_env::type_id::create("env", this); 35 | endfunction 36 | 37 | function void end_of_elaboration_phase(uvm_phase phase); 38 | cfg.print_config(); 39 | uvm_top.print_topology(); 40 | endfunction 41 | 42 | endclass -------------------------------------------------------------------------------- /Table/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/table.sv 10 | 11 | # DUT Top 12 | TOPLEVEL = table_top 13 | # top python file name 14 | MODULE = tb 15 | 16 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 17 | #TESTCASE = lifo_rand_op_test 18 | TESTCASE = table_rand_test 19 | 20 | COMPILE_ARGS = -Ptable_top.TABLE_SIZE=32 # DUT parameter #"-p" (parameter) iverilog command flags 21 | COMPILE_ARGS += -Ptable_top.DATA_WIDTH=8 # DUT parameter #"-p" (parameter) iverilog command flags 22 | COMPILE_ARGS += -Ptable_top.INPUT_RATE=1 # DUT parameter #"-p" (parameter) iverilog command flags 23 | COMPILE_ARGS += -Ptable_top.OUTPUT_RATE=1 # DUT parameter #"-p" (parameter) iverilog command flags 24 | #run make clean before running with new parameter. 25 | 26 | #Set RANDOM_SEED number 27 | #PLUSARGS = +seed=1716033254 28 | COCOTB_HDL_TIMEUNIT = 1ns 29 | COCOTB_HDL_TIMEPRECISION = 1ps 30 | 31 | ifeq ($(SIM), icarus) 32 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 33 | $(shell echo 'initial begin' >> iverilog_dump.v) 34 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 35 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 36 | $(shell echo 'end' >> iverilog_dump.v) 37 | $(shell echo 'endmodule' >> iverilog_dump.v) 38 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 39 | COMPILE_ARGS += -s iverilog_dump 40 | endif 41 | 42 | include $(shell cocotb-config --makefiles)/Makefile.sim 43 | 44 | 45 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/agent/fifo_vip_agent.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 08:57 PM 5 | // Module Name: fifo_vip_agent 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the FIFO VIP agent. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_agent extends uvm_agent; 12 | `uvm_component_utils(fifo_vip_agent) 13 | 14 | fifo_vip_driver driver; 15 | fifo_vip_monitor monitor; 16 | fifo_vip_sequencer sequencer; 17 | 18 | uvm_analysis_port #(fifo_vip_seq_item) ap; 19 | 20 | function new(string name = "fifo_vip_agent", uvm_component parent = null); 21 | super.new(name, parent); 22 | endfunction 23 | 24 | function void build_phase(uvm_phase phase); 25 | super.build_phase(phase); 26 | 27 | monitor = fifo_vip_monitor::type_id::create("monitor", this); 28 | 29 | if (is_active == UVM_ACTIVE) begin 30 | driver = fifo_vip_driver::type_id::create("driver", this); 31 | sequencer = fifo_vip_sequencer::type_id::create("sequencer", this); 32 | end 33 | endfunction 34 | 35 | function void connect_phase(uvm_phase phase); 36 | super.connect_phase(phase); 37 | 38 | ap = monitor.ap; 39 | 40 | if (is_active == UVM_ACTIVE) begin 41 | driver.seq_item_port.connect(sequencer.seq_item_export); 42 | end 43 | endfunction 44 | 45 | endclass -------------------------------------------------------------------------------- /Utils/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | SRC_DIR ?= $(PWD)/../../src 9 | VERILOG_SOURCES ?= $(addprefix $(SRC_DIR)/, $(shell cat $(SRC_DIR)/rtl_list.f)) 10 | 11 | 12 | # DUT Top 13 | TOPLEVEL = list 14 | # top python file name 15 | MODULE = tb 16 | 17 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 18 | #TESTCASE = index_op_test , addr_op_test 19 | 20 | # FIXME : Edit this to match your DUT parameters 21 | # COMPILE_ARGS ?= -P DUT_DATA_WIDTH=8 22 | # COMPILE_ARGS += -P DUT_LENGTH=8 23 | # COMPILE_ARGS += -P DUT_SUM_METHOD=0 24 | COMPILE_ARGS ?= -P list.DATA_WIDTH=8 25 | COMPILE_ARGS += -P list.LENGTH=8 26 | COMPILE_ARGS += -P list.SUM_METHOD=0 27 | #"-P" (parameter) iverilog command flags 28 | #run make clean before running with new parameter. 29 | 30 | #Set RANDOM_SEED number 31 | #PLUSARGS = +seed=1716033254 32 | COCOTB_HDL_TIMEUNIT = 1ns 33 | COCOTB_HDL_TIMEPRECISION = 1ps 34 | 35 | ifeq ($(SIM), icarus) 36 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 37 | $(shell echo 'initial begin' >> iverilog_dump.v) 38 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 39 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 40 | $(shell echo 'end' >> iverilog_dump.v) 41 | $(shell echo 'endmodule' >> iverilog_dump.v) 42 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 43 | COMPILE_ARGS += -s iverilog_dump 44 | endif 45 | 46 | include $(shell cocotb-config --makefiles)/Makefile.sim 47 | 48 | 49 | -------------------------------------------------------------------------------- /FIFO/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/fifo.sv 10 | 11 | TOPLEVEL = fifo # DUT Top 12 | MODULE = tb # top python file 13 | 14 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 15 | #TESTCASE = fifo_rand_read_write_test,fifo_rand_write_then_read_test,fifo_rand_read_write_simul_test 16 | #TESTCASE = fifo_rand_read_write_simul_test 17 | 18 | COMPILE_ARGS = -Pfifo.DEPTH=12 # DUT parameter #"-p" iverilog command flags 19 | COMPILE_ARGS += -Pfifo.DATA_WIDTH=8 # DUT parameter #"-p" iverilog command flags 20 | COMPILE_ARGS += -Pfifo.ASYNC=1 # DUT paramter #"-p" iverilog command flags 21 | COMPILE_ARGS += -Pfifo.RD_BUFFER=1 # DUT paramter #"-p" iverilog command flags 22 | #run make clean before running with new parameter. 23 | 24 | #Set RANDOM_SEED number 25 | #PLUSARGS = +seed=1 26 | 27 | COCOTB_HDL_TIMEUNIT = 1ns 28 | COCOTB_HDL_TIMEPRECISION = 1ps 29 | 30 | ifeq ($(SIM), icarus) 31 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 32 | $(shell echo 'initial begin' >> iverilog_dump.v) 33 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 34 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 35 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 36 | $(shell echo 'end' >> iverilog_dump.v) 37 | $(shell echo 'endmodule' >> iverilog_dump.v) 38 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 39 | COMPILE_ARGS += -s iverilog_dump 40 | endif 41 | 42 | include $(shell cocotb-config --makefiles)/Makefile.sim 43 | -------------------------------------------------------------------------------- /Hash_Table/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: sim gen_sim synth netlist_sim gen_netlist_sim clean 2 | 3 | DUT ?= hash_table 4 | SIM_OPTS ?= ../../src/hash_table.sv 5 | SEED ?= $$(shuf -i 1-10000 -n 1) 6 | 7 | # DUT parameter #"-p" iverilog command flags 8 | COMPILE_ARGS = -P tb.DUT_KEY_WIDTH=32 9 | COMPILE_ARGS += -P tb.DUT_VALUE_WIDTH=32 10 | COMPILE_ARGS += -P tb.DUT_TOTAL_INDEX=8 11 | COMPILE_ARGS += -P tb.DUT_CHAINING_SIZE=4 12 | #ICARUS does not support passing with string type. 13 | #COMPILE_ARGS += -P tb.DUT_COLLISION_METHOD=MULTI_STAGE_CHAINING 14 | #COMPILE_ARGS += -P tb.DUT_HASH_ALGORITHM=MODULUS 15 | COMPILE_ARGS += -P tb.TB_CLK_PERIOD=100 16 | COMPILE_ARGS += -P tb.TB_TEST_WEIGHT=1 17 | COMPILE_ARGS += -P tb.TB_SIM_TIMEOUT=30 #//ms. 18 | 19 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 20 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 21 | 22 | sim: gen_sim 23 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 24 | 25 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 26 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 27 | 28 | synth: ${SIM_OPTS} 29 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 30 | #timeout 31 | 32 | netlist_sim: gen_netlist_sim 33 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 34 | 35 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 36 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 37 | 38 | ${XILINX_LIBS_DIR}/.git: 39 | git clone ${XILINX_LIB_URL} 40 | 41 | clean: 42 | rm -f ${DUT}_sim sim.log sim.vcd 43 | rm -f ${DUT}.netlist.v synth.log 44 | -------------------------------------------------------------------------------- /Dual_Edge_FF/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: sim gen_sim synth netlist_sim gen_netlist_sim clean 3 | 4 | DUT ?= list 5 | SRC_DIR = ../../src 6 | SIM_OPTS ?= $(addprefix $(SRC_DIR)/, $(shell cat ../../src/rtl_list.f)) 7 | SEED ?= $$(shuf -i 1-10000 -n 1) 8 | 9 | # DUT parameter #"-P" iverilog command flags 10 | COMPILE_ARGS ?= -P DUT_DATA_WIDTH=8 11 | COMPILE_ARGS += -P DUT_RESET_VALUE=0 12 | COMPILE_ARGS += -P TB_CLK_PERIOD=100 13 | COMPILE_ARGS += -P TB_TEST_WEIGHT=1 14 | COMPILE_ARGS += -P TB_SIM_TIMEOUT=30 #//ms. 15 | 16 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 17 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 18 | 19 | sim: gen_sim 20 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 21 | 22 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 23 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 24 | 25 | synth: ${SIM_OPTS} 26 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 27 | #timeout 28 | 29 | netlist_sim: gen_netlist_sim 30 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 31 | 32 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 33 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 34 | 35 | ${XILINX_LIBS_DIR}/.git: 36 | @echo "XILINX_LIBS_DIR = ${XILINX_LIBS_DIR}" 37 | @echo "XILINX_LIB_URL = ${XILINX_LIB_URL}" 38 | @echo "Checking if XilinxUnisimLibrar/.git exists..." 39 | @if [ ! -d "XilinxUnisimLibrary/.git" ]; then \ 40 | echo "Directory XilinxUnisimLibrar/.git does not exist, cloning..."; \ 41 | git clone ${XILINX_LIB_URL}; \ 42 | else \ 43 | echo "Xilinx library already cloned"; \ 44 | fi 45 | 46 | clean: 47 | rm -f ${DUT}_sim sim.log sim.vcd 48 | rm -f ${DUT}.netlist.v synth.log 49 | -------------------------------------------------------------------------------- /List/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: sim gen_sim synth netlist_sim gen_netlist_sim clean 2 | 3 | DUT ?= list 4 | SRC_DIR = ../../src 5 | SIM_OPTS ?= $(addprefix $(SRC_DIR)/, $(shell cat ../../src/rtl_src.f)) 6 | SEED ?= $$(shuf -i 1-10000 -n 1) 7 | 8 | # DUT parameter #"-P" iverilog command flags 9 | COMPILE_ARGS ?= -P DUT_DATA_WIDTH=8 10 | COMPILE_ARGS += -P DUT_LENGTH=8 11 | COMPILE_ARGS += -P DUT_SUM_METHOD=0 12 | COMPILE_ARGS += -P TB_CLK_PERIOD=100 13 | COMPILE_ARGS += -P TB_TEST_WEIGHT=1 14 | COMPILE_ARGS += -P TB_SIM_TIMEOUT=30 #//ms. 15 | 16 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 17 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 18 | 19 | sim: gen_sim 20 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 21 | 22 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 23 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 24 | 25 | synth: ${SIM_OPTS} 26 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 27 | #timeout 28 | 29 | netlist_sim: gen_netlist_sim 30 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 31 | 32 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 33 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 34 | 35 | ${XILINX_LIBS_DIR}/.git: 36 | @echo "XILINX_LIBS_DIR = ${XILINX_LIBS_DIR}" 37 | @echo "XILINX_LIB_URL = ${XILINX_LIB_URL}" 38 | @echo "Checking if XilinxUnisimLibrar/.git exists..." 39 | @if [ ! -d "XilinxUnisimLibrary/.git" ]; then \ 40 | echo "Directory XilinxUnisimLibrar/.git does not exist, cloning..."; \ 41 | git clone ${XILINX_LIB_URL}; \ 42 | else \ 43 | echo "Xilinx library already cloned"; \ 44 | fi 45 | 46 | clean: 47 | rm -f ${DUT}_sim sim.log sim.vcd 48 | rm -f ${DUT}.netlist.v synth.log 49 | -------------------------------------------------------------------------------- /Hash_Table/tb/cocotb/Makefile: -------------------------------------------------------------------------------- 1 | SIM ?= icarus 2 | TOPLEVEL_LANG ?= verilog 3 | WAVES ?= 1 #set 1 to enable waveform dump. 4 | 5 | PWD=$(shell pwd) 6 | 7 | #export PYTHONPATH := $(PWD)/../model:$(PYTHONPATH) 8 | 9 | VERILOG_SOURCES = $(PWD)/../../src/hash_table.sv 10 | 11 | # DUT Top 12 | TOPLEVEL = hash_table 13 | # top python file name 14 | MODULE = tb 15 | 16 | #use , separtor to run multiple TESTCASE, by default all @cocotb.test will be run 17 | #TESTCASE = index_op_test , addr_op_test 18 | COMPILE_ARGS = -Phash_table.KEY_WIDTH=32 # DUT parameter #"-p" (parameter) iverilog command flags 19 | COMPILE_ARGS += -Phash_table.VALUE_WIDTH=32 # DUT parameter #"-p" (parameter) iverilog command flags 20 | COMPILE_ARGS += -Phash_table.TOTAL_INDEX=8 # DUT parameter #"-p" (parameter) iverilog command flags 21 | COMPILE_ARGS += -Phash_table.CHAINING_SIZE=4 # DUT parameter #"-p" (parameter) iverilog command flags 22 | #COMPILE_ARGS += -Phash_table.COLLISION_METHOD="MULTI_STAGE_CHAINING" # DUT parameter #"-p" (parameter) iverilog command flags 23 | #COMPILE_ARGS += -Phash_table.HASH_ALGORITHM="MODULUS" # DUT parameter #"-p" (parameter) iverilog command flags 24 | #run make clean before running with new parameter. 25 | 26 | #Set RANDOM_SEED number 27 | #PLUSARGS = +seed=1716033254 28 | COCOTB_HDL_TIMEUNIT = 1ns 29 | COCOTB_HDL_TIMEPRECISION = 1ps 30 | 31 | ifeq ($(SIM), icarus) 32 | $(shell echo 'module iverilog_dump();' > iverilog_dump.v) 33 | $(shell echo 'initial begin' >> iverilog_dump.v) 34 | $(shell echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> iverilog_dump.v) 35 | $(shell echo ' $$dumpvars(0, $(TOPLEVEL));' >> iverilog_dump.v) 36 | $(shell echo 'end' >> iverilog_dump.v) 37 | $(shell echo 'endmodule' >> iverilog_dump.v) 38 | VERILOG_SOURCES += $(PWD)/iverilog_dump.v 39 | COMPILE_ARGS += -s iverilog_dump 40 | endif 41 | 42 | include $(shell cocotb-config --makefiles)/Makefile.sim 43 | 44 | 45 | -------------------------------------------------------------------------------- /Utils/tb/sv/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: sim gen_sim synth netlist_sim gen_netlist_sim clean 2 | 3 | DUT ?= list 4 | SRC_DIR = ../../src 5 | SIM_OPTS ?= $(addprefix $(SRC_DIR)/, $(shell cat ../../src/rtl_list.f)) 6 | SEED ?= $$(shuf -i 1-10000 -n 1) 7 | 8 | # DUT parameter #"-P" iverilog command flags 9 | # FIXME : Edit this to match your DUT parameters 10 | # COMPILE_ARGS ?= -P DUT_DATA_WIDTH=8 11 | # COMPILE_ARGS += -P DUT_LENGTH=8 12 | # COMPILE_ARGS += -P DUT_SUM_METHOD=0 13 | COMPILE_ARGS += -P TB_CLK_PERIOD=100 14 | COMPILE_ARGS += -P TB_TEST_WEIGHT=1 15 | COMPILE_ARGS += -P TB_SIM_TIMEOUT=30 #//ms. 16 | 17 | XILINX_LIB_URL ?= https://github.com/Xilinx/XilinxUnisimLibrary.git 18 | XILINX_LIB_DIR ?= XilinxUnisimLibrary/verilog/src 19 | 20 | sim: gen_sim 21 | ./${DUT}.sim +VCDFILE=sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee sim.log 22 | 23 | gen_sim: tb.sv ${SIM_OPTS} # to generate executable file by using iverilator 24 | iverilog -g2012 -s tb ${COMPILE_ARGS} -o ${DUT}.sim $^ 25 | 26 | synth: ${SIM_OPTS} 27 | yosys -p synth_xilinx ${SIM_OPTS} -L synth.log -o ${DUT}.netlist.v 28 | #timeout 29 | 30 | netlist_sim: gen_netlist_sim 31 | ./${DUT}.netlist.sim +VCDFILE=netlist_sim.vcd +VCDLEVEL=0 +SEED=${SEED} | tee netlist_sim.log 32 | 33 | gen_netlist_sim: tb.sv ${DUT}.netlist.v | ${XILINX_LIBS_DIR}/.git 34 | iverilog -g2012 -s tb -y ${XILINX_LIB_DIR} -y ${XILINX_LIB_DIR}/unisims -DXILINX_GLS ${COMPILE_ARGS} -o ${DUT}.netlist.sim $^ 35 | 36 | ${XILINX_LIBS_DIR}/.git: 37 | @echo "XILINX_LIBS_DIR = ${XILINX_LIBS_DIR}" 38 | @echo "XILINX_LIB_URL = ${XILINX_LIB_URL}" 39 | @echo "Checking if XilinxUnisimLibrar/.git exists..." 40 | @if [ ! -d "XilinxUnisimLibrary/.git" ]; then \ 41 | echo "Directory XilinxUnisimLibrar/.git does not exist, cloning..."; \ 42 | git clone ${XILINX_LIB_URL}; \ 43 | else \ 44 | echo "Xilinx library already cloned"; \ 45 | fi 46 | 47 | clean: 48 | rm -f ${DUT}_sim sim.log sim.vcd 49 | rm -f ${DUT}.netlist.v synth.log 50 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/sim/tb_top.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 09:04 PM 5 | // Module Name: tb_top 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This is the top-level testbench for the FIFO VIP. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | `timescale 1ns/1ps 13 | 14 | module tb_top; 15 | import uvm_pkg::*; 16 | import fifo_vip_pkg::*; 17 | 18 | // Clocks 19 | logic wr_clk = 0; 20 | logic rd_clk = 0; 21 | 22 | // Clock generation - MODIFY PERIODS AS NEEDED 23 | always #10 wr_clk = ~wr_clk; // 50MHz 24 | always #16 rd_clk = ~rd_clk; // 31.25MHz 25 | 26 | // Interface 27 | fifo_vip_if dut_if(wr_clk, rd_clk); 28 | 29 | // Reset 30 | initial begin 31 | dut_if.rst = 1; 32 | repeat(5) @(posedge wr_clk); 33 | dut_if.rst = 0; 34 | end 35 | 36 | // DUT instantiation - MODIFY FOR YOUR FIFO 37 | fifo #( 38 | .DEPTH(12), 39 | .DATA_WIDTH(8), 40 | .ASYNC(1), 41 | .RD_BUFFER(1) 42 | ) dut ( 43 | .rd_clk(rd_clk), 44 | .wr_clk(wr_clk), 45 | .rst(dut_if.rst), 46 | .data_wr(dut_if.data_wr), 47 | .wr_en(dut_if.wr_en), 48 | .fifo_full(dut_if.fifo_full), 49 | .data_rd(dut_if.data_rd), 50 | .rd_en(dut_if.rd_en), 51 | .fifo_empty(dut_if.fifo_empty) 52 | ); 53 | 54 | // UVM testbench 55 | initial begin 56 | uvm_config_db#(virtual fifo_vip_if)::set(null, "*", "fifo_vip_vif", dut_if); 57 | 58 | $dumpfile("waves.vcd"); 59 | $dumpvars(0, tb_top); 60 | 61 | run_test(); 62 | end 63 | 64 | // Timeout 65 | initial begin 66 | #50us; 67 | $finish; 68 | end 69 | 70 | endmodule -------------------------------------------------------------------------------- /Dual_Edge_FF/src/dual_edge_ff.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Create Date: 30/07/2025 07:22 PM 4 | // Created By: https://www.linkedin.com/in/wei-yet-ng-065485119/ 5 | // Last Update: 03/08/2025 02:30 PM 6 | // Last Updated By: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Module Name: Dual Edge Flip Flop 8 | // Description: Synthesiazble structure that can latch data corresponding to dual edge of clock to achive double input and output rate. 9 | // Additional Comments: . 10 | // 11 | ////////////////////////////////////////////////////////////////////////////////// 12 | 13 | 14 | module dual_edge_ff #( 15 | parameter DATA_WIDTH = 8, 16 | parameter RESET_VALUE = 0 17 | )( 18 | input wire clk, 19 | input wire rst_n, 20 | input wire [DATA_WIDTH-1:0] data_in, 21 | input wire [DATA_WIDTH-1:0] pos_edge_latch_en, 22 | input wire [DATA_WIDTH-1:0] neg_edge_latch_en, 23 | output wire [DATA_WIDTH-1:0] data_out 24 | ); 25 | 26 | reg [DATA_WIDTH-1:0] d_in_pos; 27 | reg [DATA_WIDTH-1:0] q_out_pos; 28 | reg [DATA_WIDTH-1:0] d_in_neg; 29 | reg [DATA_WIDTH-1:0] q_out_neg; 30 | 31 | 32 | assign clk_n = ~clk; // Invert clock for negative edge latching 33 | 34 | genvar i; 35 | 36 | generate 37 | for(i=0;i 0) begin 37 | int expected = fifo_model.pop_front(); 38 | if (item.read_data == expected) begin 39 | `uvm_info("SB", $sformatf("Read OK: data=0x%0h, queue_size=%0d", item.read_data, fifo_model.size()), UVM_MEDIUM) 40 | end else begin 41 | `uvm_error("SB", $sformatf("Data mismatch! Expected:0x%0h Got:0x%0h", expected, item.read_data)) 42 | errors++; 43 | end 44 | end else begin 45 | `uvm_error("SB", "Read from empty FIFO model") 46 | errors++; 47 | end 48 | end 49 | endfunction 50 | 51 | function void report_phase(uvm_phase phase); 52 | if (errors == 0) 53 | `uvm_info("SB", "*** TEST PASSED ***", UVM_LOW) 54 | else 55 | `uvm_error("SB", $sformatf("*** TEST FAILED - %0d errors ***", errors)) 56 | endfunction 57 | 58 | endclass -------------------------------------------------------------------------------- /FIFO/vip/uvm/agent/fifo_vip_monitor.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 08:56 PM 5 | // Module Name: fifo_vip_monitor 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the FIFO VIP monitor. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | class fifo_vip_monitor extends uvm_monitor; 12 | `uvm_component_utils(fifo_vip_monitor) 13 | 14 | virtual fifo_vip_if vif; 15 | fifo_vip_config cfg; 16 | uvm_analysis_port #(fifo_vip_seq_item) ap; 17 | string monitor_type; // "WR" or "RD" 18 | 19 | function new(string name = "fifo_vip_monitor", uvm_component parent = null); 20 | super.new(name, parent); 21 | ap = new("ap", this); 22 | endfunction 23 | 24 | function void build_phase(uvm_phase phase); 25 | if (!uvm_config_db#(virtual fifo_vip_if)::get(this, "", "fifo_vip_vif", vif)) 26 | `uvm_fatal("MON", "No virtual interface") 27 | if (!uvm_config_db#(fifo_vip_config)::get(this, "", "fifo_vip_cfg", cfg)) 28 | `uvm_fatal("MON", "No config") 29 | 30 | // Figure out monitor type 31 | monitor_type = (get_name().substr(0,1) == "w") ? "WR" : "RD"; 32 | endfunction 33 | 34 | task run_phase(uvm_phase phase); 35 | @(negedge vif.rst); 36 | 37 | if (monitor_type == "WR") begin 38 | monitor_writes(); 39 | end else begin 40 | monitor_reads(); 41 | end 42 | endtask 43 | 44 | task monitor_writes(); 45 | fifo_vip_seq_item item; 46 | forever begin 47 | @(posedge vif.wr_clk); 48 | if (vif.wr_en && !vif.rst) begin 49 | item = fifo_vip_seq_item::type_id::create("wr_item"); 50 | item.op = WRITE; 51 | item.data = vif.data_wr; 52 | item.full = vif.fifo_full; 53 | item.success = !vif.fifo_full; 54 | ap.write(item); 55 | `uvm_info("WR_MON", $sformatf("Monitored: %s", item.convert2string()), UVM_HIGH) 56 | end 57 | end 58 | endtask 59 | 60 | task monitor_reads(); 61 | fifo_vip_seq_item item; 62 | forever begin 63 | @(posedge vif.rd_clk); 64 | if (vif.rd_en && !vif.rst) begin 65 | item = fifo_vip_seq_item::type_id::create("rd_item"); 66 | item.op = READ; 67 | item.empty = vif.fifo_empty; 68 | item.success = !vif.fifo_empty; 69 | if (cfg.RD_BUFFER) @(posedge vif.rd_clk); // Wait for buffered read 70 | item.read_data = vif.data_rd; 71 | ap.write(item); 72 | `uvm_info("RD_MON", $sformatf("Monitored: %s", item.convert2string()), UVM_HIGH) 73 | end 74 | end 75 | endtask 76 | 77 | endclass -------------------------------------------------------------------------------- /FIFO/vip/uvm/agent/fifo_vip_driver.sv: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Create Date: 05/24/2024 03:37 PM 4 | // Last Update Date: 05/24/2024 08:45 PM 5 | // Module Name: fifo_vip_driver 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: This package contains the FIFO VIP driver. 8 | // 9 | ////////////////////////////////////////////////////////////////////////////////// 10 | 11 | 12 | class fifo_vip_driver extends uvm_driver #(fifo_vip_seq_item); 13 | `uvm_component_utils(fifo_vip_driver) 14 | 15 | virtual fifo_vip_if vif; 16 | fifo_vip_config cfg; 17 | string driver_type; // "WR" or "RD" 18 | 19 | function new(string name = "fifo_vip_driver", uvm_component parent = null); 20 | super.new(name, parent); 21 | endfunction 22 | 23 | function void build_phase(uvm_phase phase); 24 | if (!uvm_config_db#(virtual fifo_vip_if)::get(this, "", "vif", vif)) 25 | `uvm_fatal("DRV", "No virtual interface") 26 | if (!uvm_config_db#(fifo_vip_config)::get(this, "", "cfg", cfg)) 27 | `uvm_fatal("DRV", "No config") 28 | 29 | // Figure out if this is write or read driver 30 | driver_type = (get_name().substr(0,1) == "w") ? "WR" : "RD"; 31 | endfunction 32 | 33 | task run_phase(uvm_phase phase); 34 | fifo_vip_seq_item item; 35 | 36 | // Initialize 37 | if (driver_type == "WR") begin 38 | vif.wr_cb.wr_en <= 0; 39 | vif.wr_cb.data_wr <= 0; 40 | end else begin 41 | vif.rd_cb.rd_en <= 0; 42 | end 43 | 44 | // Wait for reset 45 | @(negedge vif.rst); 46 | @(posedge vif.wr_clk); 47 | 48 | forever begin 49 | seq_item_port.get_next_item(item); 50 | drive_item(item); 51 | seq_item_port.item_done(); 52 | end 53 | endtask 54 | 55 | task drive_item(fifo_vip_seq_item item); 56 | // Set config on item 57 | item.set_config(cfg); 58 | 59 | case (item.op) 60 | WRITE: if (driver_type == "WR") drive_write(item); 61 | READ: if (driver_type == "RD") drive_read(item); 62 | IDLE: repeat(2) @(vif.wr_cb); 63 | endcase 64 | endtask 65 | 66 | task drive_write(fifo_vip_seq_item item); 67 | @(vif.wr_cb); 68 | vif.wr_cb.data_wr <= item.data[cfg.DATA_WIDTH-1:0]; 69 | vif.wr_cb.wr_en <= 1; 70 | @(vif.wr_cb); 71 | item.full = vif.wr_cb.fifo_full; 72 | item.success = !vif.wr_cb.fifo_full; 73 | vif.wr_cb.wr_en <= 0; 74 | `uvm_info("WR_DRV", $sformatf("Write: %s", item.convert2string()), UVM_HIGH) 75 | endtask 76 | 77 | task drive_read(fifo_vip_seq_item item); 78 | @(vif.rd_cb); 79 | vif.rd_cb.rd_en <= 1; 80 | @(vif.rd_cb); 81 | item.empty = vif.rd_cb.fifo_empty; 82 | item.success = !vif.rd_cb.fifo_empty; 83 | if (cfg.RD_BUFFER) @(vif.rd_cb); // Wait extra cycle for buffered read 84 | item.read_data = vif.rd_cb.data_rd; 85 | vif.rd_cb.rd_en <= 0; 86 | `uvm_info("RD_DRV", $sformatf("Read: %s", item.convert2string()), UVM_HIGH) 87 | endtask 88 | 89 | endclass -------------------------------------------------------------------------------- /Table/README.md: -------------------------------------------------------------------------------- 1 | # Multi-port table 2 | 3 | ## Overview 4 | This Verilog module implements a flexible table structure that supports multiple simultaneous read and write operations. It functions similarly to a register file, providing direct indexed access to stored data without the need for hashing mechanisms. 5 | 6 | ## Features 7 | - Configurable table size and data width 8 | - Support for multiple simultaneous write operations 9 | - Support for multiple simultaneous read operations 10 | - Synchronous operation with reset capability 11 | - Direct indexed access to stored data 12 | 13 | ## Parameters 14 | 15 | | Parameter | Description | Default | 16 | |-------------|------------------------------------------------|---------| 17 | | TABLE_SIZE | Number of entries in the table | 32 | 18 | | DATA_WIDTH | Width of each data entry in bits | 8 | 19 | | INPUT_RATE | Number of simultaneous write operations | 2 | 20 | | OUTPUT_RATE | Number of simultaneous read operations | 2 | 21 | 22 | ## Port Descriptions 23 | 24 | ### Input Ports 25 | 26 | | Port | Width | Description | 27 | |-----------|----------------------------------|--------------------------------| 28 | | clk | 1 | System clock signal | 29 | | rst | 1 | Active-high reset signal | 30 | | wr_en | INPUT_RATE | Write enable signals | 31 | | rd_en | 1 | Read enable signal | 32 | | index_wr | INPUT_RATE * log2(TABLE_SIZE) | Write address indices | 33 | | index_rd | OUTPUT_RATE * log2(TABLE_SIZE) | Read address indices | 34 | | data_wr | INPUT_RATE * DATA_WIDTH | Write data input | 35 | 36 | ### Output Ports 37 | 38 | | Port | Width | Description | 39 | |-----------|--------------------------|----------------------| 40 | | data_rd | OUTPUT_RATE * DATA_WIDTH | Read data output | 41 | 42 | ## Timing 43 | - All operations are synchronized to the positive edge of the clock 44 | - Reset is asynchronous and active-high 45 | - Write operations occur on the next clock edge after wr_en is asserted 46 | - Read operations occur on the next clock edge after rd_en is asserted 47 | 48 | ## Usage Example 49 | ```verilog 50 | table_top #( 51 | .TABLE_SIZE(64), 52 | .DATA_WIDTH(16), 53 | .INPUT_RATE(2), 54 | .OUTPUT_RATE(2) 55 | ) table_inst ( 56 | .clk(system_clk), 57 | .rst(system_rst), 58 | .wr_en(write_enable), 59 | .rd_en(read_enable), 60 | .index_wr(write_indices), 61 | .index_rd(read_indices), 62 | .data_wr(write_data), 63 | .data_rd(read_data) 64 | ); 65 | ``` 66 | 67 | ## Implementation Details 68 | - Uses a 2D register array for data storage 69 | - Implements parallel write operations using generate blocks 70 | - Supports concurrent read operations 71 | - Reset initializes all storage elements to zero 72 | - Uses Verilog-2001 syntax and features 73 | 74 | ## Performance Considerations 75 | - All read and write operations complete in a single clock cycle 76 | - No read-after-write hazard protection is implemented 77 | - Care should be taken when accessing the same index simultaneously 78 | 79 | ## Limitations 80 | - No built-in error checking for invalid indices 81 | - No protection against simultaneous read/write to same location 82 | - Write operations take precedence in case of conflicts 83 | 84 | -------------------------------------------------------------------------------- /Hash_Table/README.md: -------------------------------------------------------------------------------- 1 | # Hash Table Module 2 | ## Overview 3 | This Verilog module implements a flexible hash table with configurable collision resolution methods and hash algorithms. It provides support for key-value storage with operations such as insert, delete, and search. 4 | 5 | ## Features 6 | - Configurable key and value widths 7 | - Support for different collision resolution methods 8 | - Multiple hash algorithm options 9 | - Synchronous operation with reset capability 10 | - Collision tracking and error reporting 11 | 12 | ## Parameters 13 | | Parameter | Description | Default | 14 | |-----------|-------------|---------| 15 | | KEY_WIDTH | Width of keys in bits | 32 | 16 | | VALUE_WIDTH | Width of values in bits | 32 | 17 | | TOTAL_ENTRY | Number of indices in the hash table | 64 | 18 | | CHAINING_SIZE | Maximum chain length for collision resolution | 4 | 19 | | COLLISION_METHOD | Method for handling collisions | "MULTI_STAGE_CHAINING" | 20 | | HASH_ALGORITHM | Algorithm used for hashing | "MODULUS" | 21 | 22 | ## Port Descriptions 23 | ### Input Ports 24 | | Port | Width | Description | 25 | |------|-------|-------------| 26 | | clk | 1 | System clock signal | 27 | | rst | 1 | Active-high reset signal | 28 | | key_in | KEY_WIDTH | Key for insert, delete, or search operations | 29 | | value_in | VALUE_WIDTH | Value to be stored (for insert operations) | 30 | | op_sel | 2 | Operation selector (00: Insert, 01: Delete, 10: Search) | 31 | | op_en | 1 | Operation enable signal | 32 | 33 | ### Output Ports 34 | | Port | Width | Description | 35 | |------|-------|-------------| 36 | | value_out | VALUE_WIDTH | Value retrieved during search operations | 37 | | op_done | 1 | Operation completion indicator | 38 | | op_error | 1 | Error indicator (FULL for insert, KEY_NOT_FOUND for delete/search) | 39 | | collision_count | log2(CHAINING_SIZE) | Number of collisions encountered | 40 | 41 | ## Collision Methods 42 | - **MULTI_STAGE_CHAINING**: Multiple entries at the same index using a linked list approach 43 | - **LINEAR_PROBING**: Referenced in parameters but not fully implemented in the provided code 44 | 45 | ## Hash Algorithms 46 | - **MODULUS**: Simple modulus operation (key % TABLE_SIZE) 47 | - **SHA1**, **FNV1A**: Referenced in parameters but not fully implemented in the provided code 48 | 49 | ## Timing 50 | - All operations are synchronized to the positive edge of the clock 51 | - Reset is asynchronous and active-high 52 | - Operations are initiated when op_en is asserted 53 | - op_done indicates completion of an operation 54 | 55 | ## Usage Example 56 | ```verilog 57 | hash_table #( 58 | .KEY_WIDTH(32), 59 | .VALUE_WIDTH(32), 60 | .TOTAL_ENTRY(128), 61 | .CHAINING_SIZE(8), 62 | .COLLISION_METHOD("MULTI_STAGE_CHAINING"), 63 | .HASH_ALGORITHM("MODULUS") 64 | ) hash_module ( 65 | .clk(system_clk), 66 | .rst(system_rst), 67 | .key_in(key), 68 | .value_in(value), 69 | .op_sel(operation), 70 | .op_en(enable), 71 | .value_out(retrieved_value), 72 | .op_done(operation_complete), 73 | .op_error(operation_error), 74 | .collision_count(collisions) 75 | ); 76 | ``` 77 | 78 | ## Implementation Details 79 | - Uses a state machine for operation control 80 | - Implements chained hash entries for collision resolution 81 | - Provides error reporting for table overflow or key not found conditions 82 | - Uses Verilog parameter-based configuration for flexibility 83 | 84 | ## Limitations and Issues 85 | - Implementation for alternative hash algorithms is mentioned but not provided 86 | 87 | ## Performance Considerations 88 | - Search and delete operations may require multiple cycles depending on chain length 89 | - Performance degrades as collision chains grow longer 90 | - No optimization for locality or cache behavior 91 | - Please consider using [CAM(Content Addressable Memory)](https://en.wikipedia.org/wiki/Content-addressable_memory) if you have the resources. 92 | -------------------------------------------------------------------------------- /FIFO/vip/uvm/README.md: -------------------------------------------------------------------------------- 1 | # Development In Progress!! 2 | 3 | # FIFO (Queue) UVM VIP (Verification IP) User Guide 4 | ## 📁 Directory Structure 5 | 6 | ``` 7 | uvm/ 8 | ├── src/ # Core VIP source files 9 | │ ├── fifo_vip_pkg.sv # Main package + types/enums 10 | │ ├── fifo_vip_config.sv # Configuration class 11 | │ └── fifo_vip_seq_item.sv # Transaction definitions 12 | ├── agent/ # Agent layer components 13 | │ ├── fifo_vip_driver.sv # Driver implementation 14 | │ ├── fifo_vip_monitor.sv # Monitor implementation 15 | │ ├── fifo_vip_sequencer.sv # Sequencer (simple) 16 | │ └── fifo_vip_agent.sv # Agent wrapper 17 | ├── env/ # Environment layer 18 | │ ├── fifo_vip_env.sv # Environment 19 | │ └── fifo_vip_scoreboard.sv # Checking components 20 | ├── sequences/ # Test sequences 21 | │ ├── fifo_vip_base_seq.sv # Base sequence 22 | │ ├── fifo_vip_write_req_seq.sv # Write sequences 23 | │ └── fifo_vip_read_req_seq.sv # Read sequences 24 | ├── interface/ # Interface definition 25 | │ └── fifo_vip_if.sv # Virtual interface 26 | └── tb/ # Testbench 27 | ├── tests/ 28 | │ └── base_test.sv # Base test + simple_test 29 | └── tb_top.sv # Testbench top module 30 | ``` 31 | 32 | ## 🚀 Quick Start 33 | 34 | **Step 1:** Update Agent Interface with correct internal signals (refer to `fifo_vip_if.sv`) in your top level testbench: 35 | ```systemverilog 36 | // Update interface signal widths and connections in tb_top.sv 37 | fifo_vip_if dut_if; 38 | assign dut_if.rst = u_fifo.rst; 39 | assign dut_if.rd_clk = u_fifo.rd_clk; 40 | assign dut_if.wr_clk = u_fifo.wr_clk; 41 | assign dut_if.data_wr = u_fifo.data_wr; 42 | assign dut_if.wr_en = u_fifo.wr_en; 43 | assign dut_if.fifo_full = u_fifo.fifo_full; 44 | assign dut_if.data_rd = u_fifo.data_rd; 45 | assign dut_if.rd_en = u_fifo.rd_en; 46 | assign dut_if.fifo_empty = u_fifo.fifo_empty; 47 | 48 | // Set interface in config DB 49 | uvm_config_db#(virtual fifo_vip_if)::set(null, "*", "fifo_vip_vif", dut_if); 50 | ``` 51 | 52 | **Step 2:** Update DUT parameters/configuration (refer to `fifo_vip_config.sv`) in your test: 53 | ```systemverilog 54 | // In your test's build_phase() 55 | cfg = fifo_vip_config::type_id::create("cfg"); 56 | cfg.DEPTH = 12; // Match your FIFO depth 57 | cfg.DATA_WIDTH = 8; // Match your data width 58 | cfg.ASYNC = 1; // 1=async clocks, 0=sync 59 | cfg.RD_BUFFER = 1; // 1=buffered read, 0=combinational 60 | 61 | // Set config in database 62 | uvm_config_db#(fifo_vip_config)::set(this, "*", "fifo_vip_cfg", cfg); 63 | ``` 64 | 65 | **Step 3:** Agent instantiation in your environment (refer to `fifo_vip_env.sv`): 66 | ```systemverilog 67 | // Create FIFO VIP environment 68 | fifo_env = fifo_vip_env::type_id::create("fifo_env", this); 69 | ```` 70 | 71 | ##🚀 Available Sequences 72 | 73 | **Write Sequence:** 74 | ```systemverilog 75 | fifo_vip_write_req_seq wr_seq = fifo_vip_write_req_seq::type_id::create("wr_seq"); 76 | wr_seq.num_writes = 10; 77 | wr_seq.start(env.get_wr_sequencer()); 78 | ``` 79 | 80 | **Read Sequence:** 81 | ```systemverilog 82 | fifo_vip_read_req_seq rd_seq = fifo_vip_read_req_seq::type_id::create("rd_seq"); 83 | rd_seq.num_reads = 10; 84 | rd_seq.start(env.get_rd_sequencer()); 85 | ``` 86 | 87 | ## ✅ Self-Checking Features 88 | - ✅ Data integrity through FIFO 89 | - ✅ Write when full behavior 90 | - ✅ Read when empty behavior 91 | - ✅ FIFO flag correctness 92 | - ✅ Transaction success/failure 93 | 94 | ## 🚨 Common Issues & Solutions 95 | 96 | ### Future Work 97 | Add assertions to `fifo_vip_if.sv` or create a separate checker component. 98 | Add coverage 99 | 100 | **Happy Verifying! 🚀** 101 | 102 | *This VIP follows UVM best practices while keeping complexity minimal for ease of use and learning.* 103 | -------------------------------------------------------------------------------- /FIFO/README.md: -------------------------------------------------------------------------------- 1 | # FIFO (Queue) 2 | 3 | A configurable FIFO (First-In-First-Out) buffer implementation in Verilog with support for both synchronous and asynchronous clock domains. The module uses Gray code for pointer synchronization in asynchronous mode to prevent metastability issues. 4 | 5 | ## Features 6 | 7 | - Configurable data width and depth 8 | - Support for both synchronous and asynchronous clock domains 9 | - Optional registered read output 10 | - Gray code synchronization for clock domain crossing 11 | - Full and empty status flags 12 | - Automatic pointer wraparound 13 | - Parameterized design for easy customization 14 | 15 | ## Parameters 16 | 17 | | Parameter | Description | Default | 18 | |-------------|--------------------------------------------------|---------| 19 | | DEPTH | Number of entries in the FIFO | 12 | 20 | | DATA_WIDTH | Width of each data entry | 8 | 21 | | ASYNC | Enable asynchronous mode (1) or synchronous (0) | 1 | 22 | | RD_BUFFER | Enable registered read output (1) or bypass (0) | 1 | 23 | 24 | ## Interface Signals 25 | 26 | | Signal | Direction | Width | Description | 27 | |-------------|-----------|---------------|------------------------------------------------| 28 | | rd_clk | Input | 1 | Read clock domain | 29 | | wr_clk | Input | 1 | Write clock domain | 30 | | rst | Input | 1 | Active high reset | 31 | | data_wr | Input | DATA_WIDTH | Data input for writing | 32 | | wr_en | Input | 1 | Write enable signal | 33 | | fifo_full | Output | 1 | FIFO full indicator | 34 | | data_rd | Output | DATA_WIDTH | Data output from reading | 35 | | rd_en | Input | 1 | Read enable signal | 36 | | fifo_empty | Output | 1 | FIFO empty indicator | 37 | 38 | ## Usage Example 39 | 40 | ```verilog 41 | // Instantiate a 16-deep, 32-bit wide asynchronous FIFO with registered output 42 | fifo #( 43 | .DEPTH(16), 44 | .DATA_WIDTH(32), 45 | .ASYNC(1), 46 | .RD_BUFFER(1) 47 | ) fifo_inst ( 48 | .rd_clk(read_clock), 49 | .wr_clk(write_clock), 50 | .rst(reset), 51 | .data_wr(write_data), 52 | .wr_en(write_enable), 53 | .fifo_full(full_flag), 54 | .data_rd(read_data), 55 | .rd_en(read_enable), 56 | .fifo_empty(empty_flag) 57 | ); 58 | ``` 59 | 60 | ## Design Notes 61 | 62 | 1. **Clock Domain Crossing**: In asynchronous mode (ASYNC=1), the design uses Gray code encoding for pointer synchronization to prevent metastability issues when crossing clock domains. 63 | 64 | 2. **Read Buffer**: When RD_BUFFER=1, the read data output is registered, adding one clock cycle of latency but improving timing. When RD_BUFFER=0, the read data is combinatorial. 65 | 66 | 3. **Full/Empty Flags**: 67 | - The empty flag is asserted when read and write pointers are equal 68 | - The full flag is asserted when the next write pointer would equal the current read pointer 69 | 70 | 4. **Reset Behavior**: 71 | - All pointers are reset to zero 72 | - All memory locations are cleared 73 | - All flags are deasserted 74 | 75 | ## Implementation Details 76 | 77 | The module uses separate read and write pointers for tracking FIFO occupancy. In asynchronous mode, these pointers are converted to Gray code before being synchronized across clock domains. The implementation includes: 78 | 79 | - Binary counters for read/write operation 80 | - Gray code conversion for pointer synchronization 81 | - Two-stage synchronizers for clock domain crossing 82 | - Configurable output registration 83 | - Automatic pointer wraparound at FIFO boundaries 84 | 85 | ## Timing Considerations 86 | 87 | 1. In asynchronous mode, allow at least 2 clock cycles for pointer synchronization 88 | 2. When RD_BUFFER=1, read data is available one clock cycle after rd_en assertion 89 | 3. Full and empty flags are registered outputs 90 | 91 | ## Limitations 92 | 93 | - The DEPTH parameter must be a power of 2 for proper wraparound behavior 94 | - Simultaneous read/write at full/empty conditions should be managed by external logic 95 | - The reset signal must be synchronized to both clock domains 96 | -------------------------------------------------------------------------------- /LIFO/README.md: -------------------------------------------------------------------------------- 1 | # LIFO (Stack) 2 | 3 | A configurable LIFO (Last-In-First-Out) buffer implementation in Verilog. This module implements a stack-like behavior where the last element written is the first one to be read out. The design includes bypass functionality for simultaneous read/write operations. 4 | 5 | ## Features 6 | 7 | - Configurable data width and depth 8 | - Single clock domain operation 9 | - Full and empty status flags 10 | - Bypass path for simultaneous read/write 11 | - Registered read output 12 | - Automatic pointer management 13 | - Parameterized design for easy customization 14 | 15 | ## Parameters 16 | 17 | | Parameter | Description | Default | 18 | |-------------|--------------------------------------------------|---------| 19 | | DEPTH | Number of entries in the LIFO | 12 | 20 | | DATA_WIDTH | Width of each data entry | 8 | 21 | 22 | ## Interface Signals 23 | 24 | | Signal | Direction | Width | Description | 25 | |-------------|-----------|---------------|------------------------------------------------| 26 | | clk | Input | 1 | System clock | 27 | | rst | Input | 1 | Active high reset | 28 | | data_wr | Input | DATA_WIDTH | Data input for writing | 29 | | wr_en | Input | 1 | Write enable signal | 30 | | lifo_full | Output | 1 | LIFO full indicator | 31 | | data_rd | Output | DATA_WIDTH | Data output from reading | 32 | | rd_en | Input | 1 | Read enable signal | 33 | | lifo_empty | Output | 1 | LIFO empty indicator | 34 | 35 | ## Usage Example 36 | 37 | ```verilog 38 | // Instantiate a 16-deep, 32-bit wide LIFO 39 | lifo #( 40 | .DEPTH(16), 41 | .DATA_WIDTH(32) 42 | ) lifo_inst ( 43 | .clk(system_clock), 44 | .rst(reset), 45 | .data_wr(write_data), 46 | .wr_en(write_enable), 47 | .lifo_full(full_flag), 48 | .data_rd(read_data), 49 | .rd_en(read_enable), 50 | .lifo_empty(empty_flag) 51 | ); 52 | ``` 53 | 54 | ## Operation Modes 55 | 56 | The module supports three operation modes: 57 | 58 | 1. **Write Operation (wr_op)** 59 | - Activated when wr_en=1 and rd_en=0 60 | - Data is written to current pointer location 61 | - Pointer increments if not full 62 | 63 | 2. **Read Operation (rd_op)** 64 | - Activated when rd_en=1 and wr_en=0 65 | - Data is read from (pointer-1) location 66 | - Pointer decrements if not empty 67 | 68 | 3. **Bypass Operation (bypass_op)** 69 | - Activated when both wr_en=1 and rd_en=1 70 | - Input data (data_wr) is directly passed to output (data_rd) 71 | - Pointer remains unchanged 72 | 73 | ## Design Notes 74 | 75 | 1. **Pointer Management**: 76 | - Single pointer tracks both read and write positions 77 | - Increments on write, decrements on read 78 | - Range: 0 to (DEPTH-1) 79 | 80 | 2. **Memory Organization**: 81 | - Stack-like structure with DEPTH entries 82 | - Each entry is DATA_WIDTH bits wide 83 | - Last written data is first to be read 84 | 85 | 3. **Flag Generation**: 86 | - Empty flag is combinatorial (pointer = 0) 87 | - Full flag is registered (pointer = DEPTH-1) 88 | - Flags prevent invalid operations 89 | 90 | ## Reset Behavior 91 | 92 | On assertion of reset: 93 | - Pointer is cleared to zero 94 | - All memory locations are cleared 95 | - Full flag is deasserted 96 | - Output data is cleared 97 | - Empty flag becomes active 98 | 99 | ## Timing Considerations 100 | 101 | 1. All outputs except lifo_empty are registered 102 | 2. Data is available on the next clock cycle after rd_en assertion 103 | 3. Bypass operation provides data in the same clock cycle 104 | 105 | ## Limitations 106 | 107 | - Single clock domain operation only 108 | - No protection against overflow/underflow if flags are ignored 109 | - DEPTH parameter should be at least 2 for proper operation 110 | - Simultaneous read/write operations bypass the stack memory 111 | 112 | ## Alternative Implementation Note 113 | 114 | The commented code at the bottom of the module suggests an alternative implementation for full flag handling and read operations, which could be implemented if different timing behavior is needed. 115 | -------------------------------------------------------------------------------- /List/README.md: -------------------------------------------------------------------------------- 1 | # List Module 2 | 3 | ## Overview 4 | The List module is a versatile data storage and manipulation component implemented in Verilog. It provides various operations for managing and processing data, including reading, writing, summing, and sorting functionalities. This module can be particularly useful in FPGA designs requiring data buffering, accumulation, or processing. 5 | 6 | ## Features 7 | - Data storage with configurable width and length 8 | - Multiple data manipulation operations: 9 | - Read/write operations 10 | - Element searching 11 | - Data summation with multiple implementation methods 12 | - Sorting (ascending and descending) 13 | - Configurable sum calculation methods: 14 | - Parallel sum (combinatorial) 15 | - Sequential sum 16 | - Adder tree 17 | 18 | ## Module Instantiation 19 | ``` verilog 20 | // Instantiation with custom parameters 21 | list #( 22 | .DATA_WIDTH(16), // 16-bit data elements 23 | .LENGTH(32), // List can store up to 32 elements 24 | .SUM_METHOD(1) // Use sequential summation method 25 | ) custom_list ( 26 | .clk(clk), 27 | .rst(rst), 28 | .op_sel(op_sel), 29 | .op_en(op_en), 30 | .data_in(data_in), 31 | .index_in(index_in), 32 | .data_out(data_out), 33 | .op_done(op_done), 34 | .op_in_progress(op_in_progress), 35 | .op_error(op_error) 36 | ); 37 | ``` 38 | 39 | ## Parameters 40 | 41 | | Parameter | Description | Default | 42 | |--------------|--------------------------------------------------|---------| 43 | | DATA_WIDTH | Width of each data element in bits | 32 | 44 | | LENGTH | Maximum number of elements in the list | 8 | 45 | | SUM_METHOD | Method for calculating sum (0: parallel, 1: sequential, 2: adder tree) | 0 | 46 | 47 | ## IO Ports 48 | 49 | | Port | Direction | Width | Description | 50 | |----------------|-----------|-------------------------------|-------------------------------------------| 51 | | clk | input | 1 | System clock | 52 | | rst | input | 1 | Reset signal (active high) | 53 | | op_sel | input | 2 | Operation selector | 54 | | op_en | input | 1 | Operation enable | 55 | | data_in | input | DATA_WIDTH | Input data for write operations | 56 | | index_in | input | LENGTH_WIDTH | Index for read/write operations | 57 | | data_out | output | LENGTH_WIDTH+DATA_WIDTH | Output data | 58 | | op_done | output | 1 | Operation completion indicator | 59 | | op_in_progress | output | 1 | Operation is in progress | 60 | | op_error | output | 1 | Operation error indicator | 61 | 62 | ## Operation Codes 63 | 64 | | op_sel | Operation | Description | 65 | |--------|---------------------|------------------------------------------| 66 | | 3'b000 | Read | Read data from specified index | 67 | | 3'b001 | Insert | Write data to specified index | 68 | | 3'b010 | Find All Indices | Find all indices matching data_in | 69 | | 3'b011 | Find First Index | Find first index matching data_in | 70 | | 3'b100 | Sum | Calculate sum of all elements | 71 | | 3'b101 | Sort Ascending | Sort elements in ascending order | 72 | | 3'b110 | Sort Descending | Sort elements in descending order | 73 | 74 | ## State Machine 75 | The module implements a simple state machine with the following states: 76 | - **IDLE**: Default state, waiting for operation 77 | - **SUM**: Calculating sum in progress (for sequential or adder tree methods) 78 | - **SORT**: Sorting the list in progress (implementation in progress) 79 | - **ACCESS_DONE**: Operation completed, transitioning back to IDLE 80 | 81 | ## Implementation Notes 82 | - The internal storage is implemented as a register array, which could be replaced with RAM for larger data sizes 83 | - The parallel sum implementation uses combinatorial logic 84 | - Sequential sum and adder tree implementations are placeholders in the current version 85 | 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 | 7 | ![Verilog](https://img.shields.io/badge/Verilog-IEEE_1364--2005-blue) 8 | ![SystemVerilog](https://img.shields.io/badge/SystemVerilog-IEEE_1800--2017-blue) 9 | ![Python](https://img.shields.io/badge/Python-3.8%2B-blue) 10 | ![Version](https://img.shields.io/badge/Version-v1.0-green) 11 | ![Status](https://img.shields.io/badge/Status-In_Development-yellow) 12 | 13 |
14 | 15 | # RTLStructLib 16 | Highly optimized (trying my best), synthesizable data structures module/IP library for hardware design 17 | 18 | ### Overview 19 | RTLStructlib is an open-source project providing a collection of synthesizable RTL data structures implemented at the Register-Transfer Level (RTL). These modules are designed for high performance, scalability, and ease of integration into digital systems, serving as a standard library for FPGA and ASIC engineers. 20 | By using these pre-built RTL modules, engineers can accelerate development, reduce verification time, and focus on higher-level system design. 21 | 22 | ### Features 23 | ✅ Synthesizable, Optimized, Modular and Reusable
24 | ✅ Fully parameterized
25 | ✅ Comprehensive verification sequence and testbench
26 | ✅ Verification Agent (WIP)
27 | ✅ Open-source and community-driven
28 | 29 | ### Supported Data Structures 30 | - FIFO (First-In-First-Out) Queue – Parameterized depth, support for synchronous & asynchronous modes
31 | - LIFO (Last-In-First-Out) Stack – Configurable width and depth
32 | - Singly Linked List – Efficient memory utilization, dynamic data handling
33 | - Doubly Linked List – Bi-directional traversal support
34 | - Table - Indexed storage mechanism, similar to a register file, enabling rapid direct access and simultaneous read write access to data without hashing.
35 | - List - Support sorting, find_index, delete, insert operations
36 | - Circular Linked List (WIP) 37 | - Hash Table – Optimized for high-speed lookups, currently only supports modulus hashing and simple multi-staged chaining to handle collision
38 | - Dual Edge Flip Flop - Double input and output rate structure which can latch data on both rising and falling edge
39 | - Systolic Array (WIP) - Organizes processing elements in a regular grid where data flows rhythmically, enabling parallel computation.
40 | - Binary Tree (WIP) – Fundamental structure for hierarchical data organization
41 | - AVL Tree (WIP) – Self-balancing binary search tree for efficient operations
42 | - And More and More and More (WIP) 43 | 44 | ### License 45 | This project is licensed under the MIT License – see the LICENSE file for details. 46 | 47 | ### Getting Started 48 | 1️⃣ Install required tools and package 49 | ``` bash 50 | sudo apt install make git iverilog yosys gtkwave 51 | pip install cocotb 52 | pip install cocotb-bus 53 | ``` 54 | 55 | 1️⃣ Clone the Repository
56 | ``` bash 57 | git clone https://github.com/Weiyet/RTL_Data_Structure.git 58 | ``` 59 | 60 | 2️⃣ Directory Structure of Each Data Structure Module
61 | ```` 62 | 📦 / # Data Structure Module as folder name
63 | ├── 📃 readme.md # Documentation of waveform, modules IOs, parameter.
64 | ├── 📂 src/ # RTL Source Code
65 | │ ├── 📃 rtl_list.f # RTL file list required for the modules
66 | ├── 📂 tb/ # Testbench Directory
67 | │ ├── 📂 cocotb/ # Python Cocotb (Non-UVM) Testbench
68 | │ ├── 📂 sv/ # SystemVerilog (Non-UVM) Testbench
69 | ├── 📂 vip/ # Verification IP
70 | │ ├── 📂 uvm/ # system verilog UVM
71 | | | ├── 📃 readme.md # Documentation of VIP
72 | │ ├── 📂 pyuvm/ # python UVM
73 | | | ├── 📃 readme.md # Documentation of VIP
74 | ```` 75 | 2️⃣ RTL Simulation and Verification 76 | ``` bash 77 | # System Verilog Simulation 78 | cd /tb/sv 79 | make sim 80 | # Python CocoTB Simulation 81 | cd /tb/cocotb 82 | make 83 | ``` 84 | 3️⃣ Synthesis and Netlist simulation 85 | ``` bash 86 | make synth 87 | ``` 88 | 4️⃣ To view VCD waveform 89 | ``` bash 90 | gtkwave 91 | ``` 92 | 5️⃣ Integrate to your project 93 | Include file list /src/rtl_list.f to your simulation or project. 94 | 95 | ### Work in Progress/Future Works 🚀 96 | 🔹 Implementing Hash Table, Binary Tree, AVL Tree and more and more
97 | 🔹 Providing comprehensive test benches (TB) for verification
98 | 🔹 Exploring pyUVM for developing UVM & pyUVM agents
99 | 🔹 Improving performance & adding more use cases
100 | 101 | ### Disclaimer 102 | Hardware is often highly customized — these modules are designed as references, and you're encouraged to tweak them as needed (e.g., swap registers with RAM, adjust logic latency based on your STA, use content addressable RAM instead of RTL hash table). 103 | 104 | 105 | -------------------------------------------------------------------------------- /List/src/adder.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Module Name: adder 4 | // Create Date: 11/05/2025 01:58 AM 5 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 6 | // Last Update: 19/06/2025 09:25 PM 7 | // Last Updated By: https://www.linkedin.com/in/wei-yet-ng-065485119/ 8 | // Description: 9 | // Additional Comments: 10 | // 11 | ////////////////////////////////////////////////////////////////////////////////// 12 | 13 | module adder #( 14 | parameter DATA_WIDTH = 32, 15 | parameter LENGTH = 8, //need not to be power of 2 16 | parameter SUM_METHOD = 0, // 0: parallel (combo) sum, 1: sequential sum, 2: adder tree. //ICARUS does not support string overriden to parameter in CLI. 17 | localparam LENGTH_WIDTH = $clog2(LENGTH), 18 | localparam DATA_OUT_WIDTH = $clog2(LENGTH)+DATA_WIDTH-1 19 | )( 20 | input wire clk, 21 | input wire rst, 22 | input wire [LENGTH*DATA_WIDTH-1:0] data_in, 23 | input wire sum_en, 24 | output reg [LENGTH_WIDTH+DATA_WIDTH-1:0] sum_result, 25 | output reg sum_done, 26 | output reg sum_in_progress 27 | ); 28 | 29 | localparam NO_OF_STAGE = $clog2(LENGTH); 30 | localparam STG_PTR_WIDTH = $clog2(NO_OF_STAGE); 31 | localparam TOTAL_INPUT_INT = 2**NO_OF_STAGE; // round up to integer, LENGTH needs not to be in power of 2. 32 | 33 | reg [DATA_WIDTH-1:0] data_in_unpacked [LENGTH-1:0]; 34 | reg [LENGTH_WIDTH-1:0] cur_ptr; 35 | reg [STG_PTR_WIDTH-1:0] stg_ptr; 36 | reg [DATA_WIDTH-1:0] output_stage [NO_OF_STAGE-1:0][TOTAL_INPUT_INT-1:0]; 37 | integer i,j; 38 | 39 | // icarus does not support stream unpacking, so we need to do it mannually 40 | // always @ (*) begin 41 | // data_in_unpacked = { >> DATA_WIDTH {data_in}}; 42 | // end 43 | always @(*) begin 44 | for (i = 0; i < LENGTH; i = i + 1) begin 45 | data_in_unpacked[i] = data_in[i*DATA_WIDTH +: DATA_WIDTH]; 46 | end 47 | end 48 | // icarus does not support stream unpacking, so we need to do it mannually 49 | 50 | generate 51 | if(SUM_METHOD == 0) begin //: parallel sum (Combo) 52 | always @(*) begin 53 | for(i=0; i 0): 131 | cocotb.log.error("Errors count = %d",err_cnt) 132 | #cocotb.result.test_fail() 133 | #assert False, f"Test failed with {err_cnt} errors" 134 | raise cocotb.result.TestFailure(f"Test failed with {err_cnt} errors") 135 | -------------------------------------------------------------------------------- /FIFO/src/fifo.sv: -------------------------------------------------------------------------------- 1 | module fifo #( 2 | parameter DEPTH = 12, 3 | parameter DATA_WIDTH = 8, 4 | parameter ASYNC = 1, 5 | parameter RD_BUFFER = 1 6 | )( 7 | input wire rd_clk, 8 | input wire wr_clk, 9 | input wire rst, 10 | input wire [DATA_WIDTH-1:0] data_wr, 11 | input wire wr_en, 12 | output reg fifo_full, 13 | output logic [DATA_WIDTH-1:0] data_rd, 14 | input wire rd_en, 15 | output wire fifo_empty 16 | ); 17 | localparam CNTR_WIDTH = clogb2(DEPTH); 18 | 19 | reg [CNTR_WIDTH-1:0] rd_gray_pointer, rd_binary_pointer; 20 | wire [CNTR_WIDTH-1:0] rd_binary_pointer_next; 21 | reg [CNTR_WIDTH-1:0] wr_gray_pointer, wr_binary_pointer; 22 | wire [CNTR_WIDTH-1:0] wr_binary_pointer_next; 23 | reg [DATA_WIDTH-1:0] fifo_stored [DEPTH-1:0]; 24 | reg [CNTR_WIDTH-1:0] rd_gray_pointer_sync[1:0]; 25 | reg [CNTR_WIDTH-1:0] wr_gray_pointer_sync[1:0]; 26 | wire rdptr_eq_next_wrptr; 27 | 28 | generate //: POINTER_SYNCHRONIZER 29 | if (ASYNC == 1) begin 30 | always @ (posedge rd_clk, posedge rst) begin 31 | if(rst) begin 32 | {wr_gray_pointer_sync[1], wr_gray_pointer_sync[0]} <= {(2*CNTR_WIDTH){1'b0}}; 33 | end else begin 34 | {wr_gray_pointer_sync[1], wr_gray_pointer_sync[0]} <= {wr_gray_pointer_sync[0], wr_gray_pointer}; 35 | end 36 | end 37 | 38 | always @ (posedge wr_clk, posedge rst) begin 39 | if(rst) begin 40 | {rd_gray_pointer_sync[1], rd_gray_pointer_sync[0]} <= {(2*CNTR_WIDTH){1'b0}}; 41 | end else begin 42 | {rd_gray_pointer_sync[1], rd_gray_pointer_sync[0]} <= {rd_gray_pointer_sync[0], rd_gray_pointer}; 43 | end 44 | end 45 | end 46 | endgenerate 47 | 48 | // data_wr, wr_binary_pointer, wr_gray_pointer 49 | assign wr_binary_pointer_next = (wr_binary_pointer == DEPTH-1) ? {CNTR_WIDTH{1'b0}} : wr_binary_pointer + 1; 50 | 51 | integer i; 52 | 53 | always @ (posedge wr_clk, posedge rst) begin 54 | if(rst) begin 55 | wr_binary_pointer <= {CNTR_WIDTH{1'b0}}; 56 | end else if((wr_en & !rdptr_eq_next_wrptr) | (fifo_full & !rdptr_eq_next_wrptr)) begin 57 | // 1. When next write pointer == read pointer AND wr_en, it means last entry of FIFO is being filled, do not update pointer, else update pointer. 58 | // 2. Update when fifo_full flag is cleared. 59 | wr_binary_pointer <= wr_binary_pointer_next; 60 | end 61 | end 62 | 63 | always @ (posedge wr_clk, posedge rst) begin 64 | if(rst) begin 65 | for (i = 0; i < DEPTH; i = i + 1) 66 | fifo_stored[i] <= {DATA_WIDTH{1'b0}}; 67 | end else if (wr_en & !fifo_full) begin 68 | fifo_stored[wr_binary_pointer] <= data_wr; 69 | end 70 | end 71 | 72 | generate 73 | if(ASYNC == 1) begin 74 | always @ (posedge wr_clk, posedge rst) begin 75 | if(rst) begin 76 | wr_gray_pointer <= {CNTR_WIDTH{1'b0}}; 77 | end else if ((wr_en & !rdptr_eq_next_wrptr) | (fifo_full & !rdptr_eq_next_wrptr)) begin 78 | // 1. When next write pointer == read pointer AND wr_en, it means last entry of FIFO is being filled, do not update pointer, else update pointer. 79 | // 2. Update when fifo_full flag is cleared. 80 | wr_gray_pointer <= bin_to_gray(wr_binary_pointer_next); 81 | end 82 | end 83 | end 84 | endgenerate 85 | 86 | 87 | // data_rd, rd_binary_pointer, rd_gray_pointer 88 | assign rd_binary_pointer_next = (rd_binary_pointer == DEPTH-1) ? {CNTR_WIDTH{1'b0}} : rd_binary_pointer + 1; 89 | 90 | always @ (posedge rd_clk, posedge rst) begin 91 | if(rst) begin 92 | rd_binary_pointer <= {CNTR_WIDTH{1'b0}}; 93 | end else if (rd_en & !fifo_empty) begin 94 | rd_binary_pointer <= rd_binary_pointer_next; 95 | end 96 | end 97 | 98 | generate 99 | if(RD_BUFFER == 1) begin 100 | always @ (posedge rd_clk, posedge rst) begin 101 | if(rst) 102 | data_rd <= {DATA_WIDTH{1'b0}}; 103 | else if (rd_en & !fifo_empty) 104 | data_rd <= fifo_stored[rd_binary_pointer]; 105 | end 106 | end else begin 107 | assign data_rd = (rd_en & !fifo_empty) ? fifo_stored[rd_binary_pointer] : {DATA_WIDTH{1'b0}}; 108 | end 109 | endgenerate 110 | 111 | generate 112 | if(ASYNC == 1) begin 113 | always @ (posedge rd_clk, posedge rst) begin 114 | if(rst) begin 115 | rd_gray_pointer <= {CNTR_WIDTH{1'b0}}; 116 | end else if(rd_en & !fifo_empty) begin 117 | rd_gray_pointer <= bin_to_gray(rd_binary_pointer_next); 118 | end 119 | end 120 | end 121 | endgenerate 122 | 123 | // flag 124 | generate 125 | if (ASYNC == 1) begin 126 | assign rdptr_eq_next_wrptr = (rd_gray_pointer_sync[1] == bin_to_gray(wr_binary_pointer_next)); 127 | assign fifo_empty = wr_gray_pointer_sync[1] == bin_to_gray(rd_binary_pointer); 128 | //assign fifo_full = rd_gray_pointer_sync[1] == bin_to_gray(wr_binary_pointer_next); 129 | end else begin 130 | assign rdptr_eq_next_wrptr = (rd_binary_pointer == wr_binary_pointer_next); 131 | assign fifo_empty = wr_binary_pointer == rd_binary_pointer; 132 | //assign fifo_full = rd_binary_pointer == wr_binary_pointer_next; 133 | end 134 | endgenerate 135 | 136 | always@(posedge wr_clk, posedge rst) begin 137 | if(rst) begin 138 | fifo_full <= 1'b0; 139 | end else if(wr_en & rdptr_eq_next_wrptr) begin 140 | // When next write pointer == read pointer AND wr_en, it means last entry of FIFO is being filled, do not update pointer, 141 | fifo_full <= 1'b1; 142 | end else if(!rdptr_eq_next_wrptr) begin 143 | // Deassert when any read operation is completed: write pointer != read pointer 144 | fifo_full <= 1'b0; 145 | end 146 | end 147 | 148 | function integer clogb2; 149 | input integer value; 150 | value = value - (value > 1); 151 | for(clogb2=0; value>0; value = value>>1) 152 | clogb2 = clogb2 + 1; 153 | endfunction 154 | 155 | function [CNTR_WIDTH-1:0] bin_to_gray; 156 | input [CNTR_WIDTH-1:0] bin; 157 | bin_to_gray = bin[CNTR_WIDTH-1:0] ^ (bin[CNTR_WIDTH-1:0] >> 1); 158 | endfunction 159 | 160 | endmodule 161 | -------------------------------------------------------------------------------- /Table/tb/sv/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Create Date: 05/05/2024 03:37:34 PM 5 | // Last Update Date: 01/02/2024 10:37:12 AM 6 | // Module Name: tb 7 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 8 | // Description: 1. table_write_random() --> table_read_compare() 9 | // Additional Comments: 10 | // 11 | ////////////////////////////////////////////////////////////////////////////////// 12 | 13 | 14 | module tb( 15 | ); 16 | parameter TABLE_SIZE = 32; 17 | parameter DATA_WIDTH = 8; 18 | parameter INPUT_RATE = 2; 19 | parameter OUTPUT_RATE = 2; 20 | parameter TB_CLK_PERIOD = 100; 21 | parameter TB_TEST_WEIGHT = 1; 22 | parameter TB_SIM_TIMEOUT = 30; //ms. 23 | 24 | localparam MAX_DATA = 2**(DATA_WIDTH) - 1; 25 | localparam INDEX_WIDTH = $clog2(TABLE_SIZE-1); 26 | 27 | bit [DATA_WIDTH-1:0] table_expected [TABLE_SIZE]; 28 | integer index_queue[$]; 29 | 30 | reg clk=0; 31 | reg rst=0; 32 | reg wr_en=0; 33 | reg rd_en=0; 34 | reg [INPUT_RATE*$clog2(TABLE_SIZE)-1:0] index_wr=0; 35 | reg [OUTPUT_RATE*$clog2(TABLE_SIZE)-1:0] index_rd=0; 36 | reg [INPUT_RATE*DATA_WIDTH-1:0] data_wr=0; 37 | wire [OUTPUT_RATE*DATA_WIDTH-1:0] data_rd; 38 | 39 | reg [DATA_WIDTH-1:0] data_wr_rand; 40 | reg [$clog2(TABLE_SIZE)-1:0] index_wr_rand; 41 | 42 | integer err_cnt = 0; 43 | 44 | `ifdef XILINX_GLS 45 | glbl glbl (); // for Xilinx GLS 46 | `endif 47 | 48 | table_top #( 49 | .TABLE_SIZE(TABLE_SIZE), 50 | .DATA_WIDTH(DATA_WIDTH), 51 | .INPUT_RATE(INPUT_RATE), 52 | .OUTPUT_RATE(OUTPUT_RATE)) DUT ( 53 | /*input wire*/ .clk(clk), 54 | /*input wire*/ .rst(rst), 55 | /*input wire*/ .wr_en(wr_en), 56 | /*input wire*/ .rd_en(rd_en), 57 | /*input wire [INPUT_RATE*$clog2(TABLE_SIZE)-1:0]*/ .index_wr(index_wr), 58 | /*input wire [OUTPUT_RATE*$clog2(TABLE_SIZE)-1:0]*/ .index_rd(index_rd), 59 | /*input wire [INPUT_RATE*DATA_WIDTH-1:0]*/ .data_wr(data_wr), 60 | /*output reg [OUTPUT_RATE*DATA_WIDTH-1:0]*/ .data_rd(data_rd)); 61 | 62 | always #(TB_CLK_PERIOD>>1) clk = ~clk; 63 | 64 | task table_write_random (input integer count); 65 | for (int i=0; i> DATA_WIDTH {data_in}}; 48 | // end 49 | always @(*) begin 50 | for (i = 0; i < LENGTH; i = i + 1) begin 51 | data_in_unpacked[i] = data_in[i*DATA_WIDTH +: DATA_WIDTH]; 52 | end 53 | end 54 | // icarus does not support stream unpacking, so we need to do it manually 55 | 56 | // icarus does not support stream packing, so we need to do it manually 57 | // always @ (*) begin 58 | // data_sorted = {>> DATA_WIDTH {data_sorted_unpacked}}; 59 | // end 60 | always @(*) begin 61 | for (i = 0; i < LENGTH; i = i + 1) begin 62 | data_sorted[i*DATA_WIDTH +: DATA_WIDTH] = data_sorted_unpacked[i]; 63 | end 64 | end 65 | // icarus does not support stream packing, so we need to do it manually 66 | 67 | 68 | always @ (posedge clk, posedge rst) begin 69 | if(rst) begin 70 | sort_done <= 1'b0; 71 | sort_in_progress <= 1'b0; 72 | current_state <= IDLE; 73 | for(i=0; i temp) begin 119 | data_sorted_unpacked[cur_ptr+1] <= data_sorted_unpacked[cur_ptr]; 120 | data_sorted_unpacked[cur_ptr] <= temp; 121 | cur_ptr <= cur_ptr - 'b1; 122 | current_state <= (cur_ptr > 'd0) ? COMP_AND_SWAP : NEXT_KEY; 123 | end else if (data_sorted_unpacked[cur_ptr] <= temp | cur_ptr == 'b0) begin 124 | data_sorted_unpacked[cur_ptr+1] <= temp; 125 | current_state <= NEXT_KEY; 126 | end 127 | end else begin 128 | if(data_sorted_unpacked[cur_ptr] < temp) begin 129 | data_sorted_unpacked[cur_ptr+1] <= data_sorted_unpacked[cur_ptr]; 130 | data_sorted_unpacked[cur_ptr] <= temp; 131 | cur_ptr <= cur_ptr - 'b1; 132 | current_state <= (cur_ptr > 'd0) ? COMP_AND_SWAP : NEXT_KEY; 133 | end else if(data_sorted_unpacked[cur_ptr] >= temp | cur_ptr == 'b0) begin 134 | data_sorted_unpacked[cur_ptr+1] <= temp; 135 | current_state <= NEXT_KEY; 136 | end 137 | end 138 | end 139 | 140 | SORT_DONE: begin 141 | current_state <= IDLE; 142 | sort_done <= 1'b0; 143 | sort_in_progress <= 1'b0; 144 | end 145 | endcase 146 | end 147 | end 148 | 149 | endmodule -------------------------------------------------------------------------------- /Dual_Edge_FF/tb/sv/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Create Date: 09/22/2024 01:42:52 PM 4 | // Created By: https://www.linkedin.com/in/wei-yet-ng-065485119/ 5 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 6 | // Last Update: 13/06/2025 09:23 PM 7 | // Last Updated By: https://www.linkedin.com/in/wei-yet-ng-065485119/ 8 | // Module Name: tb 9 | // Description: Testbench for dual_edge_ff module. 10 | // Additional Comments: 11 | // 12 | ////////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | module tb( 16 | ); 17 | // DUT parameter 18 | localparam DUT_DATA_WIDTH = 8; 19 | localparam DUT_RESET_VALUE = 0; // Max number of nodes in the list 20 | 21 | // TB parameter 22 | localparam TB_CLK_PERIOD = 25; 23 | localparam TB_TEST_WEIGHT = 1; 24 | localparam SIM_TIMEOUT = 500000; 25 | 26 | integer err_cnt = 0; 27 | 28 | // input 29 | reg clk = 0; 30 | reg rst_n = 1; 31 | reg [DUT_DATA_WIDTH-1:0] data_in = 0; 32 | reg [DUT_DATA_WIDTH-1:0] pos_edge_latch_en = 0; 33 | reg [DUT_DATA_WIDTH-1:0] neg_edge_latch_en = 0; 34 | // output 35 | wire [DUT_DATA_WIDTH-1:0] data_out; 36 | 37 | `ifdef XILINX_GLS 38 | // for xilinx gate sim 39 | glbl glbl(); 40 | `endif 41 | 42 | 43 | 44 | dual_edge_ff #( 45 | .DATA_WIDTH(DUT_DATA_WIDTH), 46 | .RESET_VALUE(DUT_RESET_VALUE) 47 | ) DUT ( 48 | /*input wire */.clk(clk), 49 | /*input wire */.rst_n(rst_n), 50 | /*input wire [DATA_WIDTH-1:0] */.data_in(data_in), 51 | /*input wire [DATA_WIDTH-1:0] */.pos_edge_latch_en(pos_edge_latch_en), 52 | /*input wire [DATA_WIDTH-1:0] */.neg_edge_latch_en(neg_edge_latch_en), 53 | /*output wire [DATA_WIDTH-1:0] */.data_out(data_out) 54 | ); 55 | 56 | always #(TB_CLK_PERIOD/2) clk = ~clk; 57 | 58 | integer i = 0; 59 | integer j = 0; 60 | reg [DUT_DATA_WIDTH-1:0] target_data_wr; 61 | 62 | task direct_test(); 63 | begin 64 | $display("Starting direct operation test"); 65 | for (i = 0; i<50; i=i+1) begin 66 | j = $urandom_range(0,2); 67 | case (j) 68 | 0: begin //posedge only 69 | @ (negedge clk) // change data_in at negedge, expect DUT to latch at next posedge 70 | #1; 71 | pos_edge_latch_en= 2**DUT_DATA_WIDTH -1; 72 | target_data_wr = $urandom; 73 | data_in = target_data_wr; 74 | @ (posedge clk) 75 | #1; 76 | if (data_out != target_data_wr) begin 77 | $error("%0t Data out is incorrect at posedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 78 | err_cnt = err_cnt + 1; 79 | end else begin 80 | $display("%0t Data out is correctly latched at posedge with value %0d", $realtime, data_out); 81 | end 82 | 83 | data_in = target_data_wr + 1; 84 | @ (negedge clk) 85 | #1; 86 | if (data_out != target_data_wr) begin 87 | $error("%0t Data out is incorrect, should not be updated at posedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 88 | err_cnt = err_cnt + 1; 89 | end 90 | pos_edge_latch_en = 1'b0; 91 | 92 | end 93 | 1: begin //negedge only 94 | @ (posedge clk) // change data in at posedge, expect DUT to latch at next negedge 95 | #1; 96 | neg_edge_latch_en= 2**DUT_DATA_WIDTH -1; 97 | target_data_wr = $urandom; 98 | data_in = target_data_wr; 99 | @ (negedge clk) 100 | #1; 101 | if (data_out != target_data_wr) begin 102 | $error("%0t Data out is incorrect at negedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 103 | err_cnt = err_cnt + 1; 104 | end else begin 105 | $display("%0t Data out is correctly latched at negedge with value %0d", $realtime, data_out); 106 | end 107 | 108 | data_in = target_data_wr + 1; 109 | @ (posedge clk) 110 | #1; 111 | if (data_out != target_data_wr) begin 112 | $error("%0t Data out is incorrect, should not be updated at posedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 113 | err_cnt = err_cnt + 1; 114 | end 115 | neg_edge_latch_en = 1'b0; 116 | 117 | end 118 | default: begin // both edge 119 | @ (posedge clk) // change data in at posedge, expect DUT to latch at next negedge 120 | #1; 121 | neg_edge_latch_en= 2**DUT_DATA_WIDTH -1; 122 | pos_edge_latch_en= 2**DUT_DATA_WIDTH -1; 123 | target_data_wr = $urandom; 124 | data_in = target_data_wr; 125 | @ (negedge clk) 126 | #1; 127 | if (data_out != target_data_wr) begin 128 | $error("%0t Data out is incorrect at negedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 129 | err_cnt = err_cnt + 1; 130 | end else begin 131 | $display("%0t Data out is correctly latched at negedge with value %0d", $realtime, data_out); 132 | end 133 | 134 | target_data_wr = $urandom; 135 | data_in = target_data_wr; 136 | @ (posedge clk) 137 | #1; 138 | if (data_out != target_data_wr) begin 139 | $error("%0t Data out is incorrect at posedge, EXP: %0d, ACT: %0d",$realtime, target_data_wr, data_out); 140 | err_cnt = err_cnt + 1; 141 | end else begin 142 | $display("%0t Data out is correctly latched at posedge with value %0d", $realtime, data_out); 143 | end 144 | neg_edge_latch_en= 0; 145 | pos_edge_latch_en= 0; 146 | end 147 | 148 | endcase; 149 | 150 | end 151 | 152 | 153 | end 154 | endtask 155 | 156 | initial begin 157 | string vcdfile; 158 | int vcdlevel; 159 | int seed; 160 | int temp; 161 | 162 | rst_n = 1'b0; 163 | if ($value$plusargs("VCDFILE=%s",vcdfile)) 164 | $dumpfile(vcdfile); 165 | if ($value$plusargs("VCDLEVEL=%d",vcdlevel)) 166 | $dumpvars(vcdlevel,tb); 167 | if ($value$plusargs("SEED=%d",seed)) begin 168 | temp = $urandom(seed); 169 | $display("Seed = %0d",seed); 170 | end 171 | #100; 172 | rst_n = 1'b1; 173 | direct_test(); 174 | 175 | #1000; 176 | 177 | if (err_cnt > 0) begin 178 | $display("\n%0t TEST FAILED",$realtime); 179 | $display("Error count = %0d\n", err_cnt); 180 | end else 181 | $display("\n%0t TEST PASSED\n", $realtime); 182 | $finish; 183 | end 184 | 185 | initial begin 186 | #(SIM_TIMEOUT) 187 | $display("\n%0t TEST FAILED", $realtime); 188 | $display("SIM TIMEOUT!\n"); 189 | $finish; 190 | end 191 | 192 | endmodule 193 | 194 | -------------------------------------------------------------------------------- /LIFO/tb/cocotb/tb.py: -------------------------------------------------------------------------------- 1 | import random 2 | #import asyncio 3 | import cocotb 4 | from cocotb.triggers import Timer, RisingEdge, ReadOnly 5 | from cocotb.clock import Clock 6 | from cocotb_bus.drivers import BusDriver 7 | from cocotb_bus.monitors import BusMonitor 8 | 9 | DEPTH = 12 # DUT parameter 10 | DATA_WIDTH = 8 # DUT paramter 11 | TEST_WEIGHT = 1 # TB multiplier for stimulus injected 12 | CLK_PERIOD = 20 # TB clk generator 13 | #SIM_TIMEOUT = 100000; // TB simulation time out 14 | MAX_DATA = 2**DATA_WIDTH - 1 15 | err_cnt = 0 16 | 17 | # lifo #( 18 | # .DEPTH(DEPTH), 19 | # .DATA_WIDTH(DATA_WIDTH)) DUT ( 20 | # /*input wire*/ .clk(clk), 21 | # /*input wire*/ .rst(rst), 22 | # /*input wire [DATA_WIDTH-1:0]*/ .data_wr(data_wr), 23 | # /*input wire*/ .wr_en(wr_en), 24 | # /*output reg*/ .lifo_full(lifo_full), 25 | # /*output reg [DATA_WIDTH-1:0]*/ .data_rd(data_rd), 26 | # /*input wire*/ .rd_en(rd_en), 27 | # /*output wire*/ .lifo_empty(lifo_empty)); 28 | 29 | class OutputDriver(BusDriver): 30 | _signals = ["wr_en", "rd_en", "data_wr"] #dut.wr_en ; dut.rd_en; dut.data_wr 31 | 32 | def __init__(self, dut, name, clk): 33 | BusDriver.__init__(self, dut, name, clk) 34 | self.bus.wr_en.value = 0 35 | self.bus.rd_en.value = 0 36 | self.dut = dut 37 | self.clk = clk 38 | 39 | async def _driver_send(self, op_sel, op_count): 40 | match op_sel: 41 | case 0: 42 | wr_data_array = [] 43 | for i in range (op_count): 44 | wr_data_array.append(random.randint(0,MAX_DATA)) 45 | await self.lifo_write(wr_data_array) 46 | case 1: 47 | await self.lifo_read(op_count) 48 | case 2: 49 | wr_data_array = [] 50 | for i in range (op_count): 51 | wr_data_array.append(random.randint(0,MAX_DATA)) 52 | await self.lifo_read_write_simul(wr_data_array) 53 | 54 | async def lifo_write(self, wr_data_array): 55 | data_w = 0 56 | while len(wr_data_array) != 0: 57 | await RisingEdge(self.clk) 58 | await Timer (1, units = 'ns') 59 | self.bus.wr_en.value = 1 60 | data_w = wr_data_array.pop() 61 | self.bus.data_wr.value = data_w 62 | self.dut._log.info("Driver: Writting Data = %d",data_w) 63 | await RisingEdge(self.clk) 64 | self.bus.wr_en.value = 0 65 | 66 | async def lifo_read(self,op_count): 67 | for i in range(op_count): 68 | await RisingEdge(self.clk) 69 | self.bus.rd_en.value = 1 70 | self.dut._log.info("Driver: Reading Data = %d",) 71 | await RisingEdge(self.clk) 72 | await Timer (1, units='ns') 73 | self.bus.rd_en.value = 0 74 | 75 | async def lifo_read_write_simul(self,wr_data_array): 76 | data_w = 0 77 | while len(wr_data_array) != 0: 78 | await RisingEdge(self.clk) 79 | await Timer (1, units = 'ns') 80 | self.bus.rd_en.value = 1 81 | self.bus.wr_en.value = 1 82 | data_w = wr_data_array.pop() 83 | self.bus.data_wr.value = data_w 84 | self.dut._log.info("Driver: Simultanenous read write, data = %d",data_w) 85 | await RisingEdge(self.clk) 86 | await Timer (1, units='ns') 87 | self.bus.rd_en.value = 0 88 | self.bus.wr_en.value = 0 89 | 90 | class InputMonitor(BusMonitor): 91 | _signals = ["wr_en","rd_en","lifo_empty","lifo_full","data_rd","data_wr"] 92 | 93 | def __init__(self, dut, name, clk, reset): 94 | BusMonitor.__init__(self, dut, name, clk, reset) 95 | self.clk = clk 96 | self.reset = reset 97 | self.dut = dut 98 | 99 | async def _monitor_recv(self): 100 | global err_cnt 101 | lifo_expected = [] 102 | rd_en_buf = 0 103 | wr_en_buf = 0 104 | data_wr_buf = 0 105 | while True: 106 | await RisingEdge(self.clock) 107 | await Timer(3,units='ns') 108 | await ReadOnly() 109 | 110 | if self.reset.value == 1: 111 | rd_en_buf = 0 112 | wr_en_buf = 0 113 | data_wr_buf = 0 114 | continue 115 | 116 | if(rd_en_buf == 1 and wr_en_buf == 1): 117 | if(self.bus.data_rd.value == data_wr_buf): 118 | self.dut._log.info("Monitor: Simultaneous Data read/write, ACT = %d, EXP = %d, FIFO entry = %d", self.bus.data_rd.value, data_wr_buf, len(lifo_expected)) 119 | elif(wr_en_buf and len(lifo_expected) != DEPTH): 120 | lifo_expected.append(data_wr_buf) 121 | self.dut._log.info("Monitor: Data write = %d, FIFO entry = %d", data_wr_buf, len(lifo_expected)) 122 | elif(rd_en_buf == 1 and len(lifo_expected) != 0): 123 | lifo_expected.pop() 124 | self.dut._log.info("Monitor: Data read = %d, FIFO entry = %d", self.bus.data_rd.value, len(lifo_expected)) 125 | 126 | if(len(lifo_expected) == 0): 127 | if(self.bus.lifo_empty.value): 128 | self.dut._log.info("Monitor: LIFO is empty, lifo_full flag is asserted correctly") 129 | else: 130 | self.dut._log.error("Monitor: LIFO is empty, but lifo_full flag is not asserted") 131 | err_cnt += 1 132 | elif(self.bus.lifo_empty.value): 133 | self.dut._log.error("Monitor: LIFO is not empty, but lifo_empty flag is asserted") 134 | 135 | if(len(lifo_expected) == DEPTH): 136 | if(self.bus.lifo_full.value): 137 | self.dut._log.info("Monitor: LIFO is full, lifo_full flag is asserted correctly") 138 | else: 139 | self.dut._log.error("Monitor: LIFO is full, but lifo_full flag is not asserted") 140 | err_cnt += 1 141 | elif(self.bus.lifo_full.value): 142 | self.dut._log.error("Monitor: LIFO is not full, but lifo_full flag is asserted") 143 | 144 | rd_en_buf = int(self.bus.rd_en.value) 145 | wr_en_buf = int(self.bus.wr_en.value) 146 | data_wr_buf = int(self.bus.data_wr.value) 147 | 148 | 149 | async def dut_init(dut): 150 | global DEPTH 151 | global DATA_WIDTH 152 | global MAX_DATA 153 | DEPTH = dut.DEPTH.value 154 | DATA_WIDTH = dut.DATA_WIDTH.value 155 | MAX_DATA = 2**DATA_WIDTH - 1 156 | await cocotb.start(Clock(dut.clk, CLK_PERIOD, units="ns").start()) 157 | dut.data_wr.value = 0 158 | dut.rd_en.value = 0 159 | dut.wr_en.value = 0 160 | dut.rst.value = 1 161 | await(Timer(100,'ns')) 162 | dut.rst.value = 0 163 | await(Timer(100,'ns')) 164 | 165 | 166 | @cocotb.test() 167 | async def lifo_rand_op_test(dut): 168 | await dut_init(dut) 169 | driver = OutputDriver(dut, None, dut.clk) #set name='None', refer to Bus class 170 | monitor = InputMonitor(dut, None, dut.clk, dut.rst) 171 | cocotb.log.info("SEED NUMBER = %d",cocotb.RANDOM_SEED) 172 | i = DEPTH 173 | lifo_expected = [] 174 | while(i >= 0): 175 | op_sel = random.randint(0,1) 176 | op_count = random.randint(1,5) 177 | i = i - op_count 178 | await driver._driver_send(op_sel,op_count) 179 | await Timer(CLK_PERIOD,'ns') 180 | if (err_cnt > 0): 181 | cocotb.log.error("Errors count = %d",err_cnt) 182 | cocotb.result.test_fail() 183 | -------------------------------------------------------------------------------- /LIFO/tb/sv/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Create Date: 05/05/2024 05:05:34 PM 5 | // Last Update Date: 05/05/2024 05:05:34 PM 6 | // Module Name: tb 7 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 8 | // Description: 1. lifo_random_op_test 9 | // - Read/Write/Read_write_simultaneous 10 | // Additional Comments: 11 | // 12 | ////////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | module tb( 16 | ); 17 | parameter DEPTH = 12; // DUT parameter 18 | parameter DATA_WIDTH = 8; // DUT paramter 19 | parameter CLK_PERIOD = 20; // TB clk generator 20 | parameter SIM_TIMEOUT = 100000; // TB simulation time out 21 | parameter TEST_WEIGHT = 1; //TB Test weight 22 | 23 | integer lifo_expected [$]; 24 | integer i; 25 | integer op_sel,op_count; 26 | integer err_cnt = 0; 27 | reg clk = 0; 28 | 29 | reg rst = 1; 30 | reg [DATA_WIDTH-1:0] data_wr = 0; 31 | reg wr_en = 0; 32 | reg rd_en = 0; 33 | wire [DATA_WIDTH-1:0] data_rd; 34 | wire lifo_empty; 35 | wire lifo_full; 36 | 37 | `ifdef XILINX_GLS 38 | // for xilinx gate sim 39 | glbl glbl(); 40 | `endif 41 | 42 | lifo #( 43 | .DEPTH(DEPTH), 44 | .DATA_WIDTH(DATA_WIDTH)) DUT ( 45 | /*input wire*/ .clk(clk), 46 | /*input wire*/ .rst(rst), 47 | /*input wire [DATA_WIDTH-1:0]*/ .data_wr(data_wr), 48 | /*input wire*/ .wr_en(wr_en), 49 | /*output reg*/ .lifo_full(lifo_full), 50 | /*output reg [DATA_WIDTH-1:0]*/ .data_rd(data_rd), 51 | /*input wire*/ .rd_en(rd_en), 52 | /*output wire*/ .lifo_empty(lifo_empty)); 53 | 54 | always #(CLK_PERIOD>>1) clk = ~clk; 55 | 56 | integer exp_data_wr = 0; 57 | 58 | task lifo_write(input integer wr_data_array[$]); 59 | while($size(wr_data_array) != 0) begin 60 | exp_data_wr = wr_data_array.pop_front(); 61 | @(posedge(clk)) 62 | wr_en <= 1; 63 | data_wr <= exp_data_wr; 64 | #1 65 | if($size(lifo_expected)0) begin 98 | if(lifo_empty) begin 99 | $error("%0t LIFO is not empty but lifo_empty flag is asserted incorrectly",$realtime); 100 | end 101 | #1 102 | act_data_rd = data_rd; 103 | exp_data_rd = lifo_expected.pop_back(); 104 | if(act_data_rd == exp_data_rd) begin 105 | $display("%0t Data read = %d, FIFO entry = %d", $realtime, act_data_rd, $size(lifo_expected)); 106 | end 107 | else begin 108 | $error("%0t Data read mismatch, ACT = %d, EXP =%d, FIFO entry = %d", $realtime, act_data_rd, exp_data_rd, $size(lifo_expected)); 109 | err_cnt = err_cnt + 1; 110 | end 111 | end else begin 112 | if(!lifo_empty) begin 113 | $error("%0t LIFO is empty but lifo_empty flag is not asserted",$realtime); 114 | err_cnt = err_cnt + 1; 115 | end 116 | else begin 117 | $display("%0t LIFO is empty, lifo_empty flag is asserted correctly",$realtime); 118 | end 119 | end 120 | end 121 | rd_en = 0; 122 | endtask 123 | 124 | task lifo_simul_read_write(input integer wr_data_array[$]); 125 | exp_data_wr = wr_data_array.pop_front(); 126 | @(posedge(clk)) 127 | rd_en <= 1; 128 | wr_en <= 1; 129 | data_wr <= exp_data_wr; 130 | 131 | while($size(wr_data_array) != 0) begin 132 | @(posedge(clk)) 133 | #1 134 | act_data_rd = data_rd; 135 | if(act_data_rd == exp_data_wr) begin 136 | $display("%0t Simultaneous Data read/write = %d, FIFO entry = %d", $realtime, act_data_rd, $size(lifo_expected)); 137 | end 138 | else begin 139 | $error("%0t Simultaneous Data read/write, ACT = %d, EXP = %d, FIFO entry = %d", $realtime, act_data_rd, exp_data_wr, $size(lifo_expected)); 140 | end 141 | #1 142 | exp_data_wr = wr_data_array.pop_front(); 143 | data_wr <= exp_data_wr; 144 | end 145 | @(posedge(clk)) 146 | wr_en <= 0; 147 | rd_en <= 0; 148 | #1 149 | act_data_rd = data_rd; 150 | if(act_data_rd == exp_data_wr) begin 151 | $display("%0t Simultaneous Data read/write = %d, FIFO entry = %d", $realtime, act_data_rd, $size(lifo_expected)); 152 | end 153 | else begin 154 | $error("%0t Simultaneous Data read/write, ACT = %d, EXP = %d, FIFO entry = %d", $realtime, act_data_rd, exp_data_wr, $size(lifo_expected)); 155 | end 156 | endtask 157 | 158 | integer wr_data_array[$]; 159 | integer k; 160 | 161 | task lifo_random_op_test(input integer count); 162 | i = count; 163 | while (i > 0) begin 164 | op_sel = $urandom_range(0,2); 165 | op_count = $urandom_range(1,i); 166 | i = i - op_count; 167 | case(op_sel) 168 | 0: begin // read 169 | $display("%0t LIFO Read %d times", $realtime, op_count); 170 | lifo_read(op_count); 171 | end 172 | 1: begin // write 173 | $display("%0t LIFO Write %d times", $realtime, op_count); 174 | for(k=0 ; k < op_count; k = k+1) begin 175 | wr_data_array.push_back($urandom_range(0,2**DATA_WIDTH-1)); 176 | end 177 | lifo_write(wr_data_array); 178 | end 179 | 2: begin // simultaneous read write 180 | $display("%0t LIFO Simul Read Write %d times", $realtime, op_count); 181 | for(k=0 ; k < op_count; k = k+1) begin 182 | wr_data_array.push_back($urandom_range(0,2**DATA_WIDTH-1)); 183 | end 184 | lifo_simul_read_write(wr_data_array); 185 | end 186 | endcase 187 | end 188 | endtask 189 | 190 | initial begin 191 | string vcdfile; 192 | int vcdlevel; 193 | int seed; 194 | int temp; 195 | if ($value$plusargs("VCDFILE=%s",vcdfile)) 196 | $dumpfile(vcdfile); 197 | if ($value$plusargs("VCDLEVEL=%d",vcdlevel)) 198 | $dumpvars(vcdlevel, tb); 199 | $display("Seed number: %d",vcdlevel); 200 | if ($value$plusargs("SEED=%d",seed)) begin 201 | $display("Seed number: %d",seed); 202 | temp = $urandom(seed); 203 | end 204 | 205 | repeat(TEST_WEIGHT) begin 206 | rst = 1; 207 | #100 208 | rst = 0; 209 | #100 210 | lifo_expected = {}; 211 | lifo_random_op_test(DEPTH); 212 | #1000; 213 | end 214 | if (err_cnt > 0) begin 215 | $display("\n%0t TEST FAILED",$realtime); 216 | $display("Error count = %d\n", err_cnt); 217 | end else 218 | $display("\n%0t TEST PASSED\n", $realtime); 219 | $finish; 220 | end 221 | 222 | initial begin 223 | #(SIM_TIMEOUT); 224 | $display("\n%0t TEST FAILED", $realtime); 225 | $display("SIM TIMEOUT!\n"); 226 | $finish; 227 | end 228 | 229 | endmodule 230 | -------------------------------------------------------------------------------- /Table/tb/cocotb/tb.py: -------------------------------------------------------------------------------- 1 | import random 2 | #import asyncio 3 | import math 4 | import cocotb 5 | from cocotb.triggers import Timer, RisingEdge, ReadOnly 6 | from cocotb.clock import Clock 7 | from cocotb_bus.drivers import BusDriver 8 | from cocotb_bus.monitors import BusMonitor 9 | from cocotb.binary import BinaryValue 10 | 11 | #BIN string 12 | #BinaryValue(dut.data_wr.value, n_bits=8) ; BinaryValue.integar ; BinaryValue.hex ; BinaryValue.binstr; BinaryValue.signed_integer ; can represent x,z 13 | 14 | TABLE_SIZE = 32 # DUT parameter 15 | DATA_WIDTH = 8 # DUT paramter 16 | INPUT_RATE = 1 # DUT parameter 17 | OUTPUT_RATE = 1 # DUT parameter 18 | INDEX_WIDTH = 1 19 | TB_CLK_PERIOD = 30 # TB clk generator 20 | TB_SIM_TIMEOUT = 30 # TB sim timeout 30ms 21 | TB_TEST_WEIGHT = 1 22 | table_expected = [0 for i in range(TABLE_SIZE)] 23 | err_cnt = 0 24 | 25 | # table_top #( 26 | # .TABLE_SIZE(TABLE_SIZE), 27 | # .DATA_WIDTH(DATA_WIDTH), 28 | # .INPUT_RATE(INPUT_RATE), 29 | # .OUTPUT_RATE(OUTPUT_RATE)) DUT ( 30 | # /*input wire*/ .clk(clk), 31 | # /*input wire*/ .rst(rst), 32 | # /*input wire*/ .wr_en(wr_en), 33 | # /*input wire*/ .rd_en(rd_en), 34 | # /*input wire [INPUT_RATE*$clog2(TABLE_SIZE)-1:0]*/ .index_wr(index_wr), 35 | # /*input wire [OUTPUT_RATE*$clog2(TABLE_SIZE)-1:0]*/ .index_rd(index_rd), 36 | # /*input wire [INPUT_RATE*DATA_WIDTH-1:0]*/ .data_wr(data_wr), 37 | # /*output reg [OUTPUT_RATE*DATA_WIDTH-1:0]*/ .data_rd(data_rd)); 38 | 39 | class OutputDriver(BusDriver): 40 | _signals = ["wr_en", "rd_en", "index_wr", "index_rd", "data_wr"] #dut.wr_en ; dut.rd_en; dut.index_wr; dut.data_wr 41 | 42 | def __init__(self, dut, name, clk): 43 | BusDriver.__init__(self, dut, name, clk) 44 | self.bus.wr_en.value = 0 45 | self.bus.rd_en.value = 0 46 | self.bus.index_wr.value = 0 47 | self.bus.index_rd.value = 0 48 | self.bus.data_wr.value = 0 49 | self.dut = dut 50 | self.clk = clk 51 | 52 | # async def _driver_send(self): 53 | async def write_burst(self, input_data): 54 | for i in range(0,len(input_data)//INPUT_RATE): 55 | await RisingEdge(self.clk) 56 | await Timer (1, units = 'ns') 57 | data_wr = 0 58 | index_wr = 0 59 | for j in range(0,INPUT_RATE): 60 | data_wr = (data_wr<<(j)*DATA_WIDTH) + input_data[i*INPUT_RATE+j][1] 61 | index_wr = (index_wr<<(j)*INDEX_WIDTH) + input_data[i*INPUT_RATE+j][0] 62 | self.bus.wr_en.value = 2**INPUT_RATE - 1 63 | self.bus.data_wr.value = data_wr 64 | self.bus.index_wr.value = index_wr 65 | await RisingEdge(self.clk) 66 | await Timer (1, units = 'ns') 67 | self.bus.wr_en.value = 0 68 | 69 | async def read_burst(self, target_index): 70 | for i in range(0,len(target_index)//OUTPUT_RATE): 71 | await RisingEdge(self.clk) 72 | await Timer (1, units = 'ns') 73 | index_rd = 0 74 | for j in range(0,OUTPUT_RATE): 75 | index_rd = (index_rd<<(j)*INDEX_WIDTH) + target_index[i*OUTPUT_RATE+j] 76 | #print(index_rd) 77 | self.bus.rd_en.value = 1 78 | self.bus.index_rd.value = index_rd 79 | await RisingEdge(self.clk) 80 | await Timer (1, units = 'ns') 81 | self.bus.rd_en.value = 0 82 | 83 | class InputMonitor(BusMonitor): 84 | _signals = ["wr_en","rd_en","index_wr","index_rd","data_wr","data_rd"] 85 | 86 | def __init__(self, dut, name, clk, reset): 87 | BusMonitor.__init__(self, dut, name, clk, reset) 88 | self.clk = clk 89 | self.reset = reset 90 | self.dut = dut 91 | 92 | async def _monitor_recv(self): #this will be called in init. 93 | global err_cnt 94 | global table_expected 95 | while True: 96 | await RisingEdge(self.clock) 97 | await ReadOnly() 98 | #await Timer (1, units = 'ns') 99 | 100 | if self.reset.value == 1: 101 | self.bus.wr_en.value = 0 102 | self.bus.rd_en.value = 0 103 | self.bus.index_wr.value = 0 104 | self.bus.index_rd.value = 0 105 | self.bus.data_wr.value = 0 106 | table_expected = [0 for i in range(TABLE_SIZE)] 107 | continue 108 | 109 | if self.bus.wr_en.value == (2**INPUT_RATE -1) and self.bus.rd_en.value == 1: 110 | self.read_update() 111 | self.write_update() 112 | elif self.bus.wr_en.value == (2**INPUT_RATE - 1): 113 | self.write_update() 114 | elif self.bus.rd_en.value == 1: 115 | self.read_update() 116 | 117 | def write_update(self): 118 | global table_expected 119 | for j in range(0,INPUT_RATE): 120 | target_index = self.bus.index_wr.value & ((2**INDEX_WIDTH - 1) << (INDEX_WIDTH*j)) 121 | target_index = target_index >> (INDEX_WIDTH*j) 122 | exp_data_wr = self.bus.data_wr.value & ((2**DATA_WIDTH - 1) << (DATA_WIDTH*j)) 123 | exp_data_wr = exp_data_wr >> (DATA_WIDTH*j) 124 | table_expected[target_index] = exp_data_wr 125 | cocotb.log.info("WRITE OPERATION: INDEX = d%0d, DATA = d%0d", target_index, exp_data_wr) 126 | 127 | def read_update(self): 128 | global err_cnt 129 | for j in range(0,OUTPUT_RATE): 130 | target_index = self.bus.index_rd.value & ((2**INDEX_WIDTH - 1) << (INDEX_WIDTH*j)) 131 | target_index = target_index >> (INDEX_WIDTH*j) 132 | act_data_rd = self.bus.data_rd.value & ((2**DATA_WIDTH - 1) << (DATA_WIDTH*j)) 133 | act_data_rd = act_data_rd >> (DATA_WIDTH*j) 134 | exp_data_rd = table_expected[target_index] 135 | if (act_data_rd == exp_data_rd): 136 | cocotb.log.info("READ OPERATION: INDEX = d%0d, DATA = d%0d", target_index,act_data_rd) 137 | else: 138 | err_cnt += 1 139 | cocotb.log.error("READ OPERATION: INDEX = d%0d, ACT DATA = d%0d, EXP DATA = d%0d, ", target_index, act_data_rd, exp_data_rd) 140 | 141 | async def dut_init(dut): 142 | global TABLE_SIZE # DUT parameter 143 | global DATA_WIDTH # DUT paramter 144 | global INPUT_RATE # DUT parameter 145 | global OUTPUT_RATE # DUT parameter 146 | global INDEX_WIDTH 147 | TABLE_SIZE = dut.TABLE_SIZE.value 148 | DATA_WIDTH = dut.DATA_WIDTH.value 149 | INPUT_RATE = dut.INPUT_RATE.value 150 | OUTPUT_RATE = dut.OUTPUT_RATE.value 151 | INDEX_WIDTH = math.ceil(math.log2(TABLE_SIZE)); 152 | await cocotb.start(Clock(dut.clk, TB_CLK_PERIOD, units="ns").start()) 153 | dut.data_wr.value = 0 154 | dut.index_wr.value = 0 155 | dut.index_rd.value = 0 156 | dut.rd_en.value = 0 157 | dut.wr_en.value = 0 158 | dut.rst.value = 1 159 | await(Timer(100,'ns')) 160 | dut.rst.value = 0 161 | await(Timer(100,'ns')) 162 | 163 | 164 | @cocotb.test() 165 | async def table_rand_test(dut): 166 | await dut_init(dut) 167 | driver = OutputDriver(dut, None, dut.clk) #set name='None', refer to Bus class 168 | monitor = InputMonitor(dut, None, dut.clk, dut.rst) 169 | cocotb.log.info("SEED NUMBER = %d",cocotb.RANDOM_SEED) 170 | input_data = [] 171 | read_index = [] 172 | 173 | for j in range(TB_TEST_WEIGHT): 174 | for i in range(30): 175 | #data_wr = cocotb.binary.BinaryValue(n_bits=INPUT_RATE*DATA_WIDTH) 176 | #index_wr = cocotb.binary.BinaryValue(n_bits=INDEX_WIDTH) 177 | data_wr = 0 178 | index_wr = 0 179 | for k in range(0,INPUT_RATE): 180 | #data_wr = (data_wr<<(k-1)*DATA_WIDTH) + random.randint(0, 2**DATA_WIDTH-1) 181 | data_wr = random.randint(0, 2**DATA_WIDTH-1) 182 | #index_wr = (index_wr<<(k-1)*INDEX_WIDTH) + random.randint(0, TABLE_SIZE-1) 183 | index_wr = random.randint(0, TABLE_SIZE-1) 184 | input_data.append([index_wr,data_wr]) 185 | read_index.append(index_wr) 186 | await driver.write_burst(input_data) 187 | await Timer (500, units = 'ns') 188 | await driver.read_burst(read_index) 189 | await Timer (500, units = 'ns') 190 | 191 | if (err_cnt > 0): 192 | cocotb.log.error("Errors count = %d",err_cnt) 193 | cocotb.result.test_fail() 194 | -------------------------------------------------------------------------------- /Hash_Table/src/hash_table.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Create Date: 18/04/2025 1:15 AM 4 | // Last Update: 03/05/2025 6:20 PM 5 | // Module Name: Hash Table 6 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 7 | // Description: Support coliision method of Chaining and Hash Algorithm FNV1A and SHA1 8 | // Additional Comments: . 9 | // 10 | ////////////////////////////////////////////////////////////////////////////////// 11 | 12 | module hash_table #( 13 | parameter KEY_WIDTH = 32, 14 | parameter VALUE_WIDTH = 32, 15 | parameter TOTAL_INDEX = 8, // Total index of the hash table 16 | parameter CHAINING_SIZE = 4, // Number of chains for SINGLE_CYCLE_CHAINING and MULTI_STAGE_CHAINING only 17 | parameter COLLISION_METHOD = "MULTI_STAGE_CHAINING", // "MULTI_STAGE_CHAINING", "LINEAR_PROBING" 18 | parameter HASH_ALGORITHM = "MODULUS" // "MODULUS", "SHA1", "FNV1A" 19 | )( 20 | 21 | input wire clk, 22 | input wire rst, 23 | input wire [KEY_WIDTH-1:0] key_in, 24 | input wire [VALUE_WIDTH-1:0] value_in, 25 | input wire [1:0] op_sel, // 00: Insert, 01: Delete, 10: Search 26 | input wire op_en, 27 | output reg [VALUE_WIDTH-1:0] value_out, 28 | output reg op_done, 29 | output reg op_error, // FULL when insert FAIL, KEY_NOT_FOUND when delete or search FAIL 30 | output reg [$clog2(CHAINING_SIZE-1)-1:0] collision_count 31 | ); 32 | 33 | parameter CHAINING_SIZE_WIDTH = $clog2(CHAINING_SIZE+1); 34 | parameter INDEX_WIDTH = $clog2(TOTAL_INDEX); 35 | 36 | reg [2:0] current_state; 37 | //reg [2:0] next_state; 38 | reg [KEY_WIDTH*CHAINING_SIZE-1:0] hash_key_stored [0:TOTAL_INDEX-1]; 39 | reg [VALUE_WIDTH*CHAINING_SIZE-1:0] hash_value_stored [0:TOTAL_INDEX-1]; 40 | reg [CHAINING_SIZE_WIDTH-1:0] hash_chain_count [0:TOTAL_INDEX-1]; // for collision count 41 | reg [CHAINING_SIZE_WIDTH-1:0] search_ptr; // for searching the key in the chain 42 | reg [CHAINING_SIZE_WIDTH-1:0] next_search_ptr; // for searching the key in the chain 43 | integer i; 44 | 45 | localparam IDLE = 3'b000; 46 | localparam SEARCH_KEY = 3'b001; 47 | localparam INSERT = 3'b010; 48 | localparam DELETE = 3'b011; 49 | localparam READ = 3'b100; 50 | localparam OP_DONE = 3'b101; 51 | 52 | // Hash function selector 53 | function integer get_hash_index; 54 | input integer key; 55 | reg [31:0] hash_value; 56 | begin 57 | if (HASH_ALGORITHM == "MODULUS") 58 | hash_value = key % TOTAL_INDEX; 59 | else // for future implentation of other hash algorithm 60 | hash_value = key; 61 | 62 | get_hash_index = hash_value[INDEX_WIDTH-1:0]; 63 | end 64 | endfunction 65 | 66 | // Collision resolution method 67 | always @ (posedge clk, posedge rst) begin 68 | if(rst) begin 69 | current_state <= IDLE; 70 | search_ptr <= 0; 71 | value_out <= 0; 72 | collision_count <= 0; 73 | op_done <= 0; 74 | op_error <= 0; 75 | for (i = 0; i < TOTAL_INDEX; i++) begin 76 | hash_key_stored[i] <= 0; 77 | hash_value_stored[i] <= 0; 78 | hash_chain_count[i] <= 0; 79 | end 80 | end else begin 81 | case(current_state) 82 | IDLE: begin 83 | if (op_en) begin 84 | case (op_sel) 85 | 2'b00: current_state <= SEARCH_KEY; //INSERT 86 | 2'b01: current_state <= SEARCH_KEY; //DELETE 87 | 2'b10: current_state <= SEARCH_KEY; //SEARCH 88 | default: begin 89 | current_state <= OP_DONE; 90 | op_done <= 1; 91 | op_error <= 1; // Invalid operation 92 | end 93 | endcase 94 | end else begin 95 | current_state <= IDLE; 96 | op_done <= 0; 97 | op_error <= 0; 98 | end 99 | search_ptr <= 0; 100 | value_out <= 0; 101 | collision_count <= 0; 102 | end 103 | 104 | INSERT: begin 105 | // Insert logic here 106 | hash_key_stored[get_hash_index(key_in)][search_ptr*KEY_WIDTH +: KEY_WIDTH] <= key_in; 107 | hash_value_stored[get_hash_index(key_in)][search_ptr*VALUE_WIDTH +: VALUE_WIDTH] <= value_in; 108 | hash_chain_count[get_hash_index(key_in)] <= hash_chain_count[get_hash_index(key_in)] + 1; 109 | op_done <= 1; 110 | op_error <= 0; // No error 111 | current_state <= OP_DONE; 112 | end 113 | 114 | DELETE: begin 115 | // Delete logic here 116 | // Remove key and value from hash table 117 | // Shift the rest of the chain 118 | // use for loop instead 119 | for (i = 0; i < CHAINING_SIZE - 1; i++) begin 120 | if (i >= search_ptr) begin 121 | hash_key_stored[get_hash_index(key_in)][(i*KEY_WIDTH) +: KEY_WIDTH] <= hash_key_stored[get_hash_index(key_in)][((i+1)*KEY_WIDTH) +: KEY_WIDTH]; 122 | hash_value_stored[get_hash_index(key_in)][(i*VALUE_WIDTH) +: VALUE_WIDTH] <= hash_value_stored[get_hash_index(key_in)][((i+1)*VALUE_WIDTH) +: VALUE_WIDTH]; 123 | end else begin 124 | hash_key_stored[get_hash_index(key_in)][(i*KEY_WIDTH) +: KEY_WIDTH] <= {KEY_WIDTH{1'b0}}; 125 | hash_value_stored[get_hash_index(key_in)][(i*VALUE_WIDTH) +: VALUE_WIDTH] <= {VALUE_WIDTH{1'b0}}; 126 | end 127 | end 128 | hash_chain_count[get_hash_index(key_in)] <= hash_chain_count[get_hash_index(key_in)] - 1; 129 | current_state <= OP_DONE; 130 | op_done <= 1; 131 | op_error <= 0; // No error 132 | end 133 | 134 | READ: begin 135 | // Search logic here 136 | // Return the value associated with the key 137 | value_out <= hash_value_stored[get_hash_index(key_in)] >> search_ptr*VALUE_WIDTH; 138 | collision_count <= hash_chain_count[get_hash_index(key_in)]; 139 | current_state <= OP_DONE; 140 | op_done <= 1; 141 | op_error <= 0; // No error 142 | end 143 | 144 | SEARCH_KEY: begin 145 | if (hash_chain_count[get_hash_index(key_in)] == 0) begin 146 | if(op_sel == 2'b00) begin 147 | current_state <= INSERT; 148 | end else begin 149 | collision_count <= 0; 150 | op_done <= 1; 151 | op_error <= 1; // KEY_NOT_FOUND error 152 | current_state <= OP_DONE; 153 | end 154 | end else if(key_in == hash_key_stored[get_hash_index(key_in)][search_ptr*KEY_WIDTH +: KEY_WIDTH]) begin 155 | if(op_sel == 2'b00) begin 156 | current_state <= INSERT; 157 | end else if (op_sel == 2'b01) begin 158 | current_state <= DELETE; 159 | end else if (op_sel == 2'b10) begin 160 | current_state <= READ; 161 | end 162 | end else if (search_ptr == hash_chain_count[get_hash_index(key_in)]) begin 163 | if(op_sel == 2'b00 & (hash_chain_count[get_hash_index(key_in)] < CHAINING_SIZE)) begin 164 | current_state <= INSERT; 165 | end else begin 166 | collision_count <= CHAINING_SIZE; 167 | op_done <= 1; 168 | op_error <= 1; // KEY_NOT_FOUND error 169 | current_state <= OP_DONE; 170 | end 171 | end else begin 172 | current_state <= SEARCH_KEY; 173 | search_ptr <= search_ptr + 1; 174 | end 175 | end 176 | 177 | OP_DONE: begin 178 | current_state <= IDLE; 179 | op_done <= 0; 180 | op_error <= 0; 181 | end 182 | 183 | default: current_state <= IDLE; 184 | endcase 185 | end 186 | end 187 | 188 | endmodule 189 | -------------------------------------------------------------------------------- /FIFO/tb/cocotb/tb.py: -------------------------------------------------------------------------------- 1 | import random 2 | #import asyncio 3 | import cocotb 4 | from cocotb.triggers import Timer, RisingEdge 5 | from cocotb.clock import Clock 6 | from cocotb.result import TestFailure 7 | 8 | DEPTH = 12 # DUT parameter 9 | DATA_WIDTH = 8 # DUT paramter 10 | ASYNC = 1 # DUT parameter 11 | RD_BUFFER = 1 # DUT parameter 12 | TEST_WEIGHT = 1 # TB multiplier for stimulus injected 13 | WR_CLK_PERIOD = 20 # TB wr_clk generator 14 | RD_CLK_PERIOD = 32 # TB rd_clk generator 15 | #SIM_TIMEOUT = 100000; // TB simulation time out 16 | BURST_LENGHT = DEPTH 17 | MAX_DATA = 2**DATA_WIDTH - 1 18 | err_cnt = 0 19 | 20 | # fifo #( 21 | # .DEPTH(DEPTH), 22 | # .DATA_WIDTH(DATA_WIDTH), 23 | # .ASYNC(ASYNC), 24 | # .RD_BUFFER(RD_BUFFER)) DUT ( 25 | # /*input wire*/ .rd_clk(rd_clk), 26 | # /*input wire*/ .wr_clk(wr_clk), 27 | # /*input wire*/ .rst(rst), 28 | # /*input wire [DATA_WIDTH-1:0]*/ .data_wr(data_wr), 29 | # /*input wire*/ .wr_en(wr_en), 30 | # /*output wire*/ .fifo_full(fifo_full), 31 | # /*output logic [DATA_WIDTH-1:0]*/ .data_rd(data_rd), 32 | # /*input wire*/ .rd_en(rd_en), 33 | # /*output wire*/ .fifo_empty(fifo_empty)); 34 | 35 | async def dut_init(dut): 36 | global DEPTH 37 | global DATA_WIDTH 38 | global ASYNC 39 | global RD_BUFFER 40 | global MAX_DATA 41 | global BURST_LENGHT 42 | DEPTH = dut.DEPTH.value 43 | DATA_WIDTH = dut.DATA_WIDTH.value 44 | ASYNC = dut.ASYNC.value 45 | RD_BUFFER = dut.RD_BUFFER.value 46 | MAX_DATA = 2**DATA_WIDTH - 1 47 | BURST_LENGHT = DEPTH 48 | await cocotb.start(Clock(dut.wr_clk, WR_CLK_PERIOD, units="ns").start()) 49 | await cocotb.start(Clock(dut.rd_clk, RD_CLK_PERIOD, units="ns").start()) 50 | dut.rst.value = 1 51 | await(Timer(1000,'ns')) 52 | dut.rst.value = 0 53 | await(Timer(1000,'ns')) 54 | 55 | async def fifo_write_burst_rand(count,dut,fifo_expected): 56 | global err_cnt 57 | for i in range(count): 58 | await RisingEdge(dut.wr_clk) 59 | await(Timer(1,'ns')) 60 | if(len(fifo_expected) < DEPTH and dut.fifo_full.value == 1): 61 | dut._log.error("FIFO is not full but fifo_full flag is asserted") 62 | dut.wr_en.value = 1 63 | data_wr_rand = random.randint(0,MAX_DATA) 64 | dut.data_wr.value = data_wr_rand 65 | if(len(fifo_expected) < DEPTH): 66 | fifo_expected.append(data_wr_rand) 67 | dut._log.info("Data written = %d, FIFO entry = %d", data_wr_rand, len(fifo_expected)) 68 | else: 69 | await(Timer(1,'ns')) 70 | if(dut.fifo_full.value == 1): 71 | dut._log.info("FIFO is full, fifo_full flag is asserted correctly") 72 | else: 73 | dut._log.error("FIFO is full but fifo_full flag is not asserted") 74 | err_cnt += 1 75 | await RisingEdge(dut.wr_clk) 76 | await(Timer(1,'ns')) 77 | dut.wr_en.value = 0 78 | 79 | 80 | async def fifo_read_burst(count,dut,fifo_expected): 81 | global err_cnt 82 | rd_init = 0 83 | await RisingEdge(dut.rd_clk) 84 | await Timer(1,'ns') 85 | dut.rd_en.value = 1 86 | if(RD_BUFFER == 0): 87 | await Timer(1,'ns') 88 | if(len(fifo_expected)>0): 89 | if(dut.fifo_empty.value == 1): 90 | dut._log.error("FIFO is not empty but fifo_empty flag is asserted") 91 | err_cnt += 1 92 | data_rd_exp = fifo_expected.pop(0) 93 | data_rd_act = dut.data_rd.value.integer 94 | if(data_rd_exp == data_rd_act): 95 | dut._log.info("Data read = %d, FIFO entry = %d", data_rd_act, len(fifo_expected)) 96 | else: 97 | dut._log.error("Data read mismatch, ACT = %d, EXP = %d", data_rd_act, data_rd_exp) 98 | err_cnt += 1 99 | else: 100 | if(dut.fifo_empty.value == 1): 101 | dut._log.info("FIFO is empty, fifo_empty flag is asserted correctly") 102 | else: 103 | dut._log.error("FIFO is empty but fifo_empty flag is not asserted") 104 | err_cnt += 1 105 | for i in range(count): 106 | await RisingEdge(dut.rd_clk) 107 | await Timer(1,'ns') 108 | if(len(fifo_expected)>0): 109 | if(dut.fifo_empty.value == 1): 110 | if(len(fifo_expected) == 1): 111 | dut._log.info("FIFO is empty, fifo_empty flag is asserted correctly") 112 | else: 113 | dut._log.error("FIFO is not empty but fifo_empty flag is asserted") 114 | err_cnt += 1 115 | data_rd_exp = fifo_expected.pop(0) 116 | data_rd_act = dut.data_rd.value.integer 117 | if(data_rd_exp == data_rd_act): 118 | dut._log.info("Data read = %d, FIFO entry = %d", data_rd_act, len(fifo_expected)) 119 | else: 120 | dut._log.error("Data read mismatch, ACT = %d, EXP = %d", data_rd_act, data_rd_exp) 121 | err_cnt += 1 122 | else: 123 | if(dut.fifo_empty.value == 1): 124 | dut._log.info("FIFO is empty, fifo_empty flag is asserted correctly") 125 | else: 126 | dut._log.error("FIFO is empty but fifo_empty flag is not asserted") 127 | err_cnt += 1 128 | dut.rd_en.value = 0 129 | 130 | async def fifo_burst_write(dut,fifo_wr_stream,fifo_expected): 131 | for data_wr in fifo_wr_stream: 132 | await RisingEdge(dut.wr_clk) 133 | await Timer(1,'ns') 134 | dut.wr_en.value = 1 135 | dut.data_wr.value = data_wr 136 | fifo_expected.append(data_wr) 137 | dut._log.info("Data written = %d, FIFO entry = %d", data_wr, len(fifo_expected)) 138 | await RisingEdge(dut.wr_clk) 139 | await Timer(1,'ns') 140 | dut.wr_en.value = 0 141 | 142 | async def fifo_burst_read_return_stream(dut,count,fifo_expected): 143 | fifo_rd_stream = [] 144 | rd_init = 0 145 | while (rd_init == 0): 146 | await RisingEdge(dut.rd_clk) 147 | if(dut.fifo_empty.value != 1): 148 | if(rd_init == 0): 149 | await Timer(1,'ns') 150 | dut.rd_en.value = 1 151 | if(RD_BUFFER == 0): 152 | await Timer(1,'ns') 153 | data_rd = dut.data_rd.value.integer 154 | fifo_rd_stream.append(data_rd) 155 | fifo_expected.pop(0) 156 | dut._log.info("Data read = %d, FIFO entry = %d", data_rd,len(fifo_expected)) 157 | rd_init = 1 158 | while (len(fifo_rd_stream) < count): 159 | await RisingEdge(dut.rd_clk) 160 | await Timer(1,'ns') 161 | data_rd = dut.data_rd.value.integer 162 | fifo_rd_stream.append(data_rd) 163 | fifo_expected.pop(0) 164 | dut._log.info("Data read = %d, FIFO entry = %d", data_rd,len(fifo_expected)) 165 | dut.rd_en.value = 0 166 | return fifo_rd_stream 167 | 168 | async def fifo_read_write_rand_simul(count,dut): 169 | global err_cnt 170 | fifo_wr_stream = [] 171 | fifo_rd_stream = [] 172 | for i in range(BURST_LENGHT): 173 | data_wr_rand = random.randint(0,MAX_DATA) 174 | fifo_wr_stream.append(data_wr_rand) 175 | fifo_expected = [] 176 | await cocotb.start(fifo_burst_write(dut,fifo_wr_stream,fifo_expected)) 177 | fifo_rd_stream = await fifo_burst_read_return_stream(dut,BURST_LENGHT,fifo_expected) 178 | for i in range(len(fifo_wr_stream)): 179 | if(fifo_wr_stream[i] != fifo_rd_stream[i]): 180 | dut._log.error("Data rd %d does not match data wr %d", fifo_rd_stream[i],fifo_wr_stream[i]) 181 | err_cnt += 1 182 | 183 | @cocotb.test() 184 | async def fifo_rand_write_then_read_test(dut): 185 | await dut_init(dut) 186 | dut._log.info("\nFIFO WRITE BURST SEQ") 187 | fifo_expected = [] 188 | await fifo_write_burst_rand(DEPTH+3,dut,fifo_expected) 189 | await(Timer(1000,'ns')) 190 | dut._log.info("\nFIFO READ BURST SEQ") 191 | await fifo_read_burst(DEPTH+3,dut,fifo_expected) 192 | await(Timer(1000,'ns')) 193 | if (err_cnt > 0): 194 | cocotb.log.error("Errors count = %d",err_cnt) 195 | cocotb.result.test_fail() 196 | 197 | 198 | @cocotb.test() 199 | async def fifo_rand_read_write_test(dut): 200 | await dut_init(dut) 201 | dut._log.info("\nFIFO RANDOM READ WRITE SEQ") 202 | fifo_expected = [] 203 | i = DEPTH 204 | while(i >= 0): 205 | op_sel = random.randint(0,1) 206 | op_count = random.randint(1,5) 207 | i = i - op_count 208 | match (op_sel): 209 | case 1: 210 | await fifo_read_burst(op_count,dut,fifo_expected) 211 | await Timer(RD_CLK_PERIOD,'ns') 212 | await Timer(3*WR_CLK_PERIOD,'ns') 213 | case 0: 214 | await fifo_write_burst_rand(op_count,dut,fifo_expected) 215 | await Timer(WR_CLK_PERIOD,'ns') 216 | await Timer(3*RD_CLK_PERIOD,'ns') 217 | if (err_cnt > 0): 218 | cocotb.log.error("Errors count = %d",err_cnt) 219 | cocotb.result.test_fail() 220 | 221 | @cocotb.test() 222 | async def fifo_rand_read_write_simul_test(dut): 223 | cocotb.log.info("Seed = %d",cocotb.RANDOM_SEED) 224 | await dut_init(dut) 225 | dut._log.info("\nFIFO SIMULTANEOUS RANDOM READ WRITE SEQ") 226 | await fifo_read_write_rand_simul(1,dut) 227 | if (err_cnt > 0): 228 | cocotb.log.error("Errors count = %d",err_cnt) 229 | cocotb.result.test_fail() 230 | -------------------------------------------------------------------------------- /FIFO/tb/sv/tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Create Date: 05/05/2024 03:37:34 PM 5 | // Last Update Date: 05/11/2024 10:37:12 AM 6 | // Module Name: tb 7 | // Author: https://www.linkedin.com/in/wei-yet-ng-065485119/ 8 | // Description: 1. fifo_write_burst_rand 9 | // 2. fifo_read_burst 10 | // 3. fifo_burst_rand 11 | // 4. fifo_read_write_rand_simul 12 | // Additional Comments: 13 | // 14 | ////////////////////////////////////////////////////////////////////////////////// 15 | 16 | 17 | module tb( 18 | ); 19 | parameter DEPTH = 12; // DUT parameter 20 | parameter DATA_WIDTH = 8; // DUT paramter 21 | parameter ASYNC = 1; // DUT parameter 22 | parameter RD_BUFFER = 1; // DUT parameter 23 | parameter TEST_WEIGHT = 1; // TB multiplier for stimulus injected 24 | parameter WR_CLK_PERIOD = 20; // TB wr_clk generator 25 | parameter RD_CLK_PERIOD = 32; // TB rd_clk generator 26 | parameter SIM_TIMEOUT = 100000; // TB simulation time out 27 | parameter BURST_LENGHT = DEPTH; 28 | localparam MAX_DATA = 2**DATA_WIDTH - 1; 29 | integer fifo_expected [$]; 30 | integer i; 31 | integer err_cnt = 0; 32 | reg rd_clk = 0; 33 | reg wr_clk = 0; 34 | reg rst = 1; 35 | reg [DATA_WIDTH-1:0] data_wr = 0; 36 | reg wr_en = 0; 37 | reg rd_en = 0; 38 | wire [DATA_WIDTH-1:0] data_rd; 39 | wire fifo_empty; 40 | wire fifo_full; 41 | 42 | 43 | `ifdef XILINX_GLS 44 | glbl glbl (); // for Xilinx GLS 45 | `endif 46 | 47 | fifo #( 48 | .DEPTH(DEPTH), 49 | .DATA_WIDTH(DATA_WIDTH), 50 | .ASYNC(ASYNC), 51 | .RD_BUFFER(RD_BUFFER)) DUT ( 52 | /*input wire*/ .rd_clk(rd_clk), 53 | /*input wire*/ .wr_clk(wr_clk), 54 | /*input wire*/ .rst(rst), 55 | /*input wire [DATA_WIDTH-1:0]*/ .data_wr(data_wr), 56 | /*input wire*/ .wr_en(wr_en), 57 | /*output wire*/ .fifo_full(fifo_full), 58 | /*output logic [DATA_WIDTH-1:0]*/ .data_rd(data_rd), 59 | /*input wire*/ .rd_en(rd_en), 60 | /*output wire*/ .fifo_empty(fifo_empty)); 61 | 62 | always #(RD_CLK_PERIOD>>1) rd_clk = ~rd_clk; 63 | always #(WR_CLK_PERIOD>>1) wr_clk = ~wr_clk; 64 | 65 | 66 | integer data_wr_rand = 0; 67 | 68 | task fifo_write_burst_rand (input integer count); 69 | for (i=0; i 0) begin 105 | if(fifo_empty) begin 106 | $error("%0t FIFO is not empty but fifo_empty flag is asserted", $realtime); 107 | err_cnt = err_cnt + 1; 108 | end 109 | if (RD_BUFFER == 1) begin 110 | #1; 111 | end 112 | data_rd_exp = fifo_expected.pop_front(); 113 | data_rd_act <= data_rd; 114 | #1; //to make sure data_rd_act capture data_rd signal. 115 | if(data_rd_exp == data_rd_act) 116 | $display("%0t Data read = %d, FIFO entry = %d",$realtime, data_rd_act, $size(fifo_expected)); 117 | else begin 118 | $error("%0t Data read mismatch, ACT = %d, EXP =%d, FIFO entry = %d", $realtime, data_rd_act, data_rd_exp, $size(fifo_expected)); 119 | err_cnt = err_cnt + 1; 120 | end 121 | end else begin // check FIFO EMPTY flag 122 | #1; 123 | if(fifo_empty) 124 | $display("%0t FIFO is empty, fifo_empty flag is asserted correctly", $realtime); 125 | else begin 126 | $error("%0t FIFO is empty but fifo_empty flag is not asserted", $realtime); 127 | err_cnt = err_cnt + 1; 128 | end 129 | end 130 | end 131 | end 132 | // @(posedge(rd_clk)) 133 | rd_en <= 0; 134 | endtask 135 | 136 | integer op_count = 0; 137 | integer j = 0; 138 | bit op_sel = 0; 139 | 140 | task fifo_burst_rand(int count); 141 | j = count; 142 | while(j >= 0) begin 143 | op_sel = $urandom(); 144 | op_count = $urandom_range(1,j); // to have continuous request 145 | j = j - op_count; 146 | case(op_sel) 147 | 1: begin // read 148 | fifo_read_burst(op_count); 149 | #RD_CLK_PERIOD; 150 | #(3*WR_CLK_PERIOD); // It might take extra cycle for rd_pointer synchronization to deassert fifo_full, used for write operation 151 | end 152 | 0: begin // write 153 | fifo_write_burst_rand(op_count); 154 | #WR_CLK_PERIOD; 155 | #(3*RD_CLK_PERIOD); // It might take extra cycle for wr_pointer synchronization to deassert fifo_empty, used for read operation 156 | end 157 | endcase 158 | end 159 | endtask 160 | 161 | integer fifo_wr_stream [$]; 162 | integer fifo_rd_stream [$]; 163 | 164 | 165 | task fifo_read_write_rand_simul(); 166 | fifo_read_burst($size(fifo_expected)); // to make sure FIFO is empty 167 | fifo_wr_stream = {}; 168 | fifo_rd_stream = {}; 169 | for(i = 0; i < DEPTH; i = i+1) begin 170 | data_wr_rand = $urandom_range(0, MAX_DATA+1); 171 | fifo_wr_stream.push_back(data_wr_rand); 172 | end 173 | fork 174 | begin 175 | for (i=0; i 0) begin 247 | $display("\n%0t TEST FAILED",$realtime); 248 | $display("Error count = %d\n", err_cnt); 249 | end else 250 | $display("\n%0t TEST PASSED\n", $realtime); 251 | $finish; 252 | end 253 | 254 | initial begin 255 | #(SIM_TIMEOUT); 256 | $display("\n%0t TEST FAILED", $realtime); 257 | $display("SIM TIMEOUT!\n"); 258 | $finish; 259 | end 260 | 261 | endmodule 262 | -------------------------------------------------------------------------------- /Hash_Table/tb/cocotb/tb.py: -------------------------------------------------------------------------------- 1 | import random 2 | import asyncio 3 | import math 4 | import cocotb 5 | import cocotb.result 6 | from cocotb.triggers import Timer, RisingEdge, ReadOnly, with_timeout 7 | from cocotb.clock import Clock 8 | from cocotb_bus.drivers import BusDriver 9 | from cocotb_bus.monitors import BusMonitor 10 | from cocotb.binary import BinaryValue 11 | 12 | #BIN string 13 | #BinaryValue(dut.data_wr.value, n_bits=8) ; BinaryValue.integar ; BinaryValue.hex ; BinaryValue.binstr; BinaryValue.signed_integer ; can represent x,z 14 | 15 | DUT_KEY_WIDTH = 32 16 | DUT_VALUE_WIDTH = 32 17 | DUT_TOTAL_INDEX = 8 18 | DUT_CHAINING_SIZE = 4 19 | DUT_COLLISION_METHOD = "MULTI_STAGE_CHAINING" 20 | DUT_HASH_ALGORITHM = "MODULUS" 21 | 22 | MAX_VALUE = 2**DUT_VALUE_WIDTH - 1 23 | INDEX_WIDTH = int(math.log2(DUT_TOTAL_INDEX)) 24 | ADDR_WIDTH = int(math.log2(DUT_TOTAL_INDEX*DUT_CHAINING_SIZE)) 25 | 26 | OP_INSERT = 0b00 27 | OP_DELTE = 0b01 28 | OP_SEARCH = 0b10 29 | 30 | TB_CLK_PERIOD = 30 # TB clk generator 31 | TB_SIM_TIMEOUT = 30 # TB sim timeout 30ms 32 | TB_TEST_WEIGHT = 1 33 | err_cnt = 1 34 | 35 | # hash_table #( 36 | # .KEY_WIDTH(DUT_KEY_WIDTH), 37 | # .VALUE_WIDTH(DUT_VALUE_WIDTH), 38 | # .TOTAL_INDEX(DUT_TOTAL_INDEX), // Total index of the hash table 39 | # .CHAINING_SIZE(DUT_CHAINING_SIZE), // Number of chains for SINGLE_CYCLE_CHAINING and MULTI_STAGE_CHAINING only 40 | # .COLLISION_METHOD(DUT_COLLISION_METHOD), // "MULTI_STAGE_CHAINING", "LINEAR_PROBING" 41 | # .HASH_ALGORITHM(DUT_HASH_ALGORITHM)) // "MODULUS", "SHA1", "FNV1A")) 42 | # DUT ( 43 | # /*input wire*/ .clk(clk), 44 | # /*input wire*/ .rst(rst), 45 | # /*input wire [KEY_WIDTH-1:0]*/ .key_in(key_in), 46 | # /*input wire [VALUE_WIDTH-1:0]*/ .value_in(value_in), 47 | # /*input wire [1:0]*/ .op_sel(op_sel), // 00: Insert, 01: Delete, 10: Search 48 | # /*input wire*/ .op_en(op_en), 49 | # /*output reg [VALUE_WIDTH-1:0]*/ .value_out(value_out), 50 | # /*output reg*/ .op_done(op_done), 51 | # /*output reg*/ .op_error(op_error), // FULL when insert FAIL, KEY_NOT_FOUND when delete or search FAIL 52 | # /*output reg [CHAIN_WIDTH-1:0]*/ .collision_count(collision_count)); 53 | 54 | # Below is not a good way to define "hash_table" in python, but for the sake of simplicity, we define it like this. 55 | class hash_table: 56 | def __init__(self, dut): 57 | self.dut = dut 58 | self.key_value_pair = [{} for j in range(DUT_TOTAL_INDEX)] 59 | 60 | def hash(self, key): 61 | if DUT_HASH_ALGORITHM == "MODULUS": 62 | return key % DUT_TOTAL_INDEX 63 | elif DUT_HASH_ALGORITHM == "SHA1": 64 | # Implement SHA1 hash function here 65 | pass 66 | elif DUT_HASH_ALGORITHM == "FNV1A": 67 | # Implement FNV1A hash function here 68 | pass 69 | 70 | def insert(self, key, value): 71 | index = self.hash(key) 72 | if len(self.key_value_pair[index]) < DUT_CHAINING_SIZE: 73 | self.key_value_pair[index][key] = value 74 | cocotb.log.info("Inserted key: %d, value: %d at index: %d", key, value, index) 75 | return True 76 | else: 77 | cocotb.log.info("Collision occurred at index: %d", index) 78 | return False 79 | 80 | def delete(self, key): 81 | index = self.hash(key) 82 | if key in self.key_value_pair[index]: 83 | del self.key_value_pair[index][key] 84 | cocotb.log.info("Deleted key: %d at index: %d", key, index) 85 | return True 86 | else: 87 | cocotb.log.info("Key not found: %d at index: %d", key, index) 88 | return False 89 | 90 | def search(self, key): 91 | index = self.hash(key) 92 | if key in self.key_value_pair[index]: 93 | cocotb.log.info("Found key: %d, value: %d at index: %d", key, self.key_value_pair[index][key], index) 94 | return self.key_value_pair[index][key] 95 | else: 96 | cocotb.log.info("Key not found: %d at index: %d", key, index) 97 | return -1 98 | 99 | def print_content(self): 100 | cocotb.log.info("Hash Table Content:") 101 | for i in range(DUT_TOTAL_INDEX): 102 | info = "index " + str(i) + " : " + str(self.key_value_pair[i]) 103 | cocotb.log.info(info) 104 | cocotb.log.info("End of Hash Table Content") 105 | 106 | async def hash_table_insert(dut, hash_table, key, value): 107 | global err_cnt 108 | cocotb.log.info("OP_Insert key: %0d, value: %0d", key, value) 109 | await RisingEdge(dut.clk) 110 | await Timer (1, units = 'ns') 111 | dut.key_in.value = key 112 | dut.value_in.value = value 113 | dut.op_sel.value = OP_INSERT 114 | dut.op_en.value = 1 115 | await RisingEdge(dut.op_done) 116 | await Timer (1, units = 'ns') 117 | result = hash_table.insert(key, value) 118 | if (result == False): 119 | if(dut.op_error.value == 1): 120 | cocotb.log.info("Collision occurred, error flag is asserted correctly") 121 | else: 122 | cocotb.log.error("Collision occurred, error flag is not asserted") 123 | err_cnt += 1 124 | await RisingEdge(dut.clk) 125 | dut.op_en.value = 0 126 | hash_table.print_content() 127 | 128 | async def hash_table_delete(dut, hash_table, key): 129 | global err_cnt 130 | cocotb.log.info("OP_Delete key: %0d", key) 131 | await RisingEdge(dut.clk) 132 | await Timer (1, units = 'ns') 133 | dut.key_in.value = key 134 | dut.op_sel.value = OP_DELTE 135 | dut.op_en.value = 1 136 | await RisingEdge(dut.op_done) 137 | await Timer (1, units = 'ns') 138 | result = hash_table.delete(key) 139 | if (result == False): 140 | if(dut.op_error.value == 1): 141 | cocotb.log.info("Key not found, error flag is asserted correctly") 142 | else: 143 | cocotb.log.error("Key not found, error flag is not asserted") 144 | err_cnt += 1 145 | await RisingEdge(dut.clk) 146 | dut.op_en.value = 0 147 | hash_table.print_content() 148 | 149 | async def hash_table_search(dut, hash_table, key): 150 | global err_cnt 151 | cocotb.log.info("OP_Search key: %0d", key) 152 | await RisingEdge(dut.clk) 153 | await Timer (1, units = 'ns') 154 | dut.key_in.value = key 155 | dut.op_sel.value = OP_SEARCH 156 | dut.op_en.value = 1 157 | cocotb.log.info("hello") 158 | await RisingEdge(dut.op_done) 159 | cocotb.log.info("hello2") 160 | await Timer (1, units = 'ns') 161 | await ReadOnly() 162 | result = hash_table.search(key) 163 | if (result == -1): 164 | if(dut.op_error.value == 1): 165 | cocotb.log.info("Key not found, error flag is asserted correctly") 166 | else: 167 | cocotb.log.error("Key not found, error flag is not asserted") 168 | err_cnt += 1 169 | else: 170 | if(dut.value_out.value == result): 171 | cocotb.log.info("Key found, value: %0d", result) 172 | else: 173 | cocotb.log.error("Key found, but value is not correct") 174 | err_cnt += 1 175 | await RisingEdge(dut.clk) 176 | dut.op_en.value = 0 177 | hash_table.print_content() 178 | return -1 if (dut.op_error.value) else dut.value_out.value 179 | 180 | 181 | 182 | async def dut_init(dut): 183 | global DUT_KEY_WIDTH 184 | global DUT_VALUE_WIDTH 185 | global DUT_TOTAL_INDEX 186 | global DUT_CHAINING_SIZE 187 | global MAX_VALUE 188 | global INDEX_WIDTH 189 | global ADDR_WIDTH 190 | 191 | DUT_KEY_WIDTH = dut.KEY_WIDTH.value 192 | DUT_VALUE_WIDTH = dut.VALUE_WIDTH.value 193 | DUT_TOTAL_INDEX = dut.TOTAL_INDEX.value 194 | DUT_CHAINING_SIZE = dut.CHAINING_SIZE.value 195 | DUT_COLLISION_METHOD = dut.COLLISION_METHOD.value 196 | DUT_HASH_ALGORITHM = dut.HASH_ALGORITHM.value 197 | MAX_VALUE = 2**DUT_VALUE_WIDTH - 1 198 | INDEX_WIDTH = int(math.log2(DUT_TOTAL_INDEX)) 199 | ADDR_WIDTH = int(math.log2(DUT_TOTAL_INDEX*DUT_CHAINING_SIZE)) 200 | 201 | await cocotb.start(Clock(dut.clk, TB_CLK_PERIOD, units="ns").start()) 202 | dut.rst.value = 0 203 | dut.key_in.value = 0 204 | dut.value_in.value = 0 205 | dut.op_sel.value = 0 206 | dut.op_en.value = 0 207 | dut.rst.value = 1 208 | await(Timer(100,'ns')) 209 | dut.rst.value = 0 210 | await(Timer(100,'ns')) 211 | 212 | async def timeout(): 213 | await Timer(TB_SIM_TIMEOUT, units='ms') 214 | cocotb.log.error("Simulation timeout") 215 | raise cocotb.result.TestFailure("Simulation timeout") 216 | 217 | @cocotb.test() 218 | async def direct_basic_op_test(dut): 219 | #timeout_task = asyncio.create_task(timeout()) 220 | cocotb.start_soon(timeout()) 221 | await dut_init(dut) 222 | exp_hash_table = hash_table(dut) 223 | cocotb.log.info("SEED NUMBER = %d",cocotb.RANDOM_SEED) 224 | await hash_table_insert(dut, exp_hash_table, 1, 2) 225 | result = await hash_table_search(dut, exp_hash_table, 1) 226 | await hash_table_insert(dut, exp_hash_table, 3, 2) 227 | await hash_table_insert(dut, exp_hash_table, 11, 3) 228 | await hash_table_insert(dut, exp_hash_table, 19, 4) 229 | await hash_table_insert(dut, exp_hash_table, 27, 5) 230 | await hash_table_insert(dut, exp_hash_table, 35, 5) 231 | await hash_table_insert(dut, exp_hash_table, 43, 5) 232 | await hash_table_delete(dut, exp_hash_table, 1) 233 | result = await hash_table_search(dut, exp_hash_table, 19) 234 | result = await hash_table_search(dut, exp_hash_table, 1) 235 | result = await hash_table_search(dut, exp_hash_table, 3) 236 | 237 | #timeout_task.cancel() 238 | #task.kill() 239 | 240 | if (err_cnt > 0): 241 | cocotb.log.error("Errors count = %d",err_cnt) 242 | raise cocotb.result.TestFailure() 243 | --------------------------------------------------------------------------------