Pre- and Post-Layout Simulation with VCS and Verdi in a CIC Filter Design
Synopsys VCS and Verdi provide a robust environment for both pre- and post-layout digital simulations. This walkthrough uses a CIC filter as the design under test to illustrate a typical workflow from compile to waveform analysis, employing Makefiles and file lists to streamline the process.
RTL Refinement Before Simulation
The original CIC filter had a comb stage susceptible to race conditions, causing glitches in post-layout simulations and preventing successful compilation under VCS. An intermediate pipeline register eliminates the hazard, as shown in the revised design below.
module cic_filter (
input clk,
input rst_n,
input in,
output reg [18:0] out
);
wire clk_div;
reg [18:0] integrator1, integrator2, integrator3;
wire [18:0] integrator1_next, integrator2_next, integrator3_next;
assign integrator1_next = integrator1 + in;
assign integrator2_next = integrator2 + integrator1;
assign integrator3_next = integrator3 + integrator2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
integrator1 <= 19'd0;
integrator2 <= 19'd0;
integrator3 <= 19'd0;
end else begin
integrator1 <= integrator1_next;
integrator2 <= integrator2_next;
integrator3 <= integrator3_next;
end
end
divider div_inst (
.clk(clk),
.rst_n(rst_n),
.clk_div(clk_div)
);
reg [18:0] comb_a, comb_b, comb_c;
reg [18:0] comb_a_next, comb_b_next, comb_c_next;
always @(posedge clk_div or negedge rst_n) begin
if (!rst_n) begin
comb_a_next <= 19'd0;
comb_b_next <= 19'd0;
comb_c_next <= 19'd0;
end else begin
comb_a_next <= integrator3_next - comb_a;
comb_b_next <= comb_a_next - comb_b;
comb_c_next <= comb_b_next - comb_c;
end
end
always @(posedge clk_div or negedge rst_n) begin
if (!rst_n) begin
comb_a <= 19'd0;
comb_b <= 19'd0;
comb_c <= 19'd0;
end else begin
comb_a <= integrator3_next;
comb_b <= comb_a_next;
comb_c <= comb_b_next;
end
end
always @(posedge clk_div or negedge rst_n) begin
if (!rst_n) out <= 19'd0;
else out <= comb_c_next;
end
endmodule
Pre-Layout Simulation Setup
VCS separates compilation and simulation phases. A Makefile automates the invocation, defines a timescale, and selects the required FSDB waveform format for Verdi. A file list (file_list.f) controls which sources are used and allows easy switching between RTL and netlist.
.PHONY: vcs_com vcs_sim verdi
OUTPUT = cic_filter
TIMESCALE = 1ns/1ns
vcs_com:
cd ../vcs && vcs -full64 +v2k -debug_pp -timescale=${TIMESCALE} -cpp g++ -cc gcc -LDFLAGS -no-pie -LDFLAGS -Wl,--no-as-needed -CFLAGS -fPIE -fsdb -f file_list.f -o ${OUTPUT} -l compile.log
vcs_sim:
cd ../vcs && ./${OUTPUT} -l sim.log
verdi:
cd ../verdi && verdi -f ../vcs/file_list.f -ssf ../vcs/tb_${OUTPUT}.fsdb
For pre-layout simulation, the file list activates RTL sources and the testbench, while netlist and standard cell library references remain commented out:
+define+FSDB
// RTL Sources
../src/cic_filter.v
../src/divider64.v
// Netlist
//../icc/outputs/cic_filter_post_layout.v
// Standard Cell Library
//../lib/verilog/smic18.v
// Testbench
../tb/tb_cic_filter.v
The testbench uses a clock period definition, resets the design, streams a digital input pattern from a file, and terminates the simulation with $finish. FSDB dumping is conditionally compiled, and SDF annotation code is prepared for post-layout use but disabled with a macro.
`define period 78.125
module testbench;
reg clk, rst_n, in;
wire [18:0] out;
always #`period clk <= ~clk;
initial begin
rst_n = 1'b0;
clk = 1'b0;
#500;
rst_n = 1'b1;
#(10 * 12800 * `period);
$finish;
end
integer i;
reg mem[0:3000000];
initial $readmemb("../src/1k1000mv.txt", mem);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
i = 0;
in <= 1'b0;
end else begin
in <= mem[i];
i = i + 1;
end
end
cic_filter cic (
.clk(clk),
.rst_n(rst_n),
.in(in),
.out(out)
);
`ifdef FSDB
initial begin
$fsdbDumpfile("tb_cic_filter.fsdb");
$fsdbDumpvars;
$fsdbDumpMDA();
end
`endif
// `define post_sim
`ifdef post_sim
initial begin
$sdf_annotate("../icc/outputs/cic_filter_post_layout.sdf", cic);
end
`endif
endmodule
Execute the three targets sequentially from the project directory.
make vcs_com
make vcs_sim
make verdi
Verdi loads the FSDB file and the source list. Signals or entire instances can be added to the waveform viewer through the context menu.
Post-Layout Simulation
To run post-layout simulation, update the file list to point to the synthesized netlist and the standard cell library, leaving only those entries active:
+define+FSDB
//../src/cic_filter.v
//../src/divider64.v
../icc/outputs/cic_filter_post_layout.v
../lib/verilog/smic18.v
../tb/tb_cic_filter.v
Enable the post_sim macro in the testbench by removing its comment, allowing SDF back-annotation of cell and wire delays. Then rerun the same three Makefile steps. The FSDB waveform now reflects the timing behavior of the placed-and-routed netlist.