I'm self studying with Chu's FPGA prototyping book. Exercise 4.7.1 asks for a programmable square wave generator:
A programmable square-wave generator is a circuit that can generate a square wave with variable on (i.e., logic 1) and off (i.e., logic 0) intervals. The durations of the intervals are specified by two 4-bit control signals, m and n, which are interpreted as unsigned integers. The on and off intervals are m* 100 ns and n* 100 ns, respectively. Design a programmable square-wave generator circuit. The circuit should be completely synchronous.
I have a completely syncrhonous working solution, but I couldn't find a nice way for it to be cycle accurate, in the sense that the code I like the most uses two more clock cycles to change the logic level of the square wave. I'm pasting the whole code at the end of my question, but what I don't like is the part that does
if(clk_tick_count == interval_quant_ns - 1), specifically having to substract 1 from the number of intervals I want to count. I came to this solution after verifying that the solution without the -1 was taking two more clock cycles, and fixed it with the -1. I understand this is because since the update is synchronous I need another full clock cycle for the changes to be reflected in my ouput wave.
I just have a feeling that there ir a nicer way to do this but I can't discuss it with anyone nor have I been lucky searching for nicer code online.
This is my current code:
module sqwaveGen #( parameter interval_quant_ns = 5 ) ( input wire clk, input wire rst, output wire wave, input wire [3:0] on_interval, input wire [3:0] off_interval ); reg wave_next, wave_reg; reg [3:0] clk_tick_count, clk_tick_count_next; reg [3:0] count, count_next; always @(posedge clk, negedge rst) begin if(~rst) begin wave_reg <= 0; clk_tick_count <= 0; count <= 0; end else begin wave_reg <= wave_next; clk_tick_count <= clk_tick_count_next; count <= count_next; end end always @(*) begin wave_next = wave_reg; count_next = count; clk_tick_count_next = clk_tick_count + 1; if(wave_reg == 0 && count == off_interval) begin wave_next = 1; count_next = 0; end if(wave_reg == 1 && count == on_interval) begin wave_next = 0; count_next = 0; end if(clk_tick_count == interval_quant_ns - 1) begin count_next = count + 1; clk_tick_count_next = 0; end end assign wave = wave_reg; endmodule
Output wave of a test for the sake of completeness, showing that this works: