|
1 |
| -//-------------------------------------------------------------------------------- |
| 1 | +//------------------------------------------------------------------------------ |
2 | 2 | // pulse_gen.sv
|
3 | 3 | // Konstantin Pavlov, [email protected]
|
4 |
| -//-------------------------------------------------------------------------------- |
| 4 | +//------------------------------------------------------------------------------ |
| 5 | + |
| 6 | +// INFO ------------------------------------------------------------------------ |
| 7 | +// Pulse generator module, ver.2 |
| 8 | +// |
| 9 | +// - generates one or many pulses of given width and period |
| 10 | +// - generates constant HIGH, constant LOW, or impulse output |
| 11 | +// - features buffered inputs, so inputs can change continiously during pulse period |
| 12 | +// - generates LOW when idle |
| 13 | +// |
| 14 | +// - Pulse period is (cntr_max[]+1) cycles |
| 15 | +// - If you need to generate constant LOW pulses, then CNTR_WIDTH should allow |
| 16 | +// setting cntr_low[]>cntr_max[] |
| 17 | +// |
| 18 | +// Example 1: |
| 19 | +// let CNTR_WIDTH = 8 |
| 20 | +// let cntr_max[7:0] = 2^CNTR_WIDTH-2 = 254, pulse period is 255 cycles |
| 21 | +// cntr_low[7:0]==255 then output will be constant LOW |
| 22 | +// 0<cntr_low[7:0]<=cntr_max[7:0] then output will be generating pulse(s) |
| 23 | +// cntr_low[7:0]==0 then output will be constant HIGH |
| 24 | +// |
| 25 | +// Example 2: |
| 26 | +// let CNTR_WIDTH = 9 |
| 27 | +// let cntr_max[8:0] = 255, pulse period is 256 cycles |
| 28 | +// cntr_low[8:0]>255 then output will be constant LOW |
| 29 | +// 0<cntr_low[8:0]<=cntr_max[8:0] then output will be generating pulse(s) |
| 30 | +// cntr_low[8:0]==0 then output will be constant HIGH |
| 31 | +// |
| 32 | +// In Example 2 constant LOW state can be acheived also by disabling start |
| 33 | +// condition or holding reset input, so cntr_low[8:0] and cntr_max[8:0] |
| 34 | +// can be left 8-bit-wide actually |
5 | 35 |
|
6 |
| -// INFO -------------------------------------------------------------------------------- |
7 |
| -// Pulse generator module |
8 |
| -// generates one or many pulses of given wigth |
9 |
| -// low_wdth[] and high_wdth[] must NOT be 0 |
10 |
| - |
11 |
| -// CAUTION: |
12 |
| -// - low_wdth[], high_wdth[] and rpt inputs are NOT buffered, so could be changed |
13 |
| -// interactively while pulse_gen is already performing |
14 |
| -// This could be beneficial for implementing PWM-like genetators with |
15 |
| -// variating parameters |
16 | 36 |
|
17 | 37 |
|
18 | 38 | /* --- INSTANTIATION TEMPLATE BEGIN ---
|
19 | 39 |
|
20 | 40 | pulse_gen #(
|
21 |
| - .CNTR_WIDTH( 32 ) |
| 41 | + .CNTR_WIDTH( 8 ) |
22 | 42 | ) pg1 (
|
23 | 43 | .clk( clk ),
|
24 | 44 | .nrst( nrst ),
|
25 |
| - .low_width( 2 ), |
26 |
| - .high_width( 2 ), |
27 |
| - .rpt( 1'b0 ), |
| 45 | +
|
28 | 46 | .start( 1'b1 ),
|
29 |
| - .busy( ), |
30 |
| - .out( ) |
| 47 | + .cntr_max( 255 ), |
| 48 | + .cntr_low( 2 ), |
| 49 | +
|
| 50 | + .pulse_out( ), |
| 51 | +
|
| 52 | + .start_strobe, |
| 53 | + .busy( ) |
31 | 54 | );
|
32 | 55 |
|
33 | 56 | --- INSTANTIATION TEMPLATE END ---*/
|
34 | 57 |
|
35 | 58 | module pulse_gen #( parameter
|
36 | 59 | CNTR_WIDTH = 32
|
37 | 60 | )(
|
| 61 | + input clk, // system clock |
| 62 | + input nrst, // negative reset |
38 | 63 |
|
39 |
| - input clk, |
40 |
| - input nrst, |
| 64 | + input start, // enables new period start |
| 65 | + input [CNTR_WIDTH-1:0] cntr_max, // counter initilization value, should be > 0 |
| 66 | + input [CNTR_WIDTH-1:0] cntr_low, // transition to LOW counter value |
41 | 67 |
|
42 |
| - input [CNTR_WIDTH-1:0] low_width, |
43 |
| - input [CNTR_WIDTH-1:0] high_width, |
44 |
| - input rpt, |
| 68 | + output logic pulse_out, // active HIGH output |
45 | 69 |
|
46 |
| - input start, // only first front matters |
47 |
| - output busy, |
48 |
| - output logic out = 1'b0 |
| 70 | + // status outputs |
| 71 | + output logic start_strobe = 1'b0, |
| 72 | + output busy |
49 | 73 | );
|
50 | 74 |
|
51 |
| -logic [CNTR_WIDTH-1:0] cnt_low = '0; |
52 |
| -logic [CNTR_WIDTH-1:0] cnt_high = '0; |
53 | 75 |
|
54 |
| -enum logic [1:0] {IDLE,LOW,HIGH} gen_state; |
| 76 | +logic [CNTR_WIDTH-1:0] seq_cntr = '0; |
55 | 77 |
|
| 78 | +logic seq_cntr_0; |
| 79 | +assign seq_cntr_0 = (seq_cntr[CNTR_WIDTH-1:0] == '0); |
| 80 | + |
| 81 | +// delayed one cycle |
| 82 | +logic seq_cntr_0_d1; |
56 | 83 | always_ff @(posedge clk) begin
|
57 |
| - if( ~nrst ) begin |
58 |
| - out = 1'b0; |
| 84 | + if( ~nrst) begin |
| 85 | + seq_cntr_0_d1 <= 0; |
| 86 | + end else begin |
| 87 | + seq_cntr_0_d1 <= seq_cntr_0; |
| 88 | + end |
| 89 | +end |
59 | 90 |
|
60 |
| - gen_state[1:0] <= IDLE; |
| 91 | +// first seq_cntr_0 cycle time belongs to pulse period |
| 92 | +// second and further seq_cntr_0 cycles are idle |
| 93 | +assign busy = ~(seq_cntr_0 && seq_cntr_0_d1); |
61 | 94 |
|
62 |
| - cnt_low[CNTR_WIDTH-1:0] <= '0; |
63 |
| - cnt_high[CNTR_WIDTH-1:0] <= '0; |
64 |
| - end else begin |
65 | 95 |
|
66 |
| - case( gen_state[1:0] ) |
67 |
| - IDLE: begin |
68 |
| - if( start ) begin |
69 |
| - out <= 1'b0; |
70 |
| - // latching first pulse widths here |
71 |
| - if( low_width[CNTR_WIDTH-1:0] != '0) begin |
72 |
| - cnt_low[CNTR_WIDTH-1:0] <= low_width[CNTR_WIDTH-1:0] - 1'b1; |
73 |
| - end else begin |
74 |
| - cnt_low[CNTR_WIDTH-1:0] <= '0; |
75 |
| - end |
76 |
| - if( high_width[CNTR_WIDTH-1:0] != '0) begin |
77 |
| - cnt_high[CNTR_WIDTH-1:0] <= high_width[CNTR_WIDTH-1:0] - 1'b1; |
78 |
| - end else begin |
79 |
| - cnt_high[31:0] <= '0; |
80 |
| - end |
81 |
| - gen_state[1:0] <= LOW; |
82 |
| - end |
83 |
| - end // IDLE |
84 |
| - |
85 |
| - LOW: begin |
86 |
| - if( cnt_low[CNTR_WIDTH-1:0] != 0 ) begin |
87 |
| - out <= 1'b0; |
88 |
| - cnt_low[CNTR_WIDTH-1:0] <= cnt_low[CNTR_WIDTH-1:0] - 1'b1; |
89 |
| - end else begin |
90 |
| - out <= 1'b1; |
91 |
| - gen_state[1:0] <= HIGH; |
92 |
| - end |
93 |
| - end // LOW |
94 |
| - |
95 |
| - HIGH: begin |
96 |
| - if( cnt_high[CNTR_WIDTH-1:0] != 0 ) begin |
97 |
| - out <= 1'b1; |
98 |
| - cnt_high[CNTR_WIDTH-1:0] <= cnt_high[CNTR_WIDTH-1:0] - 1'b1; |
99 |
| - end else begin |
100 |
| - out <= 1'b0; |
101 |
| - if( rpt ) begin |
102 |
| - // latching repetitive pulse widths here |
103 |
| - if( low_width[CNTR_WIDTH-1:0] != '0) begin |
104 |
| - cnt_low[CNTR_WIDTH-1:0] <= low_width[CNTR_WIDTH-1:0] - 1'b1; |
105 |
| - end else begin |
106 |
| - cnt_low[CNTR_WIDTH-1:0] <= '0; |
107 |
| - end |
108 |
| - if( high_width[CNTR_WIDTH-1:0] != '0) begin |
109 |
| - cnt_high[CNTR_WIDTH-1:0] <= high_width[CNTR_WIDTH-1:0] - 1'b1; |
110 |
| - end else begin |
111 |
| - cnt_high[CNTR_WIDTH-1:0] <= '0; |
112 |
| - end |
113 |
| - gen_state[1:0] <= LOW; |
114 |
| - end else begin |
115 |
| - gen_state[1:0] <= IDLE; |
116 |
| - end |
117 |
| - end |
118 |
| - end // HIGH |
119 |
| - |
120 |
| - default: gen_state[1:0] <= IDLE; |
121 |
| - endcase // gen_state |
122 |
| - |
123 |
| - end // nrst |
| 96 | +// buffering cntr_low untill pulse period is over to allow continiously |
| 97 | +// changing inputs |
| 98 | +logic [CNTR_WIDTH-1:0] cntr_low_buf = '0; |
| 99 | +always_ff @(posedge clk) begin |
| 100 | + if( ~nrst ) begin |
| 101 | + seq_cntr[CNTR_WIDTH-1:0] <= '0; |
| 102 | + cntr_low_buf[CNTR_WIDTH-1:0] <= '0; |
| 103 | + start_strobe <= 1'b0; |
| 104 | + end else begin |
| 105 | + if( seq_cntr_0 ) begin |
| 106 | + // don`t start if cntr_max[] is illegal value |
| 107 | + if( start && (cntr_max[CNTR_WIDTH-1:0]!='0) ) begin |
| 108 | + seq_cntr[CNTR_WIDTH-1:0] <= cntr_max[CNTR_WIDTH-1:0]; |
| 109 | + cntr_low_buf[CNTR_WIDTH-1:0] <= cntr_low[CNTR_WIDTH-1:0]; |
| 110 | + start_strobe <= 1'b1; |
| 111 | + end else begin |
| 112 | + start_strobe <= 1'b0; |
| 113 | + end |
| 114 | + end else begin |
| 115 | + seq_cntr[CNTR_WIDTH-1:0] <= seq_cntr[CNTR_WIDTH-1:0] - 1'b1; |
| 116 | + start_strobe <= 1'b0; |
| 117 | + end |
| 118 | + end // ~nrst |
124 | 119 | end
|
125 | 120 |
|
126 |
| -assign busy = (gen_state[1:0] != IDLE); |
| 121 | +always_comb begin |
| 122 | + if( ~nrst ) begin |
| 123 | + pulse_out <= 1'b0; |
| 124 | + end else begin |
| 125 | + // busy condition guarantees LOW output when idle |
| 126 | + if( busy && |
| 127 | + (seq_cntr[CNTR_WIDTH-1:0] >= cntr_low_buf[CNTR_WIDTH-1:0]) ) begin |
| 128 | + pulse_out <= 1'b1; |
| 129 | + end else begin |
| 130 | + pulse_out <= 1'b0; |
| 131 | + end |
| 132 | + end // ~nrst |
| 133 | +end |
127 | 134 |
|
128 | 135 |
|
129 | 136 | endmodule
|
|
0 commit comments