目录
引言
知识储备
实际操作
设计源码
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) begin R_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; end else begin if(I_DATA_A_VAL & I_DATA_B_VAL) begin case (I_FUNC) 0: begin R_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; end 1: begin R_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; end 2: begin R_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; end default : begin R_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; end endcase end else begin R_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; end end end always @ (posedge I_CLK_100M) begin:beat if(~I_RSTN) begin R_FUNC <= 2'd0; end else begin R_FUNC <= I_FUNC; end end assign 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; begin if(A>=B) begin MAX = A; end else begin MAX = B; end end 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 low input [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_c if(~I_RSTN) begin R_DATA_C_VAL <= 0; R_DATA_C <= 0; end else begin R_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_d if(~I_RSTN) begin R_DATA_D_VAL <= 2'b00; R_DATA_D[0] <= 0; R_DATA_D[1] <= 0; end else begin R_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; begin if(A>=B) begin MAX = A; end else begin MAX = B; end end endfunction endmodule
仿真文件:
// ================== 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 low reg [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 begin I_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; end initial begin `ifdef VPD_TEST $vcdpluson(); `endif end TOP #( .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; begin if(A>=B) begin MAX = A; end else begin MAX = B; end end endfunction endmodule
Vivado2018.3仿真
VCS2016仿真
刚好复习一下 前段时间学习的 VCS使用。不了解的可以看本专栏前面关于 VCS 的文章:
Synosys Toolhttps://blog.csdn.net/qq_43045275/category_12082114.html?spm=1001.2014.3001.5482
Tcl脚本
仅供参考~~~
约束脚本 MY_TOP.tcl
# |=========================================================== # | 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_MODULE if {[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 typical set 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_NAME set 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}]
运行脚本 RUN.tcl
# 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文件中。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~