diff options
author | Jon Nordby <jononor@gmail.com> | 2025-04-26 18:13:37 +0200 |
---|---|---|
committer | Jon Nordby <jononor@gmail.com> | 2025-04-26 21:33:29 +0200 |
commit | b9d821cb5409a545431d7b34d8df0ad493c26a46 (patch) | |
tree | 7e196adc6e8e1548c6643c5e4c25e4fc0259bfd3 | |
parent | b2b664b2596b48048ba97c5b43f3f29345c6bdb3 (diff) |
cocotb: Try to test a CIC filter
-rw-r--r-- | cocotb_try/Makefile | 6 | ||||
-rw-r--r-- | cocotb_try/cic3_pdm.v | 68 | ||||
-rw-r--r-- | cocotb_try/test_cic.py | 32 |
3 files changed, 103 insertions, 3 deletions
diff --git a/cocotb_try/Makefile b/cocotb_try/Makefile index 2d4fe2b..6612173 100644 --- a/cocotb_try/Makefile +++ b/cocotb_try/Makefile @@ -4,14 +4,14 @@ SIM ?= verilator TOPLEVEL_LANG ?= verilog -VERILOG_SOURCES += $(PWD)/my_design.v +VERILOG_SOURCES += $(PWD)/cic3_pdm.v # use VHDL_SOURCES for VHDL files # TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file -TOPLEVEL = my_design +TOPLEVEL = cic3_pdm # MODULE is the basename of the Python test file -MODULE = test_my_design +MODULE = test_cic # include cocotb's make rules to take care of the simulator setup include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/cocotb_try/cic3_pdm.v b/cocotb_try/cic3_pdm.v new file mode 100644 index 0000000..f572d64 --- /dev/null +++ b/cocotb_try/cic3_pdm.v @@ -0,0 +1,68 @@ + +// XXX: A chatbot wrote this, might be complete crack + +module cic3_pdm ( + input wire clk, // PDM clock + input wire rst, // active-high synchronous reset + input wire pdm_in, // 1-bit PDM data input + output wire signed [15:0] pcm_out, // Decimated PCM output + output wire pcm_valid // High when pcm_out is valid +); + parameter DECIMATION = 64; // Decimation factor + + // Internal registers + reg signed [31:0] integrator_0 = 0; + reg signed [31:0] integrator_1 = 0; + reg signed [31:0] integrator_2 = 0; + + reg [5:0] decim_counter = 0; + reg signed [31:0] comb_0 = 0, comb_1 = 0, comb_2 = 0; + reg signed [31:0] delay_0 = 0, delay_1 = 0, delay_2 = 0; + + reg signed [15:0] pcm_out_r = 0; + reg pcm_valid_r = 0; + + // Integrator stage (runs every clk) + always @(posedge clk) begin + if (rst) begin + integrator_0 <= 0; + integrator_1 <= 0; + integrator_2 <= 0; + end else begin + integrator_0 <= integrator_0 + (pdm_in ? 1 : -1); + integrator_1 <= integrator_1 + integrator_0; + integrator_2 <= integrator_2 + integrator_1; + end + end + + // Decimation counter + always @(posedge clk) begin + if (rst) + decim_counter <= 0; + else + decim_counter <= decim_counter + 1; + end + + // Comb stage (runs every DECIMATION clocks) + always @(posedge clk) begin + pcm_valid_r <= 0; + if (decim_counter == DECIMATION[5:0] - 1) begin + comb_0 <= integrator_2 - delay_0; + delay_0 <= integrator_2; + + comb_1 <= comb_0 - delay_1; + delay_1 <= comb_0; + + comb_2 <= comb_1 - delay_2; + delay_2 <= comb_1; + + // Bit-shift down to get 16-bit output (tune shift based on DECIMATION and stage count) + pcm_out_r <= comb_2[31:16]; + pcm_valid_r <= 1; + end + end + + assign pcm_out = pcm_out_r; + assign pcm_valid = pcm_valid_r; + +endmodule diff --git a/cocotb_try/test_cic.py b/cocotb_try/test_cic.py new file mode 100644 index 0000000..3a4e385 --- /dev/null +++ b/cocotb_try/test_cic.py @@ -0,0 +1,32 @@ + +# https://docs.cocotb.org/en/stable/quickstart.html +# test_my_design.py (extended) + +import cocotb +from cocotb.triggers import FallingEdge, Timer + + +async def generate_clock(dut): + """Generate clock pulses.""" + + for cycle in range(10): + dut.clk.value = 0 + await Timer(1, units="ns") + dut.clk.value = 1 + await Timer(1, units="ns") + + +@cocotb.test() +async def my_second_test(dut): + """Try accessing the design.""" + + await cocotb.start(generate_clock(dut)) # run the clock "in the background" + + await Timer(5, units="ns") # wait a bit + await FallingEdge(dut.clk) # wait for falling edge/"negedge" + + dut._log.info("my_signal_1 is %s", dut.my_signal_1.value) + assert dut.my_signal_2.value[0] == 0, "my_signal_2[0] is not 0!" + + + |