diff options
Diffstat (limited to 'python/openvino/demo/ip/intel_ai_ip/verilog/dla_acl_reset_handler.sv')
| -rw-r--r-- | python/openvino/demo/ip/intel_ai_ip/verilog/dla_acl_reset_handler.sv | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/python/openvino/demo/ip/intel_ai_ip/verilog/dla_acl_reset_handler.sv b/python/openvino/demo/ip/intel_ai_ip/verilog/dla_acl_reset_handler.sv new file mode 100644 index 0000000..aff51df --- /dev/null +++ b/python/openvino/demo/ip/intel_ai_ip/verilog/dla_acl_reset_handler.sv @@ -0,0 +1,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 |
