diff --git a/firmware/rtl/testbench.hpp b/firmware/rtl/testbench.hpp index 606844b..b2f7eb5 100644 --- a/firmware/rtl/testbench.hpp +++ b/firmware/rtl/testbench.hpp @@ -32,9 +32,10 @@ template class TB { Verilated::timeInc(1); tick_count++; - if (bailout > 0 && tick_count >= bailout) + if (bailout > 0 && tick_count >= bailout) { exit(1); - if (Verilated::gotError()) + } if (Verilated::gotError()) { exit(1); + } } }; diff --git a/firmware/rtl/waveform/Makefile b/firmware/rtl/waveform/Makefile index 1ddde22..ec97b45 100644 --- a/firmware/rtl/waveform/Makefile +++ b/firmware/rtl/waveform/Makefile @@ -2,7 +2,7 @@ .PHONY: test clean -test: obj_dir/Vbram_interface_sim +test: obj_dir/Vbram_interface_sim obj_dir/Vwaveform_sim bram_SRC= bram_interface_sim.v dma_sim.v bram_interface.v bram_interface_sim.cpp @@ -15,5 +15,15 @@ obj_dir/Vbram_interface_sim: obj_dir/Vbram_interface_sim.mk cd obj_dir && make -f Vbram_interface_sim.mk ./obj_dir/Vbram_interface_sim +waveform_src = waveform_sim.v waveform.v bram_interface.v dma_sim.v waveform_sim.cpp ../spi/spi_slave_no_write.v +obj_dir/Vwaveform_sim.mk: $(waveform_src) + verilator --cc --exe -Wall --trace --trace-fst -I../spi \ + -CFLAGS -DWORD_AMNT=2048 \ + -CFLAGS -DRAM_WID=32 \ + $(waveform_src) +obj_dir/Vwaveform_sim: obj_dir/Vwaveform_sim.mk $(waveform_src) + cd obj_dir && make -f Vwaveform_sim.mk + ./obj_dir/Vwaveform_sim + clean: rm -rf obj_dir/ diff --git a/firmware/rtl/waveform/bram_interface.v b/firmware/rtl/waveform/bram_interface.v index 8bf64ad..8a2daba 100644 --- a/firmware/rtl/waveform/bram_interface.v +++ b/firmware/rtl/waveform/bram_interface.v @@ -106,3 +106,4 @@ end else if (!word_next && word_ok) begin end endmodule +`undefineall diff --git a/firmware/rtl/waveform/bram_interface_sim.v b/firmware/rtl/waveform/bram_interface_sim.v index facdc85..7286bd0 100644 --- a/firmware/rtl/waveform/bram_interface_sim.v +++ b/firmware/rtl/waveform/bram_interface_sim.v @@ -1,5 +1,5 @@ module bram_interface_sim #( - parameter WORD_WID = 24, + parameter WORD_WID = 20, parameter WORD_AMNT_WID = 11, parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047, parameter RAM_WID = 32, diff --git a/firmware/rtl/waveform/dma_sim.v b/firmware/rtl/waveform/dma_sim.v index dce214e..b2f44d1 100644 --- a/firmware/rtl/waveform/dma_sim.v +++ b/firmware/rtl/waveform/dma_sim.v @@ -42,3 +42,4 @@ always @ (posedge clk) begin end endmodule +`undefineall diff --git a/firmware/rtl/waveform/waveform.v b/firmware/rtl/waveform/waveform.v index 31fad4c..5c53f50 100644 --- a/firmware/rtl/waveform/waveform.v +++ b/firmware/rtl/waveform/waveform.v @@ -1,4 +1,5 @@ /* Write a waveform to a DAC. */ +/* TODO: Add reset pin. */ module waveform #( parameter DAC_WID = 24, parameter DAC_WID_SIZ = 5, @@ -18,6 +19,8 @@ module waveform #( ) ( input clk, input arm, + input halt_on_finish, + output reg finished, input [TIMER_WID-1:0] time_to_wait, /* User interface */ @@ -100,11 +103,14 @@ reg [1:0] state = WAIT_ON_ARM; reg [TIMER_WID-1:0] wait_timer = 0; always @ (posedge clk) case (state) -WAIT_ON_ARM: if (arm) begin - state <= DO_WAIT; - wait_timer <= time_to_wait; -end else begin - word_rst <= 1; +WAIT_ON_ARM: begin + finished <= 0; + if (arm) begin + state <= DO_WAIT; + wait_timer <= time_to_wait; + end else begin + word_rst <= 1; + end end DO_WAIT: if (!arm) begin state <= WAIT_ON_ARM; @@ -126,11 +132,26 @@ WAIT_ON_DAC: if (dac_finished) begin dac_arm <= 0; /* Was the last word read *the* last word? */ if (word_last) begin - state <= WAIT_ON_ARM; + if (!halt_on_finish) begin + state <= WAIT_ON_ARM; + finished <= 0; + end else begin + finished <= 1; + end end else begin state <= DO_WAIT; end end endcase +/* Warning! This will crash verilator with a segmentation fault! +`ifdef VERILATOR +initial begin + $dumpfile("waveform.fst"); + $dumpvars(); +end +`endif +*/ + endmodule +`undefineall diff --git a/firmware/rtl/waveform/waveform_sim.cpp b/firmware/rtl/waveform/waveform_sim.cpp new file mode 100644 index 0000000..8471180 --- /dev/null +++ b/firmware/rtl/waveform/waveform_sim.cpp @@ -0,0 +1,90 @@ +#include +#include "Vwaveform_sim.h" +#include "../testbench.hpp" + +class WaveformTestbench : public TB { +private: + void refresh_posedge(); + void spi_posedge(); +public: + std::array ram_refresh_data; + int cur_ind; + void posedge() override; + void refresh_data(); + WaveformTestbench(int _bailout = 0) : TB(_bailout) + , ram_refresh_data{} + , cur_ind{0} {} +}; + +void WaveformTestbench::refresh_data() { + for (size_t i = 0; i < WORD_AMNT; i++) { + uint32_t val = mask_extend(rand(), 20); + ram_refresh_data[i] = val; + mod.backing_store[i*2] = val & 0xFFFF; + mod.backing_store[i*2+1] = val >> 16; + } + + mod.refresh_start = 1; + mod.start_addr = 0x12340; +} + +void WaveformTestbench::refresh_posedge() { + if (mod.refresh_finished) { + mod.refresh_start = 0; + } +} + +void WaveformTestbench::spi_posedge() { + if (mod.finished) { + mod.rdy = 0; + // Check for proper DAC register. + my_assert(mod.from_master >> 20 == 0x1, "%d", mod.from_master >> 20); + uint32_t val = mask_extend(mod.from_master & 0xFFFFF, 20); + my_assert(val == ram_refresh_data[cur_ind], "(%d) %X != %X", + cur_ind, val, ram_refresh_data[cur_ind]); + cur_ind++; + if (cur_ind == WORD_AMNT) + cur_ind = 0; + } else if (!mod.finished && !mod.rdy) { + mod.rdy = 1; + } +} + +void WaveformTestbench::posedge() { + refresh_posedge(); + spi_posedge(); +} + +WaveformTestbench *tb; + +int main(int argc, char *argv[]) { + int j = 0; + Verilated::commandArgs(argc, argv); + // Verilated::traceEverOn(true); + Verilated::fatalOnError(false); + + tb = new WaveformTestbench(); + tb->mod.rdy = 1; + tb->refresh_data(); + tb->mod.time_to_wait = 10; + tb->mod.arm = 1; + + do { + tb->run_clock(); + } while (!tb->mod.refresh_finished); + + tb->mod.halt_on_finish = 1; + do { + tb->run_clock(); + } while (!tb->mod.waveform_finished); + + tb->mod.halt_on_finish = 0; + tb->run_clock(); + tb->mod.halt_on_finish = 1; + do { + tb->run_clock(); + } while (!tb->mod.waveform_finished); + + delete tb; + return 0; +} diff --git a/firmware/rtl/waveform/waveform_sim.v b/firmware/rtl/waveform/waveform_sim.v new file mode 100644 index 0000000..ee74524 --- /dev/null +++ b/firmware/rtl/waveform/waveform_sim.v @@ -0,0 +1,122 @@ +module waveform_sim #( + parameter DAC_WID = 24, + parameter DAC_WID_SIZ = 5, + parameter DAC_POLARITY = 0, + parameter DAC_PHASE = 1, + parameter DAC_CYCLE_HALF_WAIT = 10, + parameter DAC_CYCLE_HALF_WAIT_SIZ = 4, + parameter DAC_SS_WAIT = 5, + parameter DAC_SS_WAIT_SIZ = 3, + parameter TIMER_WID = 32, + parameter WORD_WID = 20, + parameter WORD_AMNT_WID = 11, + parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047, + parameter RAM_REAL_START = 32'h12340, + parameter RAM_CNTR_LEN = 12, + parameter TOTAL_RAM_WORD_MINUS_ONE = 4095, + parameter DELAY_CNTR_LEN = 8, + parameter DELAY_TOTAL = 12, + parameter RAM_WID = 32, + parameter RAM_WORD_WID = 16, + parameter RAM_WORD_INCR = 2 +) ( + input clk, + input arm, + input halt_on_finish, + output waveform_finished, + input [TIMER_WID-1:0] time_to_wait, + + /* User interface */ + input refresh_start, + input [RAM_WID-1:0] start_addr, + output reg refresh_finished, + + output [DAC_WID-1:0] from_master, + output finished, + input rdy, + output spi_err, + + input[RAM_WORD_WID-1:0] backing_store [TOTAL_RAM_WORD_MINUS_ONE:0] +); + +wire sck; +wire ss_L; +wire mosi; + +spi_slave_no_write #( + .WID(DAC_WID), + .WID_LEN(DAC_WID_SIZ), + .POLARITY(DAC_POLARITY), + .PHASE(DAC_PHASE) +) slave ( + .clk(clk), + .sck(sck), + .ss_L(ss_L), + .mosi(mosi), + .from_master(from_master), + .finished(finished), + .rdy(rdy), + .err(spi_err) +); + +wire [RAM_WID-1:0] ram_dma_addr; +wire [RAM_WORD_WID-1:0] ram_word; +wire ram_read; +wire ram_valid; + +dma_sim #( + .RAM_WID(RAM_WID), + .RAM_WORD_WID(RAM_WORD_WID), + .RAM_REAL_START(RAM_REAL_START), + .RAM_CNTR_LEN(RAM_CNTR_LEN), + .TOTAL_RAM_WORD_MINUS_ONE(TOTAL_RAM_WORD_MINUS_ONE), + .DELAY_CNTR_LEN(DELAY_CNTR_LEN), + .DELAY_TOTAL(DELAY_TOTAL) +) dma_sim ( + .clk(clk), + .ram_dma_addr(ram_dma_addr), + .ram_word(ram_word), + .ram_read(ram_read), + .ram_valid(ram_valid), + .backing_store(backing_store) +); + +waveform #( + .DAC_WID(DAC_WID), + .DAC_WID_SIZ(DAC_WID_SIZ), + .DAC_POLARITY(DAC_POLARITY), + .DAC_PHASE(DAC_PHASE), + .DAC_CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT), + .DAC_CYCLE_HALF_WAIT_SIZ(DAC_CYCLE_HALF_WAIT_SIZ), + .DAC_SS_WAIT(DAC_SS_WAIT), + .DAC_SS_WAIT_SIZ(DAC_SS_WAIT_SIZ), + .TIMER_WID(TIMER_WID), + .WORD_WID(WORD_WID), + .WORD_AMNT_WID(WORD_AMNT_WID), + .WORD_AMNT(WORD_AMNT), + .RAM_WID(RAM_WID), + .RAM_WORD_WID(RAM_WORD_WID), + .RAM_WORD_INCR(RAM_WORD_INCR) +) waveform ( + .clk(clk), + .arm(arm), + .halt_on_finish(halt_on_finish), + .finished(waveform_finished), + .time_to_wait(time_to_wait), + + .refresh_start(refresh_start), + .start_addr(start_addr), + .refresh_finished(refresh_finished), + + .ram_dma_addr(ram_dma_addr), + .ram_word(ram_word), + .ram_read(ram_read), + .ram_valid(ram_valid), + + .mosi(mosi), + .sck(sck), + .ss_L(ss_L) +); + +endmodule +`undefineall