Skip to content

Commit d5030cf

Browse files
committed
Updated pulse_gen to ver.2
1 parent eba4111 commit d5030cf

File tree

2 files changed

+159
-133
lines changed

2 files changed

+159
-133
lines changed

pulse_gen.sv

+101-94
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,136 @@
1-
//--------------------------------------------------------------------------------
1+
//------------------------------------------------------------------------------
22
// pulse_gen.sv
33
// 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
535

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
1636

1737

1838
/* --- INSTANTIATION TEMPLATE BEGIN ---
1939
2040
pulse_gen #(
21-
.CNTR_WIDTH( 32 )
41+
.CNTR_WIDTH( 8 )
2242
) pg1 (
2343
.clk( clk ),
2444
.nrst( nrst ),
25-
.low_width( 2 ),
26-
.high_width( 2 ),
27-
.rpt( 1'b0 ),
45+
2846
.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( )
3154
);
3255
3356
--- INSTANTIATION TEMPLATE END ---*/
3457

3558
module pulse_gen #( parameter
3659
CNTR_WIDTH = 32
3760
)(
61+
input clk, // system clock
62+
input nrst, // negative reset
3863

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
4167

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
4569

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
4973
);
5074

51-
logic [CNTR_WIDTH-1:0] cnt_low = '0;
52-
logic [CNTR_WIDTH-1:0] cnt_high = '0;
5375

54-
enum logic [1:0] {IDLE,LOW,HIGH} gen_state;
76+
logic [CNTR_WIDTH-1:0] seq_cntr = '0;
5577

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;
5683
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
5990

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);
6194

62-
cnt_low[CNTR_WIDTH-1:0] <= '0;
63-
cnt_high[CNTR_WIDTH-1:0] <= '0;
64-
end else begin
6595

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
124119
end
125120

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
127134

128135

129136
endmodule

pulse_gen_tb.sv

+58-39
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ initial begin
1818
#2.5 clk200 = ~clk200;
1919
end
2020

21+
// external device "asynchronous" clock
22+
logic clk33;
23+
initial begin
24+
#0 clk33 = 1'b0;
25+
forever
26+
#15.151 clk33 = ~clk33;
27+
end
28+
2129
logic rst;
2230
initial begin
2331
#0 rst = 1'b0;
@@ -63,89 +71,100 @@ edge_detect ed1[31:0] (
6371
.both( )
6472
);
6573

66-
logic [15:0] RandomNumber1;
74+
logic [31:0] RandomNumber1;
6775
c_rand rng1 (
6876
.clk( clk200 ),
69-
.rst( rst_once ),
70-
.reseed( 1'b0 ),
71-
.seed_val( DerivedClocks[31:0] ),
77+
.rst( 1'b0 ),
78+
.reseed( rst_once ),
79+
.seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 1) ),
7280
.out( RandomNumber1[15:0] )
7381
);
7482

83+
c_rand rng2 (
84+
.clk( clk200 ),
85+
.rst( 1'b0 ),
86+
.reseed( rst_once ),
87+
.seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 2) ),
88+
.out( RandomNumber1[31:16] )
89+
);
90+
7591
logic start;
7692
initial begin
7793
#0 start = 1'b0;
7894
#100 start = 1'b1;
79-
#10 start = 1'b0;
95+
#20 start = 1'b0;
8096
end
8197

8298
// Modules under test ==========================================================
8399

84100
// simple static test
85-
pulse_gen #(
86-
.CNTR_WIDTH( 32 )
101+
/*pulse_gen #(
102+
.CNTR_WIDTH( 8 )
87103
) pg1 (
88104
.clk( clk200 ),
89105
.nrst( nrst_once ),
90-
.low_width( 32'd1 ),
91-
.high_width( 32'd1 ),
92-
.rpt( 1'b0 ),
106+
93107
.start( start ),
94-
.busy( ),
95-
.out( )
108+
.cntr_max( 15 ),
109+
.cntr_low( 0 ),
110+
111+
.out( ),
112+
.busy( )
96113
);
114+
*/
97115

98116
// random test
99117
pulse_gen #(
100-
.CNTR_WIDTH( 32 )
101-
) pg2 (
118+
.CNTR_WIDTH( 8 )
119+
) pg1 (
102120
.clk( clk200 ),
103121
.nrst( nrst_once ),
104-
.low_width( {28'd0,RandomNumber1[3:0]} ),
105-
.high_width( {28'd0,RandomNumber1[7:4]} ),
106-
.rpt( 1'b1 ),
107-
.start( start ),
108-
.busy( ),
109-
.out( )
122+
123+
.start( 1'b1 ),
124+
.cntr_max( 16 ),
125+
.cntr_low( {4'b0,RandomNumber1[3:0]} ),
126+
127+
.out( ),
128+
.busy( )
110129
);
111130

112131

113-
logic [31:0] pg3_in_high_width = '0;
114-
logic pg3_out;
115-
logic pg3_out_rise;
132+
logic [31:0] in_high_width = '0;
133+
logic out;
134+
logic out_rise;
116135

117-
edge_detect pg3_out_ed (
136+
edge_detect out_ed (
118137
.clk( clk200 ),
119138
.nrst( nrst_once ),
120-
.in( pg3_out ),
121-
.rising( pg3_out_rise ),
139+
.in( out ),
140+
.rising( out_rise ),
122141
.falling( ),
123142
.both( )
124143
);
125144

126145
always_ff @(posedge clk200) begin
127146
if( ~nrst_once ) begin
128-
pg3_in_high_width[31:0] <= 1'b1;
147+
in_high_width[31:0] <= 1'b0;
129148
end else begin
130-
if( pg3_out_rise ) begin
131-
pg3_in_high_width[31:0] <= pg3_in_high_width[31:0] + 1'b1;
149+
if( out_rise ) begin
150+
in_high_width[31:0] <= in_high_width[31:0] + 1'b1;
132151
end
133152
end
134153
end
135154

136155
// PWM test
137-
pulse_gen #(
138-
.CNTR_WIDTH( 32 )
139-
) pg3 (
156+
/*pulse_gen #(
157+
.CNTR_WIDTH( 8 )
158+
) pg1 (
140159
.clk( clk200 ),
141160
.nrst( nrst_once ),
142-
.low_width( 32'd1 ),
143-
.high_width( pg3_in_high_width[31:0] ),
144-
.rpt( 1'b1 ),
145-
.start( start ),
146-
.busy( ),
147-
.out( pg3_out )
148-
);
149161
162+
.start( 1'b1 ),
163+
.cntr_max( 15 ),
164+
.cntr_low( {4'b0,in_high_width[3:0]} ),
165+
166+
.out( out ),
167+
.busy( )
168+
);*/
150169

151170
endmodule

0 commit comments

Comments
 (0)