目录
引言
知识储备
实际操作
设计源码
Vivado2018.3仿真
VCS2016仿真
Tcl脚本
约束脚本 MY_TOP.tcl
运行脚本 RUN.tcl
本篇继续学习 DC的基本使用。本篇主要学习 DC 需要的环境约束。
前文链接:
Design Compiler工具学习笔记(1)
Design Compiler工具学习笔记(2)
Design Compiler工具学习笔记(3)
此处做一个简单的运算模块,实现 (A+B)*C-D
其中,A、B、C、D的位宽可变
子模块源码:
// ================== calculate A & B module ========================== // Date:2022-11-20 // By:Xu Y. B. // Description: // FNUC == 0 : A+B; // FUNC == 1 : A-B; // FUNC == 2 : A*B; // ===================================================================== module CAL_FUNC_MDL #(// ======================= module parameters specify =================== parameter P_DATA_A_WIDTH = 8, parameter P_DATA_B_WIDTH = 4 )( // ======================= module iuput ports specify ================== input I_CLK_100M, input I_RSTN, input [P_DATA_A_WIDTH-1:0] I_DATA_A, input [P_DATA_B_WIDTH-1:0] I_DATA_B, input I_DATA_A_VAL, input I_DATA_B_VAL, input [1:0] I_FUNC,// ======================= module output ports specify ================= output [P_DATA_A_WIDTH+P_DATA_B_WIDTH-1:0] O_CAL_RES, output O_CAL_RES_VAL);// ======================= module local parameters ===================== localparam LP_ADD_SUB_RES_WIDTH = MAX(P_DATA_B_WIDTH,P_DATA_A_WIDTH) + 1; localparam LP_MULT_RES_WIDTH = P_DATA_A_WIDTH+P_DATA_B_WIDTH;// ======================= module internal signals ===================== reg [LP_ADD_SUB_RES_WIDTH-1:0] R_ADD_SUB_RES; reg [LP_MULT_RES_WIDTH-1:0] R_MULT_RES; reg R_CAL_RES_VAL;reg [1:0] R_FUNC;// ======================= module logic ================================ always @ (posedge I_CLK_100M) begin:cal if(~I_RSTN)beginR_ADD_SUB_RES <= {(LP_ADD_SUB_RES_WIDTH){1'b0}};R_MULT_RES <= {(LP_MULT_RES_WIDTH){1'b0}};R_CAL_RES_VAL <= 1'b0;endelsebeginif(I_DATA_A_VAL & I_DATA_B_VAL)begincase (I_FUNC)0:beginR_ADD_SUB_RES <= {{(LP_ADD_SUB_RES_WIDTH-P_DATA_A_WIDTH){I_DATA_A[P_DATA_A_WIDTH-1]}},I_DATA_A} + {{(LP_ADD_SUB_RES_WIDTH-P_DATA_B_WIDTH){I_DATA_B[P_DATA_B_WIDTH-1]}},I_DATA_B};R_MULT_RES <= {(LP_MULT_RES_WIDTH){1'b0}};R_CAL_RES_VAL <= 1'b1;end1:beginR_ADD_SUB_RES <= {{(LP_ADD_SUB_RES_WIDTH-P_DATA_A_WIDTH){I_DATA_A[P_DATA_A_WIDTH-1]}},I_DATA_A} - {{(LP_ADD_SUB_RES_WIDTH-P_DATA_B_WIDTH){I_DATA_B[P_DATA_B_WIDTH-1]}},I_DATA_B};R_MULT_RES <= {(LP_MULT_RES_WIDTH){1'b0}};R_CAL_RES_VAL <= 1'b1;end2:beginR_ADD_SUB_RES <= {(LP_ADD_SUB_RES_WIDTH){1'b0}};R_MULT_RES <= {{(P_DATA_B_WIDTH){I_DATA_A[P_DATA_A_WIDTH-1]}},I_DATA_A} * {{(P_DATA_A_WIDTH){I_DATA_B[P_DATA_B_WIDTH-1]}},I_DATA_B};R_CAL_RES_VAL <= 1'b1;enddefault : beginR_ADD_SUB_RES <= {{(LP_ADD_SUB_RES_WIDTH-P_DATA_A_WIDTH){I_DATA_A[P_DATA_A_WIDTH-1]}},I_DATA_A} + {{(LP_ADD_SUB_RES_WIDTH-P_DATA_B_WIDTH){I_DATA_B[P_DATA_B_WIDTH-1]}},I_DATA_B};R_MULT_RES <= {(LP_MULT_RES_WIDTH){1'b0}};R_CAL_RES_VAL <= 1'b1;endendcaseendelsebeginR_ADD_SUB_RES <= {(LP_ADD_SUB_RES_WIDTH){1'b0}};R_MULT_RES <= {(LP_MULT_RES_WIDTH){1'b0}};R_CAL_RES_VAL <= 1'b0; endend endalways @ (posedge I_CLK_100M) begin:beatif(~I_RSTN)beginR_FUNC <= 2'd0;endelsebeginR_FUNC <= I_FUNC;end endassign O_CAL_RES_VAL = R_CAL_RES_VAL; assign O_CAL_RES = (R_FUNC < 2) ? {{(LP_MULT_RES_WIDTH-LP_ADD_SUB_RES_WIDTH){R_ADD_SUB_RES[LP_ADD_SUB_RES_WIDTH-1]}},R_ADD_SUB_RES}: R_MULT_RES;// function define function integer MAX;input integer A, B;beginif(A>=B)beginMAX = A;endelsebeginMAX = B;endend endfunction endmodule
顶层文件:
// ================== TOP module ========================== // Date:2022-11-20 // By:Xu Y. B. // Description: // (A+B)*C-D // =========================================================module TOP #( // ======================= module parameters specify =================== parameter P_DATA_A_WIDTH = 2, parameter P_DATA_B_WIDTH = 4, parameter P_DATA_C_WIDTH = 5, parameter P_DATA_D_WIDTH = 8 )( // ======================= module iuput ports specify ================== input I_CLK_100M, // clock input I_RSTN, // synchronous reset active lowinput [P_DATA_A_WIDTH-1:0] I_DATA_A, input [P_DATA_B_WIDTH-1:0] I_DATA_B, input [P_DATA_C_WIDTH-1:0] I_DATA_C, input [P_DATA_D_WIDTH-1:0] I_DATA_D,input I_DATA_VAL,// ======================= module output ports specify ================= output [MAX(MAX(P_DATA_A_WIDTH,P_DATA_B_WIDTH)+1+P_DATA_C_WIDTH,P_DATA_D_WIDTH):0] O_CAL_RES, output O_CAL_RES_VAL ); // ======================= module local parameters ===================== localparam LP_ADD_RES_WIDTH = MAX(P_DATA_A_WIDTH,P_DATA_B_WIDTH)+1; localparam LP_MULT_RES_WIDTH = LP_ADD_RES_WIDTH + P_DATA_C_WIDTH; localparam LP_SUB_RES_WIDTH = MAX(LP_MULT_RES_WIDTH,P_DATA_D_WIDTH)+1; // ======================= module internal signals ===================== wire [LP_ADD_RES_WIDTH-1:0] W_ADD_RES; wire W_ADD_RES_VAL; wire [LP_MULT_RES_WIDTH-1:0] W_MULT_RES; wire W_MULT_RES_VAL; wire [LP_SUB_RES_WIDTH-1:0] W_SUB_RES; wire W_SUB_RES_VAL;reg [P_DATA_C_WIDTH-1:0] R_DATA_C; reg R_DATA_C_VAL;reg [P_DATA_D_WIDTH-1:0] R_DATA_D[1:0]; reg [1:0] R_DATA_D_VAL; // ======================= module logic ================================// instantiate module // ADD CAL_FUNC_MDL #(.P_DATA_A_WIDTH(P_DATA_A_WIDTH),.P_DATA_B_WIDTH(P_DATA_B_WIDTH)) INST_CAL_FUNC_MDL_ADD (.I_CLK_100M (I_CLK_100M),.I_RSTN (I_RSTN),.I_DATA_A (I_DATA_A),.I_DATA_B (I_DATA_B),.I_DATA_A_VAL (I_DATA_VAL),.I_DATA_B_VAL (I_DATA_VAL),.I_FUNC (2'd0),.O_CAL_RES (W_ADD_RES),.O_CAL_RES_VAL (W_ADD_RES_VAL)); // MULT always @ (posedge I_CLK_100M) begin:delay_cif(~I_RSTN)beginR_DATA_C_VAL <= 0;R_DATA_C <= 0;endelsebeginR_DATA_C <= I_DATA_C;R_DATA_C_VAL <= I_DATA_VAL;end end CAL_FUNC_MDL #(.P_DATA_A_WIDTH(LP_ADD_RES_WIDTH),.P_DATA_B_WIDTH(P_DATA_C_WIDTH)) INST_CAL_FUNC_MDL_MULT (.I_CLK_100M (I_CLK_100M),.I_RSTN (I_RSTN),.I_DATA_A (W_ADD_RES),.I_DATA_B (R_DATA_C),.I_DATA_A_VAL (W_ADD_RES_VAL),.I_DATA_B_VAL (R_DATA_C_VAL),.I_FUNC (2'd2),.O_CAL_RES (W_MULT_RES),.O_CAL_RES_VAL (W_MULT_RES_VAL));// SUB always @ (posedge I_CLK_100M) begin:delay_dif(~I_RSTN)beginR_DATA_D_VAL <= 2'b00;R_DATA_D[0] <= 0;R_DATA_D[1] <= 0;endelsebeginR_DATA_D_VAL[0] <= I_DATA_VAL;R_DATA_D_VAL[1] <= R_DATA_D_VAL[0];R_DATA_D[0] <= I_DATA_D;R_DATA_D[1] <= R_DATA_D[0];end end CAL_FUNC_MDL #(.P_DATA_A_WIDTH(LP_MULT_RES_WIDTH),.P_DATA_B_WIDTH(P_DATA_D_WIDTH)) INST_CAL_FUNC_MDL_SUB (.I_CLK_100M (I_CLK_100M),.I_RSTN (I_RSTN),.I_DATA_A (W_MULT_RES),.I_DATA_B (R_DATA_D[1]),.I_DATA_A_VAL (W_MULT_RES_VAL),.I_DATA_B_VAL (R_DATA_D_VAL[1]),.I_FUNC (2'd1),.O_CAL_RES (W_SUB_RES),.O_CAL_RES_VAL (W_SUB_RES_VAL));assign O_CAL_RES = W_SUB_RES; assign O_CAL_RES_VAL = W_SUB_RES_VAL;// function define function integer MAX;input integer A, B;beginif(A>=B)beginMAX = A;endelsebeginMAX = B;endend endfunctionendmodule
仿真文件:
// ================== calculate A & B module TestBench================= // Date:2022-11-20 // By:Xu Y. B. // Description: // FNUC == 0 : A+B; // FUNC == 1 : A-B; // FUNC == 2 : A*B; // ===================================================================== module TB ();// ======================= module parameters specify =================== localparam P_DATA_A_WIDTH = 2; localparam P_DATA_B_WIDTH = 4; localparam P_DATA_C_WIDTH = 5; localparam P_DATA_D_WIDTH = 8;// ======================= module iuput ports specify ================== reg I_CLK_100M; // clock reg I_RSTN; // synchronous reset active lowreg [P_DATA_A_WIDTH-1:0] I_DATA_A; reg [P_DATA_B_WIDTH-1:0] I_DATA_B; reg [P_DATA_C_WIDTH-1:0] I_DATA_C; reg [P_DATA_D_WIDTH-1:0] I_DATA_D;reg I_DATA_VAL;// ======================= module output ports specify ================= wire [MAX(MAX(P_DATA_A_WIDTH,P_DATA_B_WIDTH)+1+P_DATA_C_WIDTH,P_DATA_D_WIDTH):0] O_CAL_RES; wire O_CAL_RES_VAL ;// ======================= generate clock ============================== initial I_CLK_100M = 0; always #5 I_CLK_100M = ~I_CLK_100M;initial beginI_RSTN = 1'b0;I_DATA_A <= 0;I_DATA_B <= 0;I_DATA_C <= 0;I_DATA_D <= 0;I_DATA_VAL = 0;#20;I_RSTN = 1;#10;@(posedge I_CLK_100M)I_DATA_A = 2'd1;I_DATA_B = -4'd6;I_DATA_C = -5'd2;I_DATA_D = 8'd100;I_DATA_VAL <= 1; @(posedge I_CLK_100M)I_DATA_VAL <= 0;I_DATA_A <= 0;I_DATA_B <= 0;I_DATA_C <= 0;I_DATA_D <= 0;#10;@(posedge I_CLK_100M)I_DATA_A = -2'd1;I_DATA_B = 4'd6;I_DATA_C = -5'd2;I_DATA_D = 8'd66;I_DATA_VAL <= 1;@(posedge I_CLK_100M)I_DATA_VAL <= 0;I_DATA_A <= 0;I_DATA_B <= 0;I_DATA_C <= 0;I_DATA_D <= 0;@(negedge O_CAL_RES_VAL)#50;$display("TB END",`__FILE__,`__LINE__);$finish;endinitial begin`ifdef VPD_TEST$vcdpluson();`endif endTOP #(.P_DATA_A_WIDTH(P_DATA_A_WIDTH),.P_DATA_B_WIDTH(P_DATA_B_WIDTH),.P_DATA_C_WIDTH(P_DATA_C_WIDTH),.P_DATA_D_WIDTH(P_DATA_D_WIDTH)) INST_TOP (.I_CLK_100M (I_CLK_100M),.I_RSTN (I_RSTN),.I_DATA_A (I_DATA_A),.I_DATA_B (I_DATA_B),.I_DATA_C (I_DATA_C),.I_DATA_D (I_DATA_D),.I_DATA_VAL (I_DATA_VAL),.O_CAL_RES (O_CAL_RES),.O_CAL_RES_VAL (O_CAL_RES_VAL));// function define function integer MAX;input integer A, B;beginif(A>=B)beginMAX = A;endelsebeginMAX = B;endend endfunctionendmodule
刚好复习一下 前段时间学习的 VCS使用。不了解的可以看本专栏前面关于 VCS 的文章:
Synosys Toolhttps://blog.csdn.net/qq_43045275/category_12082114.html?spm=1001.2014.3001.5482
仅供参考~~~
# |=========================================================== # | Author : Xu Y. B. # | Date : 2022-11-21 # | Description : tcl script for top design # |===========================================================# |=========================================================== # |STEP 1: Read & elaborate the RTL design file list & check # |=========================================================== set TOP_MODULE TOP analyze -format verilog [list TOP.v CAL_FUNC_MDL.v] elaborate $TOP_MODULE -architecture verilog current_design $TOP_MODULEif {[link] == 0} {echo "Your Link has errors !";exit; }if {[check_design] == 0} {echo "Your check design has errors !";exit; }# |=========================================================== # |STEP 2: reset design # |=========================================================== reset_design# |=========================================================== # |STEP 3: Write unmapped ddc file # |=========================================================== uniquify set uniquify_naming_style "%s_%d" write -f ddc -hierarchy -output ${UNMAPPED_PATH}/${TOP_MODULE}.ddc# |=========================================================== # |STEP 4: define clocks # |=========================================================== set CLK_NAME I_CLK_100M set CLK_PERIOD 10 set CLK_SKEW [expr {$CLK_PERIOD*0.05}] set CLK_TRANS [expr {$CLK_PERIOD*0.01}] set CLK_SRC_LATENCY [expr {$CLK_PERIOD*0.1 }] set CLK_LATENCY [expr {$CLK_PERIOD*0.1 }] create_clock -period $CLK_PERIOD [get_ports $CLK_NAME] set_ideal_network [get_ports $CLK_NAME] set_dont_touch_network [get_ports $CLK_NAME] set_drive 0 [get_ports $CLK_NAME]set_clock_uncertainty -setup $CLK_SKEW [get_clocks $CLK_NAME] set_clock_transition -max $CLK_TRANS [get_clocks $CLK_NAME] set_clock_latency -source -max $CLK_SRC_LATENCY [get_clocks $CLK_NAME] set_clock_latency -max $CLK_LATENCY [get_clocks $CLK_NAME]# |=========================================================== # |STEP 5: define reset # |=========================================================== set RST_NAME I_RSTN set_ideal_network [get_ports $RST_NAME] set_dont_touch_network [get_ports $RST_NAME] set_drive 0 [get_ports $RST_NAME]# |=========================================================== # |STEP 6: set input delay using timing budget # |Assume a weak cell to drive the input pins # |=========================================================== set LIB_NAME typical set WIRE_LOAD_MODEL smic18_wl10 set DRIVE_CELL INVX1 set DRIVE_PIN Y set OPERATE_CONDITION typicalset ALL_INPUT_EXCEPT_CLK [remove_from_collection [all_inputs] [get_ports "$CLK_NAME"]] set INPUT_DELAY [expr {$CLK_PERIOD*0.6}]set_input_delay $INPUT_DELAY -clock $CLK_NAME $ALL_INPUT_EXCEPT_CLK # set_input_delay -min 0 -clock $CLK_NAME $ALL_INPUT_EXCEPT_CLK set_driving_cell -lib_cell ${DRIVE_CELL} -pin ${DRIVE_PIN} $ALL_INPUT_EXCEPT_CLK# |=========================================================== # |STEP 7: set output delay # |=========================================================== set output_DELAY [expr {$CLK_PERIOD*0.6}] set MAX_LOAD [expr {[load_of $LIB_NAME/INVX8/A] * 10}]set_output_delay $output_DELAY -clock $CLK_NAME [all_outputs] set_load [expr {$MAX_LOAD * 3}] [all_outputs] set_isolate_ports -type buffer [all_outputs]# |=========================================================== # |STEP 8: set max delay for comb logic # |=========================================================== # set_input_delay [expr $CLK_PERIOD * 0.1] -clock $CLK_NAME -add_delay [get_ports I_1] # set_output_delay [expr $CLK_PERIOD * 0.1] -clock $CLK_NAME -add_delay [get_ports O_1]# |=========================================================== # |STEP 9: set operating condition & wire load model # |=========================================================== set_operating_conditions -max $OPERATE_CONDITION \-max_library $LIB_NAMEset auto_wire_load_selection false set_wire_load_mode top set_wire_load_model -name $WIRE_LOAD_MODEL \-library $LIB_NAME# |=========================================================== # |STEP 10: set area constraint (Let DC try its best) # |===========================================================set_max_area 0# |=========================================================== # |STEP 11: set DRC constraint # |=========================================================== # set MAX_CAPACITANCE [expr {[load_of $LIB_NAME/NAND4X2/Y] * 5}] # set_max_capacitance $MAX_CAPACITANCE $ALL_INPUT_EXCEPT_CLK# |=========================================================== # |STEP 12: set group path # |Avoid getting stack on one path # |=========================================================== # group_path -name $CLK_NAME -weight 5 \ # -critical_range [expr {$CLK_PERIOD * 0.1}] # group_path -name INPUTS -from [all_inputs] \ # -critical_range [expr {$CLK_PERIOD * 0.1}] # group_path -name $CLK_NAME -to [all_outputs] \ # -critical_range [expr {$CLK_PERIOD * 0.1}] # group_path -name $CLK_NAME -from [all_inputs] \ # -to [all_outputs] \ # -critical_range [expr {$CLK_PERIOD * 0.1}]
# source MY_TOP.tcl and print the process to terminal & run.log redirect -tee -file ${WORK_PATH}/run.log {source -echo -verbose MY_TOP.tcl}
运行约束脚本,并将信息存放于log文件中。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~