Hi,
up until a minute ago I thought I understood the generate construct of SystemVerilog. I have used it plenty of times in the past with success.
However, looking through some code from Xilinx I found this:
module xpm_fifo_rst # (
parameter integer COMMON_CLOCK = 1,
parameter integer CDC_DEST_SYNC_FF = 2,
parameter integer SIM_ASSERT_CHK = 0
) (
input wire rst,
input wire wr_clk,
input wire rd_clk,
output wire wr_rst,
output wire rd_rst,
output wire wr_rst_busy,
output wire rd_rst_busy
);
reg [1:0] power_on_rst = 2'h3;
wire rst_i;
// -------------------------------------------------------------------------------------------------------------------
// Reset Logic
// -------------------------------------------------------------------------------------------------------------------
//Keeping the power on reset to work even when the input reset(to xpm_fifo) is not applied or not using
always @ (posedge wr_clk) begin
power_on_rst <= {power_on_rst[0], 1'b0};
end
assign rst_i = power_on_rst[1] | rst;
// Write and read reset generation for common clock FIFO
if (COMMON_CLOCK == 1) begin : gen_rst_cc
reg [2:0] fifo_wr_rst_cc = 3'b00;
assign wr_rst = fifo_wr_rst_cc[2];
assign rd_rst = fifo_wr_rst_cc[2];
assign rd_rst_busy = fifo_wr_rst_cc[2];
assign wr_rst_busy = fifo_wr_rst_cc[2];
// synthesis translate_off
`ifndef DISABLE_XPM_ASSERTIONS
if (SIM_ASSERT_CHK == 1) begin: assert_rst
always @ (posedge wr_clk) begin
assert (!$isunknown(rst)) else $warning ("Input port 'rst' has unknown value 'X' or 'Z' at %0t. This may cause the outputs of FIFO to be 'X' or 'Z' in simulation. Ensure 'rst' has a valid value ('0' or '1')",$time);
end
end : assert_rst
`endif
// synthesis translate_on
always @ (posedge wr_clk) begin
if (rst_i) begin
fifo_wr_rst_cc <= 3'h7;
end else begin
fifo_wr_rst_cc <= {fifo_wr_rst_cc[1:0],1'b0};
end
end
end : gen_rst_cc
// Write and read reset generation for independent clock FIFO
if (COMMON_CLOCK == 0) begin : gen_rst_ic
wire fifo_wr_rst_rd;
wire fifo_rd_rst_wr_i;
reg fifo_wr_rst_i = 1'b0;
reg wr_rst_busy_i = 1'b0;
reg fifo_rd_rst_i = 1'b0;
reg fifo_rd_rst_ic = 1'b0;
reg fifo_wr_rst_ic = 1'b0;
reg wr_rst_busy_ic = 1'b0;
reg rst_seq_reentered = 1'b0;
assign wr_rst = fifo_wr_rst_ic | wr_rst_busy_ic;
assign rd_rst = fifo_rd_rst_ic;
assign rd_rst_busy = fifo_rd_rst_ic;
assign wr_rst_busy = wr_rst_busy_ic;
(* fsm_safe_state = "default_state" *) enum logic [2:0] {WRST_IDLE = 3'b000,
WRST_IN = 3'b010,
WRST_OUT = 3'b111,
WRST_EXIT = 3'b110,
WRST_GO2IDLE = 3'b100} curr_wrst_state = WRST_IDLE, next_wrst_state = WRST_IDLE;
(* fsm_safe_state = "default_state" *) enum logic [1:0] {RRST_IDLE = 2'b00,
RRST_IN = 2'b10,
RRST_OUT = 2'b11,
RRST_EXIT = 2'b01} curr_rrst_state = RRST_IDLE, next_rrst_state = RRST_IDLE;
// synthesis translate_off
`ifndef DISABLE_XPM_ASSERTIONS
if (SIM_ASSERT_CHK == 1) begin: assert_rst
always @ (posedge wr_clk) begin
assert (!$isunknown(rst)) else $warning ("Input port 'rst' has unknown value 'X' or 'Z' at %0t. This may cause the outputs of FIFO to be 'X' or 'Z' in simulation. Ensure 'rst' has a valid value ('0' or '1')",$time);
end
end : assert_rst
`endif
// synthesis translate_on
always @ (posedge wr_clk) begin
if (rst_i) begin
rst_seq_reentered <= 1'b0;
end else begin
if (curr_wrst_state == WRST_GO2IDLE) begin
rst_seq_reentered <= 1'b1;
end
end
end
always @* begin
case (curr_wrst_state)
WRST_IDLE: begin
if (rst_i)
next_wrst_state <= WRST_IN;
else
next_wrst_state <= WRST_IDLE;
end
WRST_IN: begin
if (rst_i)
next_wrst_state <= WRST_IN;
else if (fifo_rd_rst_wr_i)
next_wrst_state <= WRST_OUT;
else
next_wrst_state <= WRST_IN;
end
WRST_OUT: begin
if (rst_i)
next_wrst_state <= WRST_IN;
else if (~fifo_rd_rst_wr_i)
next_wrst_state <= WRST_EXIT;
else
next_wrst_state <= WRST_OUT;
end
WRST_EXIT: begin
if (rst_i)
next_wrst_state <= WRST_IN;
else if (~rst & ~rst_seq_reentered)
next_wrst_state <= WRST_GO2IDLE;
else if (rst_seq_reentered)
next_wrst_state <= WRST_IDLE;
else
next_wrst_state <= WRST_EXIT;
end
WRST_GO2IDLE: begin
next_wrst_state <= WRST_IN;
end
default: next_wrst_state <= WRST_IDLE;
endcase
end
always @ (posedge wr_clk) begin
curr_wrst_state <= next_wrst_state;
fifo_wr_rst_ic <= fifo_wr_rst_i;
wr_rst_busy_ic <= wr_rst_busy_i;
end
always @* begin
case (curr_wrst_state)
WRST_IDLE : fifo_wr_rst_i = rst_i;
WRST_IN : fifo_wr_rst_i = 1'b1;
WRST_OUT : fifo_wr_rst_i = 1'b0;
WRST_EXIT : fifo_wr_rst_i = 1'b0;
WRST_GO2IDLE : fifo_wr_rst_i = 1'b1;
default: fifo_wr_rst_i = fifo_wr_rst_ic;
endcase
end
always @* begin
case (curr_wrst_state)
WRST_IDLE: wr_rst_busy_i = rst_i;
WRST_IN : wr_rst_busy_i = 1'b1;
WRST_OUT : wr_rst_busy_i = 1'b1;
WRST_EXIT: wr_rst_busy_i = 1'b1;
default: wr_rst_busy_i = wr_rst_busy_ic;
endcase
end
always @* begin
case (curr_rrst_state)
RRST_IDLE: begin
if (fifo_wr_rst_rd)
next_rrst_state <= RRST_IN;
else
next_rrst_state <= RRST_IDLE;
end
RRST_IN : next_rrst_state <= RRST_OUT;
RRST_OUT : begin
if (~fifo_wr_rst_rd)
next_rrst_state <= RRST_EXIT;
else
next_rrst_state <= RRST_OUT;
end
RRST_EXIT: next_rrst_state <= RRST_IDLE;
default: next_rrst_state <= RRST_IDLE;
endcase
end
always @ (posedge rd_clk) begin
curr_rrst_state <= next_rrst_state;
fifo_rd_rst_ic <= fifo_rd_rst_i;
end
always @* begin
case (curr_rrst_state)
RRST_IDLE: fifo_rd_rst_i <= fifo_wr_rst_rd;
RRST_IN : fifo_rd_rst_i <= 1'b1;
RRST_OUT : fifo_rd_rst_i <= 1'b1;
RRST_EXIT: fifo_rd_rst_i <= 1'b0;
default: fifo_rd_rst_i <= 1'b0;
endcase
end
// Synchronize the wr_rst (fifo_wr_rst_ic) in read clock domain
xpm_cdc_sync_rst #(
.DEST_SYNC_FF (CDC_DEST_SYNC_FF),
.INIT (0),
.INIT_SYNC_FF (1),
.SIM_ASSERT_CHK (0),
.VERSION (0))
wrst_rd_inst (
.src_rst (fifo_wr_rst_ic),
.dest_clk (rd_clk),
.dest_rst (fifo_wr_rst_rd));
// Synchronize the rd_rst (fifo_rd_rst_ic) in write clock domain
xpm_cdc_sync_rst #(
.DEST_SYNC_FF (CDC_DEST_SYNC_FF),
.INIT (0),
.INIT_SYNC_FF (1),
.SIM_ASSERT_CHK (0),
.VERSION (0))
rrst_wr_inst (
.src_rst (fifo_rd_rst_ic),
.dest_clk (wr_clk),
.dest_rst (fifo_rd_rst_wr_i));
end : gen_rst_ic
endmodule : xpm_fifo_rst
This is just a module that comes with the current Vivado installation and which is used to handle reset signals in a fifo, I pasted the entire thing in case it is relevant.
Just a few lines into the module there a line which reads
if (COMMON_CLOCK == 1) begin : gen_rst_cc
that if statement is not inside of any always, function or task, it is just standing on it’s own. Inside the if code there are register definitions, assign statements, etc.
My confusion comes from the fact that I always thought that in order to have conditional instantiations, declarations and assignments one always needed a generate block.
Can somebody clarify that for me please? I have searched everywhere and I have not found any examples of code where the generate or if statements are used as the case above…