Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 1 | // Copyright lowRISC contributors. |
| 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | // |
| 5 | // ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------// |
| 6 | // PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND: |
| 7 | // |
Rupert Swarbrick | 59ffe88 | 2021-11-25 14:21:47 +0000 | [diff] [blame] | 8 | // util/design/gen-mubi.py |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 9 | // |
| 10 | // Double-synchronizer flop for multibit signals with additional output buffers. |
| 11 | |
| 12 | `include "prim_assert.sv" |
| 13 | |
| 14 | module prim_mubi8_sync |
| 15 | import prim_mubi_pkg::*; |
| 16 | #( |
| 17 | // Number of separately buffered output signals. |
| 18 | // The buffer cells have a don't touch constraint |
| 19 | // on them such that synthesis tools won't collapse |
| 20 | // all copies into one signal. |
| 21 | parameter int NumCopies = 1, |
| 22 | // This instantiates the synchronizer flops if set to 1. |
| 23 | // In special cases where the receiver is in the same clock domain as the sender, |
| 24 | // this can be set to 0. However, it is recommended to leave this at 1. |
| 25 | parameter bit AsyncOn = 1, |
Timothy Chen | a5e3223 | 2021-11-11 15:16:36 -0800 | [diff] [blame] | 26 | // This controls whether the mubi module institutes stability checks when |
| 27 | // AsyncOn is set. If stability checks are on, a 3rd stage of storage is |
| 28 | // added after the synchronizers and the outputs only updated if the 3rd |
| 29 | // stage and sychronizer agree. If they do not agree, the ResetValue is |
Timothy Chen | 41b2628 | 2021-11-11 16:32:51 -0800 | [diff] [blame] | 30 | // output instead. |
Timothy Chen | a5e3223 | 2021-11-11 15:16:36 -0800 | [diff] [blame] | 31 | parameter bit StabilityCheck = 0, |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 32 | // Reset value for the sync flops |
| 33 | parameter mubi8_t ResetValue = MuBi8False |
| 34 | ) ( |
| 35 | input clk_i, |
| 36 | input rst_ni, |
| 37 | input mubi8_t mubi_i, |
| 38 | output mubi8_t [NumCopies-1:0] mubi_o |
| 39 | ); |
| 40 | |
| 41 | `ASSERT_INIT(NumCopiesMustBeGreaterZero_A, NumCopies > 0) |
| 42 | |
| 43 | logic [MuBi8Width-1:0] mubi; |
| 44 | if (AsyncOn) begin : gen_flops |
Timothy Chen | a5e3223 | 2021-11-11 15:16:36 -0800 | [diff] [blame] | 45 | logic [MuBi8Width-1:0] mubi_sync; |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 46 | prim_flop_2sync #( |
| 47 | .Width(MuBi8Width), |
| 48 | .ResetValue(MuBi8Width'(ResetValue)) |
| 49 | ) u_prim_flop_2sync ( |
| 50 | .clk_i, |
| 51 | .rst_ni, |
Michael Schaffner | 50c7af2 | 2021-10-12 11:30:13 -0700 | [diff] [blame] | 52 | .d_i(MuBi8Width'(mubi_i)), |
Timothy Chen | a5e3223 | 2021-11-11 15:16:36 -0800 | [diff] [blame] | 53 | .q_o(mubi_sync) |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 54 | ); |
Timothy Chen | a5e3223 | 2021-11-11 15:16:36 -0800 | [diff] [blame] | 55 | |
| 56 | if (StabilityCheck) begin : gen_stable_chks |
| 57 | logic [MuBi8Width-1:0] mubi_q; |
| 58 | prim_flop #( |
| 59 | .Width(MuBi8Width), |
| 60 | .ResetValue(MuBi8Width'(ResetValue)) |
| 61 | ) u_prim_flop_3rd_stage ( |
| 62 | .clk_i, |
| 63 | .rst_ni, |
| 64 | .d_i(mubi_sync), |
| 65 | .q_o(mubi_q) |
| 66 | ); |
| 67 | |
| 68 | logic [MuBi8Width-1:0] sig_unstable; |
| 69 | prim_xor2 #( |
| 70 | .Width(MuBi8Width) |
| 71 | ) u_mubi_xor ( |
| 72 | .in0_i(mubi_sync), |
| 73 | .in1_i(mubi_q), |
| 74 | .out_o(sig_unstable) |
| 75 | ); |
| 76 | |
| 77 | logic [MuBi8Width-1:0] reset_value; |
| 78 | assign reset_value = ResetValue; |
| 79 | |
| 80 | for (genvar k = 0; k < MuBi8Width; k++) begin : gen_bufs_muxes |
| 81 | logic [MuBi8Width-1:0] sig_unstable_buf; |
| 82 | |
| 83 | // each mux gets its own buffered output, this ensures the OR-ing |
| 84 | // cannot be defeated in one place. |
| 85 | prim_sec_anchor_buf #( |
| 86 | .Width(MuBi8Width) |
| 87 | ) u_sig_unstable_buf ( |
| 88 | .in_i(sig_unstable), |
| 89 | .out_o(sig_unstable_buf) |
| 90 | ); |
| 91 | |
| 92 | // if any xor indicates signal is unstable, output the reset |
| 93 | // value. |
| 94 | prim_clock_mux2 #( |
| 95 | .NoFpgaBufG(1'b1) |
| 96 | ) u_mux ( |
| 97 | .clk0_i(mubi_q[k]), |
| 98 | .clk1_i(reset_value[k]), |
| 99 | .sel_i(|sig_unstable_buf), |
| 100 | .clk_o(mubi[k]) |
| 101 | ); |
| 102 | end |
| 103 | |
| 104 | end else begin : gen_no_stable_chks |
| 105 | assign mubi = mubi_sync; |
| 106 | end |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 107 | end else begin : gen_no_flops |
| 108 | logic unused_clk; |
| 109 | logic unused_rst; |
| 110 | assign unused_clk = clk_i; |
| 111 | assign unused_rst = rst_ni; |
Michael Schaffner | 50c7af2 | 2021-10-12 11:30:13 -0700 | [diff] [blame] | 112 | assign mubi = MuBi8Width'(mubi_i); |
Michael Schaffner | 443352e | 2021-10-05 15:43:26 -0700 | [diff] [blame] | 113 | end |
| 114 | |
| 115 | for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs |
| 116 | logic [MuBi8Width-1:0] mubi_out; |
| 117 | for (genvar k = 0; k < MuBi8Width; k++) begin : gen_bits |
| 118 | prim_buf u_prim_buf ( |
| 119 | .in_i(mubi[k]), |
| 120 | .out_o(mubi_out[k]) |
| 121 | ); |
| 122 | end |
| 123 | assign mubi_o[j] = mubi8_t'(mubi_out); |
| 124 | end |
| 125 | |
| 126 | //////////////// |
| 127 | // Assertions // |
| 128 | //////////////// |
| 129 | |
| 130 | // The outputs should be known at all times. |
| 131 | `ASSERT_KNOWN(OutputsKnown_A, mubi_o) |
| 132 | |
| 133 | // If the multibit signal is in a transient state, we expect it |
| 134 | // to be stable again within one clock cycle. |
| 135 | // DV will exclude these three assertions by name, thus added a module name prefix to make it |
| 136 | // harder to accidentally replicate in other modules. |
| 137 | `ASSERT(PrimMubi8SyncCheckTransients_A, |
| 138 | !(mubi_i inside {MuBi8True, MuBi8False}) |
| 139 | |=> |
| 140 | (mubi_i inside {MuBi8True, MuBi8False})) |
| 141 | |
| 142 | // If a signal departs from passive state, we expect it to move to the active state |
| 143 | // with only one transient cycle in between. |
| 144 | `ASSERT(PrimMubi8SyncCheckTransients0_A, |
| 145 | $past(mubi_i == MuBi8False) && |
| 146 | !(mubi_i inside {MuBi8True, MuBi8False}) |
| 147 | |=> |
| 148 | (mubi_i == MuBi8True)) |
| 149 | |
| 150 | `ASSERT(PrimMubi8SyncCheckTransients1_A, |
| 151 | $past(mubi_i == MuBi8True) && |
| 152 | !(mubi_i inside {MuBi8True, MuBi8False}) |
| 153 | |=> |
| 154 | (mubi_i == MuBi8False)) |
| 155 | |
| 156 | endmodule : prim_mubi8_sync |