1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
|
// Copyright 2015-2020 Intel Corporation.
//
// This software and the related documents are Intel copyrighted materials,
// and your use of them is governed by the express license under which they
// were provided to you ("License"). Unless the License provides otherwise,
// you may not use, modify, copy, publish, distribute, disclose or transmit
// this software or the related documents without Intel's prior written
// permission.
//
// This software and the related documents are provided as is, with no express
// or implied warranties, other than those that are expressly stated in the
// License.
/////////////////////////////////////////////////////////////////////////////////////
// //
// dla_reset_handler (renamed version of dla_acl_reset_handler) //
// //
// This block handles the generation of asynchronous and synchronous reset //
// signals for an OpenCL system. Only one type of reset will be generated //
// (based on the ASYNC_RESET parameter), with the other hard-wired to be //
// inactive, so that any logic relying on the unused reset signal will be //
// optimized away. //
// //
// The block takes an active-low reset input that is meant to be fed by a //
// global signal. For use as an asynchronous reset, the input signal directly //
// (or through a synchronizer) feeds the asynchronous reset output. For use //
// as a synchronous reset signal, the input reset is synchronized with proper //
// metastability hardening. //
// //
// *-------------------------------------------------* //
// | AVAILABLE FEATURES | //
// *-------------------------*--------------*----------------*-----------------* //
// | WIRING MODE | Synchronizer | Pulse Extender | Fanout Pipeline | //
// *-------------------------*--------------*----------------*-----------------* //
// | synchronous | Optional | Optional | Optional | //
// | async pass-through | - | - | - | //
// | async with synchronizer | Must Enable | - | - | //
// *-------------------------*--------------*----------------*-----------------* //
// //
/////////////////////////////////////////////////////////////////////////////////////
/*
Example usage of the reset handler:
modul my_module #(
parameter bit ASYNC_RESET = 1, // how do the registers CONSUME reset: 1 means registers are reset asynchronously, 0 means registers are reset synchronously
parameter bit SYNCHRONIZE_RESET = 0 // before consumption, do we SYNCHRONIZE the reset: 1 means use a synchronizer (reset arrived asynchronously), 0 means passthrough (reset was already synchronized)
...
) (
input wire clk,
input wire i_resetn, // this signal is assumed to be routed on a global network (although that is not strictlty necessary)
...
);
// local parameters
localparam NUM_RESET_COPIES = 3; // select this number to reduce the fanout of the synchronous reset signal within this module
localparam RESET_PIPE_DEPTH = 4; // select this number to allow adequate registers on the reset path for retiming
// reset related signals
// we will write code that uses both of these signals, but remember that one of them will be hard-wired to '1' based on whether we select asynchronous or synchronous reset
logic aclrn; // only one async reset signal, no special handling for fanout
logic [NUM_RESET_COPIES-1:0] sclrn; // multiple copies of synchronous reset to reduce fanout
logic resetn_synchronized; // use this signal to prevent sub-blocks from requiring additional synchronizers
// instantiate the reset handler
dla_reset_handler #(
.ASYNC_RESET (ASYNC_RESET), // select whether reset should be consumed asynchronously (1) or synchronously (0)
.USE_SYNCHRONIZER (SYNCHRONIZE_RESET), // select whether to synchronize the reset BEFORE CONSUMPTION
.SYNCHRONIZE_ACLRN (SYNCHRONIZE_RESET), // if ASYNC_RESET == 1 && USE_SYNCHRONIZER == 1, select whether o_alcrn should use the synchronized reset
.PIPE_DEPTH (RESET_PIPE_DEPTH),
.NUM_COPIES (NUM_RESET_COPIES)
) dla_reset_handler_inst (
.clk (clk),
.i_resetn (i_resetn),
.o_aclrn (aclrn),
.o_sclrn (sclrn),
.o_resetn_synchronized (resetn_synchronized)
);
// sample always block showing use of both aclrn and sclrn
always_ff @(posedge clk or negedge aclrn) begin
// code to use the async reset
// remember, if ASYNC_RESET is set to 0, then aclrn is hard-wired to '1', and all this logic is
// optimized away, so no ACLR ports are actually used in that case
if (~aclrn) begin
// reset EVERY register with aclrn
// if something is missing from this list that register will hold its value when aclrn == 0, whereas the desired behavior is typically aclrn has no effect
myreg1 <= '0;
myreg2 <= '0;
...
end
else begin
myreg1 <= ...;
myreg2 <= ...;
// code the sync reset
// Since this comes at the BOTTOM of the code, the assignments here override assignments above, thus
// the synchronous reset takes precendence over all other assignments in this always block.
// Recommended coding style is that this code should be an exact copy of the async code above,
// but optionally with select lines commented out, since not all signals may need a synchronous
// reset. It is a good practice to only reset those registers that REQUIRE a reset here.
if (~scnlrn[0]) begin // select which copy of sclrn to use, to optimize fanout of each copy
// reset only SOME register with sclrn
myreg1 <= '0;
//myreg2 <= '0; // leave this code here, but commented out, to show that this signal has intentionally NOT been reset with sclrn
end
end
end
// sample sub-module instantiation that has its own synchronizer
my_submodule1 #(
.ASYNC_RESET (ASYNC_RESET), // pass this parameter on to sub modules
...
) my_submodule1_inst (
.clk (clk),
.i_resetn (i_resetn), // pass the input reset signal straight through
...
);
// sample sub-module instantiation that does not have its own synchronizer
my_submodule2 #(
.ASYNC_RESET (ASYNC_RESET), // module may or may not have this parameter
.SYNCHRONIZE_RESET (0), // some modules may selectively allow adding a synchronizer locally or not
// this would be passed on to the USE_SYNCHRONIZER parameter in my_submodule2's dla_reset_handler
...
) my_submodule2_inst (
.clk (clk),
.i_resetn (resetn_synchronized),
...
);
...
endmodule
*/
`default_nettype none
module dla_acl_reset_handler #(
// Configure port wiring:
parameter ASYNC_RESET = 0, // set to 1 to select asynchronous reset output, 0 to select synchronous reset output
parameter SYNCHRONIZE_ACLRN = 0, // set to 1 to cause the aclrn output to be fed through the synchronizer (only if enabled), 0 to have it fed directly by i_resetn (when ASYNC_RESET = 1)
// Configure the synchronizer block:
parameter USE_SYNCHRONIZER = 1, // set to 1 to enable a clock domain crossing synchronizer, 0 to use i_resetn directly without a synchronizer
// Configure the pulse extender block:
parameter PULSE_EXTENSION = 0, // prolongs the duration of the synchronized reset pulse by PULSE_EXTENSION cycles
// Parameter is only respected when reset is synchronous (ASYNC_RESET = 0)
// Configure the fanout block:
parameter PIPE_DEPTH = 1, // number of pipeline stages for synchronous reset outputs (pipeline stages are added AFTER the synchronizer)
// A value of 0 is valid and means the input will be passed straight to the output after the synchronizer chain
parameter NUM_COPIES = 1 // number of copies of the synchronous reset output. Minimum value 1.
) (
input wire clk,
input wire i_resetn, // this MUST be an active-low reset signal, NOTE that if this signal is left disconnected, the output reset signals will be stuck ASSERTED
output logic o_aclrn, // asynchronous reset output, equal to i_resetn (synchronized if SYNCHRONIZE_ACLRN=1) if ASYNC_RESET=1, hard wired to '1' otherwise
output logic [NUM_COPIES-1:0] o_sclrn, // multiple copies of synchronous reset output, with 'dont_merge' constraints applied to the registers that feed them to help with fanout
// these signals will be hard-wired to '1' if ASYNC_RESET is 1
output logic o_resetn_synchronized // signal to drive reset to local sub-modules (to prevent the need for multiple reset synchronizers within a local block)
// if ASYNC_RESET = 1 and SYNCHRONIZE_ACLRN = 0, this is a copy of i_resetn, otherwise this is the reset signal after the synchronizer block
);
//////////////////////////////////////////
// //
// First stage: synchronize the reset //
// //
//////////////////////////////////////////
localparam SYNCHRONIZER_DEFAULT_DEPTH = 3; // number of register stages used in sychronizer, default is 3 for S10 devices, must always be 2 or larger for all devices
logic resetn_synchronized;
if (USE_SYNCHRONIZER) begin : GEN_SYNCHRONIZER
if (ASYNC_RESET) begin : GEN_ASYNC_RESET
dla_cdc_reset_async u_dla_cdc_sync_reset
(
.clk (clk),
.i_async_resetn (i_resetn),
.o_async_resetn (resetn_synchronized)
);
end else begin : GEN_SYNC_RESET
dla_cdc_reset_sync u_dla_cdc_sync_reset
(
.clk (clk),
.i_async_resetn (i_resetn),
.o_sync_resetn (resetn_synchronized)
);
end
end
else begin : NO_SYNCHRONIZER
assign resetn_synchronized = i_resetn;
end
/////////////////////////////////////
// //
// Second stage: pulse extension //
// //
/////////////////////////////////////
logic resetn_extended;
if (PULSE_EXTENSION > 0 && ASYNC_RESET == 0) begin : GEN_PULSE_EXTENDER // ignore pulse extender argument if reset type is asynchronous
// POWER-UP NOTE:
// This module has no "reset" for its own internal state, and will power up to a random state (PR). If the MSB is 0 on power-up, a spurious
// reset pulse of unknown length will be triggered while the counter counts down to -1. This is not a problem because the "real" reset pulse
// will follow. The resulting behavior will be correct whether the "real" pulse arrives during or after the spurious pulse.
// count goes from PULSE_EXTENSION down to -1
localparam WIDTH = $clog2(PULSE_EXTENSION+1) + 1; // Number of bits needed to represent PULSE_EXTENSION, plus one extra MSB for rollover detection
logic [WIDTH-1:0] count;
// Peculiar coding style is used to work around synthesis arithmetic LUT inference issue - see case 459381.
// Must express all combinational logic as happening BEFORE the arithmetic logic to guarantee LUT depth 1.
logic [WIDTH-1:0] count_mod;
logic [WIDTH-1:0] decr;
// Present synthesis with an unmistakable counter
always_ff @(posedge clk) begin //no reset
count <= count_mod - decr;
end
// Express control logic as coming before the arithmetic operands
always_comb begin
if (!resetn_synchronized) begin // active low reset is active, set count to PULSE_EXTENSION
count_mod = PULSE_EXTENSION;
decr = '0;
end
else begin // reset is not active, count down
if (!count[WIDTH-1]) begin // MSB = 0, counter has not reached -1 yet, keep counting down
count_mod = count;
decr = 1'b1;
end
else begin // counter rolled over, stay at -1
count_mod = '1;
decr = '0;
end
end
end
// original code (for readability)
// always_ff @(posedge clk) begin
// if (!resetn_synchronized) count <= PULSE_EXTENSION;
// else if (!count[WIDTH-1]) count <= count - 1;
// else count <= -1;
// end
assign resetn_extended = count[WIDTH-1];
end
else begin : NO_PULSE_EXTENDER
assign resetn_extended = resetn_synchronized;
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Third stage: reset distribution management - make multiple copies and add pipeline registers to each //
// //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
logic [NUM_COPIES-1:0] resetn_fanout_pipeline;
if (PIPE_DEPTH > 0) begin : GEN_RESET_PIPELINE
logic [NUM_COPIES-1:0] pipe [PIPE_DEPTH-1:0] /* synthesis dont_merge */;
always_ff @(posedge clk) begin //no reset
pipe[0] <= {NUM_COPIES{resetn_extended}};
for (int i=1; i<PIPE_DEPTH; i++) begin
pipe[i] <= pipe[i-1];
end
end
assign resetn_fanout_pipeline = pipe[PIPE_DEPTH-1];
end
else begin : NO_RESET_PIPELINE
assign resetn_fanout_pipeline = {NUM_COPIES{resetn_extended}};
end
//////////////////////////////////
// //
// Finally, drive the outputs //
// //
//////////////////////////////////
if (ASYNC_RESET) begin : GEN_ASYNC_RESET
assign o_aclrn = (SYNCHRONIZE_ACLRN) ? resetn_synchronized : i_resetn; //use a sychronized reset if USE_SYNCHRONIZER==1 && SYNCHRONIZE_ACLRN==1
assign o_sclrn = '1; //tie off
assign o_resetn_synchronized = o_aclrn; //choose the selected reset before fanout pipeline, pulse extension is not allowed on async reset so this is the same as after the synchronizer stage
end
else begin : GEN_SYNC_RESET
assign o_aclrn = '1; //tie off
assign o_sclrn = resetn_fanout_pipeline; //this already has synchronize, pulse extend, and fanout pipeline integrated in
assign o_resetn_synchronized = resetn_extended; //choose the selected reset before fanout pipeline
end
endmodule
`default_nettype wire
|