From d5030cfb5dc8c9f6cc7e760cbda94795744fbc46 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 5 May 2020 06:51:23 +0300 Subject: [PATCH] Updated pulse_gen to ver.2 --- pulse_gen.sv | 197 +++++++++++++++++++++++++----------------------- pulse_gen_tb.sv | 97 ++++++++++++++---------- 2 files changed, 160 insertions(+), 134 deletions(-) diff --git a/pulse_gen.sv b/pulse_gen.sv index 3635b2c..136591a 100644 --- a/pulse_gen.sv +++ b/pulse_gen.sv @@ -1,33 +1,56 @@ -//-------------------------------------------------------------------------------- +//------------------------------------------------------------------------------ // pulse_gen.sv // Konstantin Pavlov, pavlovconst@gmail.com -//-------------------------------------------------------------------------------- +//------------------------------------------------------------------------------ -// INFO -------------------------------------------------------------------------------- -// Pulse generator module -// generates one or many pulses of given wigth -// low_wdth[] and high_wdth[] must NOT be 0 +// INFO ------------------------------------------------------------------------ +// Pulse generator module, ver.2 +// +// - generates one or many pulses of given width and period +// - generates constant HIGH, constant LOW, or impulse output +// - features buffered inputs, so inputs can change continiously during pulse period +// - generates LOW when idle +// +// - Pulse period is (cntr_max[]+1) cycles +// - If you need to generate constant LOW pulses, then CNTR_WIDTH should allow +// setting cntr_low[]>cntr_max[] +// +// Example 1: +// let CNTR_WIDTH = 8 +// let cntr_max[7:0] = 2^CNTR_WIDTH-2 = 254, pulse period is 255 cycles +// cntr_low[7:0]==255 then output will be constant LOW +// 0255 then output will be constant LOW +// 0 0 + input [CNTR_WIDTH-1:0] cntr_low, // transition to LOW counter value - input [CNTR_WIDTH-1:0] low_width, - input [CNTR_WIDTH-1:0] high_width, - input rpt, + output logic pulse_out, // active HIGH output - input start, // only first front matters - output busy, - output logic out = 1'b0 + // status outputs + output logic start_strobe = 1'b0, + output busy ); -logic [CNTR_WIDTH-1:0] cnt_low = '0; -logic [CNTR_WIDTH-1:0] cnt_high = '0; -enum logic [1:0] {IDLE,LOW,HIGH} gen_state; +logic [CNTR_WIDTH-1:0] seq_cntr = '0; +logic seq_cntr_0; +assign seq_cntr_0 = (seq_cntr[CNTR_WIDTH-1:0] == '0); + +// delayed one cycle +logic seq_cntr_0_d1; always_ff @(posedge clk) begin - if( ~nrst ) begin - out = 1'b0; - - gen_state[1:0] <= IDLE; - - cnt_low[CNTR_WIDTH-1:0] <= '0; - cnt_high[CNTR_WIDTH-1:0] <= '0; + if( ~nrst) begin + seq_cntr_0_d1 <= 0; end else begin - - case( gen_state[1:0] ) - IDLE: begin - if( start ) begin - out <= 1'b0; - // latching first pulse widths here - if( low_width[CNTR_WIDTH-1:0] != '0) begin - cnt_low[CNTR_WIDTH-1:0] <= low_width[CNTR_WIDTH-1:0] - 1'b1; - end else begin - cnt_low[CNTR_WIDTH-1:0] <= '0; - end - if( high_width[CNTR_WIDTH-1:0] != '0) begin - cnt_high[CNTR_WIDTH-1:0] <= high_width[CNTR_WIDTH-1:0] - 1'b1; - end else begin - cnt_high[31:0] <= '0; - end - gen_state[1:0] <= LOW; - end - end // IDLE - - LOW: begin - if( cnt_low[CNTR_WIDTH-1:0] != 0 ) begin - out <= 1'b0; - cnt_low[CNTR_WIDTH-1:0] <= cnt_low[CNTR_WIDTH-1:0] - 1'b1; - end else begin - out <= 1'b1; - gen_state[1:0] <= HIGH; - end - end // LOW - - HIGH: begin - if( cnt_high[CNTR_WIDTH-1:0] != 0 ) begin - out <= 1'b1; - cnt_high[CNTR_WIDTH-1:0] <= cnt_high[CNTR_WIDTH-1:0] - 1'b1; - end else begin - out <= 1'b0; - if( rpt ) begin - // latching repetitive pulse widths here - if( low_width[CNTR_WIDTH-1:0] != '0) begin - cnt_low[CNTR_WIDTH-1:0] <= low_width[CNTR_WIDTH-1:0] - 1'b1; - end else begin - cnt_low[CNTR_WIDTH-1:0] <= '0; - end - if( high_width[CNTR_WIDTH-1:0] != '0) begin - cnt_high[CNTR_WIDTH-1:0] <= high_width[CNTR_WIDTH-1:0] - 1'b1; - end else begin - cnt_high[CNTR_WIDTH-1:0] <= '0; - end - gen_state[1:0] <= LOW; - end else begin - gen_state[1:0] <= IDLE; - end - end - end // HIGH - - default: gen_state[1:0] <= IDLE; - endcase // gen_state - - end // nrst + seq_cntr_0_d1 <= seq_cntr_0; + end end -assign busy = (gen_state[1:0] != IDLE); +// first seq_cntr_0 cycle time belongs to pulse period +// second and further seq_cntr_0 cycles are idle +assign busy = ~(seq_cntr_0 && seq_cntr_0_d1); + + +// buffering cntr_low untill pulse period is over to allow continiously +// changing inputs +logic [CNTR_WIDTH-1:0] cntr_low_buf = '0; +always_ff @(posedge clk) begin + if( ~nrst ) begin + seq_cntr[CNTR_WIDTH-1:0] <= '0; + cntr_low_buf[CNTR_WIDTH-1:0] <= '0; + start_strobe <= 1'b0; + end else begin + if( seq_cntr_0 ) begin + // don`t start if cntr_max[] is illegal value + if( start && (cntr_max[CNTR_WIDTH-1:0]!='0) ) begin + seq_cntr[CNTR_WIDTH-1:0] <= cntr_max[CNTR_WIDTH-1:0]; + cntr_low_buf[CNTR_WIDTH-1:0] <= cntr_low[CNTR_WIDTH-1:0]; + start_strobe <= 1'b1; + end else begin + start_strobe <= 1'b0; + end + end else begin + seq_cntr[CNTR_WIDTH-1:0] <= seq_cntr[CNTR_WIDTH-1:0] - 1'b1; + start_strobe <= 1'b0; + end + end // ~nrst +end + +always_comb begin + if( ~nrst ) begin + pulse_out <= 1'b0; + end else begin + // busy condition guarantees LOW output when idle + if( busy && + (seq_cntr[CNTR_WIDTH-1:0] >= cntr_low_buf[CNTR_WIDTH-1:0]) ) begin + pulse_out <= 1'b1; + end else begin + pulse_out <= 1'b0; + end + end // ~nrst +end endmodule diff --git a/pulse_gen_tb.sv b/pulse_gen_tb.sv index c09ec7a..226b1d0 100644 --- a/pulse_gen_tb.sv +++ b/pulse_gen_tb.sv @@ -18,6 +18,14 @@ initial begin #2.5 clk200 = ~clk200; end +// external device "asynchronous" clock +logic clk33; +initial begin + #0 clk33 = 1'b0; + forever + #15.151 clk33 = ~clk33; +end + logic rst; initial begin #0 rst = 1'b0; @@ -63,89 +71,100 @@ edge_detect ed1[31:0] ( .both( ) ); -logic [15:0] RandomNumber1; +logic [31:0] RandomNumber1; c_rand rng1 ( .clk( clk200 ), - .rst( rst_once ), - .reseed( 1'b0 ), - .seed_val( DerivedClocks[31:0] ), + .rst( 1'b0 ), + .reseed( rst_once ), + .seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 1) ), .out( RandomNumber1[15:0] ) ); +c_rand rng2 ( + .clk( clk200 ), + .rst( 1'b0 ), + .reseed( rst_once ), + .seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 2) ), + .out( RandomNumber1[31:16] ) +); + logic start; initial begin #0 start = 1'b0; #100 start = 1'b1; - #10 start = 1'b0; + #20 start = 1'b0; end // Modules under test ========================================================== // simple static test -pulse_gen #( - .CNTR_WIDTH( 32 ) +/*pulse_gen #( + .CNTR_WIDTH( 8 ) ) pg1 ( .clk( clk200 ), .nrst( nrst_once ), - .low_width( 32'd1 ), - .high_width( 32'd1 ), - .rpt( 1'b0 ), + .start( start ), - .busy( ), - .out( ) + .cntr_max( 15 ), + .cntr_low( 0 ), + + .out( ), + .busy( ) ); +*/ // random test pulse_gen #( - .CNTR_WIDTH( 32 ) -) pg2 ( + .CNTR_WIDTH( 8 ) +) pg1 ( .clk( clk200 ), .nrst( nrst_once ), - .low_width( {28'd0,RandomNumber1[3:0]} ), - .high_width( {28'd0,RandomNumber1[7:4]} ), - .rpt( 1'b1 ), - .start( start ), - .busy( ), - .out( ) + + .start( 1'b1 ), + .cntr_max( 16 ), + .cntr_low( {4'b0,RandomNumber1[3:0]} ), + + .out( ), + .busy( ) ); -logic [31:0] pg3_in_high_width = '0; -logic pg3_out; -logic pg3_out_rise; +logic [31:0] in_high_width = '0; +logic out; +logic out_rise; -edge_detect pg3_out_ed ( +edge_detect out_ed ( .clk( clk200 ), .nrst( nrst_once ), - .in( pg3_out ), - .rising( pg3_out_rise ), + .in( out ), + .rising( out_rise ), .falling( ), .both( ) ); always_ff @(posedge clk200) begin if( ~nrst_once ) begin - pg3_in_high_width[31:0] <= 1'b1; + in_high_width[31:0] <= 1'b0; end else begin - if( pg3_out_rise ) begin - pg3_in_high_width[31:0] <= pg3_in_high_width[31:0] + 1'b1; + if( out_rise ) begin + in_high_width[31:0] <= in_high_width[31:0] + 1'b1; end end end // PWM test -pulse_gen #( - .CNTR_WIDTH( 32 ) -) pg3 ( +/*pulse_gen #( + .CNTR_WIDTH( 8 ) +) pg1 ( .clk( clk200 ), .nrst( nrst_once ), - .low_width( 32'd1 ), - .high_width( pg3_in_high_width[31:0] ), - .rpt( 1'b1 ), - .start( start ), - .busy( ), - .out( pg3_out ) -); + .start( 1'b1 ), + .cntr_max( 15 ), + .cntr_low( {4'b0,in_high_width[3:0]} ), + + .out( out ), + .busy( ) +);*/ endmodule