Skip to content

Commit

Permalink
Add clk_int_div_static (#183)
Browse files Browse the repository at this point in the history
* Add wrapper for dynamic clk_int_div module for static clk division

* Improve documentation of clk_int_div and add notes about constraints

* Add clk_int_div_static TB to CI

* Update README

* Fix initalization instead of assignment bug

* Update lint waivers for blocking assignments in clk_int_div
  • Loading branch information
meggiman authored Jun 9, 2023
1 parent 6a8e38b commit 534340f
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ stages:
script:
- bender script vsim -t test > compile.tcl
- $VSIM -c -quiet -do 'source compile.tcl; quit'
- $VSIM -c $TOPLEVEL -do "run -all" $PARAM1 $PARAM2
- $VSIM -c $TOPLEVEL -voptargs="-timescale 1ns/100ps" -do "run -all" $PARAM1 $PARAM2
- (! grep -n "Error:" transcript)

tests:
Expand All @@ -38,6 +38,7 @@ tests:
- cb_filter_tb
# - cdc_fifo_clearable_tb
- clk_int_div_tb
- clk_int_div_static_tb
- clk_mux_glitch_free_tb
- id_queue_tb
- isochronous_crossing_tb
Expand Down
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ sources:
- src/read.sv
- src/cdc_reset_ctrlr_pkg.sv
# Level 1
- src/clk_int_div_static.sv
- src/addr_decode_napot.sv
- src/cdc_2phase.sv
- src/cdc_4phase.sv
Expand Down Expand Up @@ -128,6 +129,7 @@ sources:
- test/stream_omega_net_tb.sv
- test/stream_xbar_tb.sv
- test/clk_int_div_tb.sv
- test/clk_int_div_static_tb.sv
- test/clk_mux_glitch_free_tb.sv
- test/lossy_valid_to_stream_tb.sv

Expand Down
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ Please note that cells with status *deprecated* are not to be used for new desig

### Clocks and Resets

| Name | Description | Status | Superseded By |
| ----------------------- | ------------------------------------------------------------------------------------ | ------------ | ------------- |
| `clk_int_div` | Arbitrary integer clock divier with config interface and 50% output clock duty cycle | active | |
| `clk_div` | Clock divider with integer divisor | *deprecated* | `clk_int_div` |
| `clock_divider` | Clock divider with configuration registers | *deprecated* | `clk_int_div` |
| `clock_divider_counter` | Clock divider using a counter | *deprecated* | `clk_int_div` |
| `rstgen` | Reset synchronizer | active | |
| `rstgen_bypass` | Reset synchronizer with dedicated test reset bypass | active | |
| Name | Description | Status | Superseded By |
|-------------------------|---------------------------------------------------------------------------------------|--------------|---------------|
| `clk_int_div` | Arbitrary integer clock divider with config interface and 50% output clock duty cycle | active | |
| `clk_int_div_static` | A convenience wrapper around `clk_int_div` with static division factor. | active | |
| `clk_div` | Clock divider with integer divisor | *deprecated* | `clk_int_div` |
| `clock_divider` | Clock divider with configuration registers | *deprecated* | `clk_int_div` |
| `clock_divider_counter` | Clock divider using a counter | *deprecated* | `clk_int_div` |
| `rstgen` | Reset synchronizer | active | |
| `rstgen_bypass` | Reset synchronizer with dedicated test reset bypass | active | |

### Clock Domains and Asynchronous Crossings

Expand Down
8 changes: 4 additions & 4 deletions lint/common_cells.style.waiver
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ waive --rule=typedef-structs-unions --line=29 --location="src/ecc_encode.sv"
# That is a known issue with string parameter in Synopsys DC
waive --rule=explicit-parameter-storage-type --line=19 --location="src/stream_arbiter.sv"
waive --rule=explicit-parameter-storage-type --line=19 --location="src/stream_arbiter_flushable.sv"
waive --rule=always-ff-non-blocking --line=276 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=279 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=288 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=291 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=290 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=293 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=302 --location="src/clk_int_div.sv"
waive --rule=always-ff-non-blocking --line=305 --location="src/clk_int_div.sv"
# Allow strings to continue across lines
waive --rule=forbid-line-continuations
22 changes: 18 additions & 4 deletions src/clk_int_div.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,31 @@
// clk_o will always be directly driven by clk_i. Use this mode for DFT of the
// downstream logic.
//
// Parameters: DIV_VALUE_WIDTH: The number of bits to use for the internal
// Parameters:
//
// DIV_VALUE_WIDTH: The number of bits to use for the internal
// counter. Defines the maximum division factor.
//
// DEFAULT_DIV_VALUE: The default division factor to use after reset. Use this
// parameter and tie div_valid_i to zero if you don't need at runtime
// configurability. An elaboration time error will be issued if the supplied
// default div value is not repressentable with DIV_VALUE_WIDTH bits.
//
// ENABLE_CLOCK_IN_RESET: If 1'b1, clk_o will not be gated during reset and will
// immediately start clocking with the configured DEFAULT_DIV_VALUE. (Disabled
// by default).
// ENABLE_CLOCK_IN_RESET: If 1'b1, the clock gate will be enabled during reset
// which allows the clk_int_div instance to bypass the clock during reset, IFF
// the DEFAULT_DIV_VALUE is 1. For all other DEFAULT_DIV_VALUES, the output
// clock will not be available until rst_ni is deasserted!
//
// IMPORTANT!!!
//
// All clock gating/logic within this design is performed by dedicated clock logic
// tech cells. By default the common_cell library uses the behavioral models in
// the `tech_cells_generic` repository. However, for synthesis these cells need to be
// mapped to dedicated cells from your standard cell library, preferably ones
// that are designed for clock logic (they have balanced rise and fall time).
// During synthesis you furthermore have to properly set `dont_touch` or
// `size_only` attributes to prevent the logic synthesizer from replacing those
// cells with regular logic gates which could end up being glitchty!
//
//-----------------------------------------------------------------------------
// Copyright (C) 2022 ETH Zurich, University of Bologna Copyright and related
Expand Down
95 changes: 95 additions & 0 deletions src/clk_int_div_static.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//-----------------------------------------------------------------------------
// Title : Static Integer Clock Divider
//-----------------------------------------------------------------------------
// File : clk_int_div_static.sv
// Author : Manuel Eggimann <[email protected]>
// Created : 08.05.2023
//-----------------------------------------------------------------------------
// Description :
//
// This module implements a static arbitrary integer divider. Static in this
// case means, the divider value is constant at elaboration time (SV parameter).
// It supports arbitrary integer division with a guaranteed 50% duty cycle for
// odd and even division.

// Internally, this module is wrapper around the "at-runtime" configurable
// `clk_int_div`module. If you need to change the division factor at-runtime you
// should directly use `clk_int_div`instead. However if all you need is a single
// division factor this module provides a convenience wrapper for you with a
// simplified interface.
//
// The `en_i` signal can be used to enable or disable the output clock in a safe
// manner (there is an internal, glitch-free clock gate).
//
// Parameters:
//
// DIV_VALUE: The integer value by which the clock shall be divided. Must be
// non-zero integer smaller than 2^32-1.
//
// ENABLE_CLOCK_IN_RESET: If 1'b1, the clock gate will be enabled during reset
// which allows the clk_int_div instance to bypass the clock during reset, IFF
// the DEFAULT_DIV_VALUE is 1. For all other DEFAULT_DIV_VALUES, the output
// clock will not be available until rst_ni is deasserted!
//
// IMPORTANT!!!
//
// All clock gating/logic within this design is performed by dedicated clock
// logic tech cells. By default the common_cell library uses the behavioral
// models in the `tech_cells_generic` repository. However, for synthesis these
// cells need to be mapped to dedicated cells from your standard cell library,
// preferably ones that are designed for clock logic (they have balanced rise
// and fall time). During synthesis you furthermore have to properly set
// `dont_touch` or `size_only` attributes to prevent the logic synthesizer from
// replacing those cells with regular logic gates which could end up being
// glitchty!
//
//-----------------------------------------------------------------------------
// Copyright (C) 2023 ETH Zurich, University of Bologna Copyright and related
// rights are licensed under the Solderpad Hardware License, Version 0.51 (the
// "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law or
// agreed to in writing, software, hardware and materials distributed under this
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.
// SPDX-License-Identifier: SHL-0.51
// -----------------------------------------------------------------------------


module clk_int_div_static #(
parameter int unsigned DIV_VALUE = 1,
parameter bit ENABLE_CLOCK_IN_RESET = 1'b1
) (
input logic clk_i,
input logic rst_ni,
input logic en_i,
input logic test_mode_en_i,
output logic clk_o
);
if (DIV_VALUE == 0) begin : gen_elab_error
$error("DIV_VALUE must be strictly larger than 0.");
end

localparam int unsigned DivValueWidth = $clog2(DIV_VALUE+1);

logic [DivValueWidth-1:0] div_value;
assign div_value = DIV_VALUE;

clk_int_div #(
.DIV_VALUE_WIDTH ( DivValueWidth ),
.DEFAULT_DIV_VALUE ( DIV_VALUE ),
.ENABLE_CLOCK_IN_RESET ( ENABLE_CLOCK_IN_RESET )
) i_clk_int_div (
.clk_i,
.rst_ni,
.en_i,
.test_mode_en_i,
.div_i ( div_value ),
.div_valid_i ( 1'b0 ),
.div_ready_o ( ),
.clk_o,
.cycl_count_o ( )
);

endmodule
84 changes: 84 additions & 0 deletions test/clk_int_div_static_tb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2023 ETH Zurich, University of Bologna
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// SPDX-License-Identifier: SHL-0.51
//-----------------------------------------------------------------------------

module clk_int_div_static_tb;
parameter int unsigned NumTestCycles = 10000;
parameter realtime TClkIn = 10ns;
localparam int unsigned RstClkCycles = 10;

localparam int unsigned MaxClkDiv = 100;

realtime t_delta = 100ps;

logic clk, rstn;
logic test_mode_en;
logic enable;
logic clk_out [MaxClkDiv];


// system clock and reset
clk_rst_gen #(
.ClkPeriod ( TClkIn ),
.RstClkCycles ( RstClkCycles )
) i_clk_rst_gen_reg (
.clk_o ( clk ),
.rst_no ( rstn )
);

property T_clk(real clk_period);
realtime current_time;
realtime actual_period;
disable iff (!rstn || !enable)
(('1, current_time = $realtime)) |=>
('1, actual_period = $realtime - current_time) |->
(($realtime - current_time >= clk_period - t_delta) && ($realtime - current_time < clk_period + t_delta));
endproperty


for (genvar i = 1; i < MaxClkDiv; i++) begin :gen_clk_divs
clk_int_div_static #(
.DIV_VALUE(i),
.ENABLE_CLOCK_IN_RESET(1'b1)
) i_dut(
.clk_i ( clk ),
.rst_ni ( rstn ),
.en_i ( enable ),
.test_mode_en_i ( test_mode_en ),
.clk_o ( clk_out[i] )
);

assert_period_period: assert property (@(posedge clk_out[i]) T_clk(TClkIn*i)) else
$error("Output period of div %d clock is incorrect. Should be in range %d to %d.", i, TClkIn*i-t_delta, TClkIn*i+t_delta);

end

initial begin : apply_stimuli
test_mode_en = 1'b0;
enable = 1'b1;
$info("Resetting clock dividers...");
@(posedge rstn);

// Randomly enable and disable the output clock
repeat(NumTestCycles) begin
@(posedge clk);
if ($urandom_range(0, 1000)<5) begin
enable = 1'b0;
repeat($urandom_range(1, 100)) @(posedge clk);
enable = 1'b1;
end
end
$info("Test finished");
$stop();
end

endmodule

0 comments on commit 534340f

Please sign in to comment.