| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------// |
| // PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND: |
| // |
| // util/design/gen-mubi.py |
| // |
| // Double-synchronizer flop for multibit signals with additional output buffers. |
| |
| `include "prim_assert.sv" |
| |
| module prim_mubi4_sync |
| import prim_mubi_pkg::*; |
| #( |
| // Number of separately buffered output signals. |
| // The buffer cells have a don't touch constraint |
| // on them such that synthesis tools won't collapse |
| // all copies into one signal. |
| parameter int NumCopies = 1, |
| // This instantiates the synchronizer flops if set to 1. |
| // In special cases where the receiver is in the same clock domain as the sender, |
| // this can be set to 0. However, it is recommended to leave this at 1. |
| parameter bit AsyncOn = 1, |
| // This controls whether the mubi module institutes stability checks when |
| // AsyncOn is set. If stability checks are on, a 3rd stage of storage is |
| // added after the synchronizers and the outputs only updated if the 3rd |
| // stage and sychronizer agree. If they do not agree, the ResetValue is |
| // output instead. |
| parameter bit StabilityCheck = 0, |
| // Reset value for the sync flops |
| parameter mubi4_t ResetValue = MuBi4False |
| ) ( |
| input clk_i, |
| input rst_ni, |
| input mubi4_t mubi_i, |
| output mubi4_t [NumCopies-1:0] mubi_o |
| ); |
| |
| `ASSERT_INIT(NumCopiesMustBeGreaterZero_A, NumCopies > 0) |
| |
| logic [MuBi4Width-1:0] mubi; |
| if (AsyncOn) begin : gen_flops |
| logic [MuBi4Width-1:0] mubi_sync; |
| prim_flop_2sync #( |
| .Width(MuBi4Width), |
| .ResetValue(MuBi4Width'(ResetValue)) |
| ) u_prim_flop_2sync ( |
| .clk_i, |
| .rst_ni, |
| .d_i(MuBi4Width'(mubi_i)), |
| .q_o(mubi_sync) |
| ); |
| |
| if (StabilityCheck) begin : gen_stable_chks |
| logic [MuBi4Width-1:0] mubi_q; |
| prim_flop #( |
| .Width(MuBi4Width), |
| .ResetValue(MuBi4Width'(ResetValue)) |
| ) u_prim_flop_3rd_stage ( |
| .clk_i, |
| .rst_ni, |
| .d_i(mubi_sync), |
| .q_o(mubi_q) |
| ); |
| |
| logic [MuBi4Width-1:0] sig_unstable; |
| prim_xor2 #( |
| .Width(MuBi4Width) |
| ) u_mubi_xor ( |
| .in0_i(mubi_sync), |
| .in1_i(mubi_q), |
| .out_o(sig_unstable) |
| ); |
| |
| logic [MuBi4Width-1:0] reset_value; |
| assign reset_value = ResetValue; |
| |
| for (genvar k = 0; k < MuBi4Width; k++) begin : gen_bufs_muxes |
| logic [MuBi4Width-1:0] sig_unstable_buf; |
| |
| // each mux gets its own buffered output, this ensures the OR-ing |
| // cannot be defeated in one place. |
| prim_sec_anchor_buf #( |
| .Width(MuBi4Width) |
| ) u_sig_unstable_buf ( |
| .in_i(sig_unstable), |
| .out_o(sig_unstable_buf) |
| ); |
| |
| // if any xor indicates signal is unstable, output the reset |
| // value. |
| prim_clock_mux2 #( |
| .NoFpgaBufG(1'b1) |
| ) u_mux ( |
| .clk0_i(mubi_q[k]), |
| .clk1_i(reset_value[k]), |
| .sel_i(|sig_unstable_buf), |
| .clk_o(mubi[k]) |
| ); |
| end |
| |
| `ASSERT(OutputIfUnstable_A, sig_unstable |-> mubi_o == {NumCopies{reset_value}}) |
| `ASSERT(OutputDelay_A, ##3 !sig_unstable |-> mubi_o == {NumCopies{$past(mubi_i, 3)}}) |
| end else begin : gen_no_stable_chks |
| assign mubi = mubi_sync; |
| // Without the sampled rst_ni pre-condition, this may cause false assertion failures |
| // right after a reset release, since the "iff disable" condition with the rst_ni is |
| // sampled in the "observed" SV scheduler region after all assignments have been |
| // evaluated. This is a simulation artifact due to reset synchronization in RTL, which |
| // releases rst_ni on the active clock edge. This causes the assertion to evaluate |
| // although the reset was actually 0 when entering this simulation cycle. |
| `ASSERT(OutputDelay_A, rst_ni |-> ##2 mubi_o == {NumCopies{$past(mubi_i, 2)}}) |
| end |
| end else begin : gen_no_flops |
| |
| // This unused companion logic helps remove lint errors |
| // for modules where clock and reset are used for assertions only |
| // This logic will be removed for synthesis since it is unloaded. |
| mubi4_t unused_logic; |
| always_ff @(posedge clk_i or negedge rst_ni) begin |
| if (!rst_ni) begin |
| unused_logic <= MuBi4False; |
| end else begin |
| unused_logic <= mubi_i; |
| end |
| end |
| |
| assign mubi = MuBi4Width'(mubi_i); |
| |
| `ASSERT(OutputDelay_A, mubi_o == {NumCopies{mubi_i}}) |
| end |
| |
| for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs |
| logic [MuBi4Width-1:0] mubi_out; |
| for (genvar k = 0; k < MuBi4Width; k++) begin : gen_bits |
| prim_buf u_prim_buf ( |
| .in_i(mubi[k]), |
| .out_o(mubi_out[k]) |
| ); |
| end |
| assign mubi_o[j] = mubi4_t'(mubi_out); |
| end |
| |
| //////////////// |
| // Assertions // |
| //////////////// |
| |
| // The outputs should be known at all times. |
| `ASSERT_KNOWN(OutputsKnown_A, mubi_o) |
| |
| endmodule : prim_mubi4_sync |