(* keep_hierarchy=“yes“ *)

       在 Verilog 中,(* keep_hierarchy="yes" *) 是一个 层次保留属性,用于指示综合工具保持模块的层次结构,不将其展平或优化到其他模块中。

一、作用与含义

这个属性强制要求工具:

  • 保持层次:防止模块边界被打破

  • 禁止展平:阻止模块被合并到父模块中

  • 独立优化:在每个模块内部独立进行优化

  • 便于调试:保持与原始RTL相同的层次结构

二、语法格式

// 用于模块定义
(* keep_hierarchy = "yes" *)
module my_module (...);

// 用于模块实例(某些工具)
(* keep_hierarchy = "yes" *)
module_name instance_name (...);

三、使用场景

1. 保护IP核和子模块

(* keep_hierarchy = "yes" *)
module dsp_multiplier (
    input [15:0] a,
    input [15:0] b,
    output [31:0] p
);
    // DSP48E1 或其他专用硬件的映射
    assign p = a * b;
endmodule

module top_design (
    input [15:0] data_a,
    input [15:0] data_b, 
    output [31:0] result
);

// 这个实例的层次结构会被保留
dsp_multiplier u_mult (
    .a(data_a),
    .b(data_b),
    .p(result)
);

endmodule

2. 保持功能模块的独立性

(* keep_hierarchy = "yes" *)
module fifo_controller (
    input clk,
    input rst_n,
    input wr_en,
    input rd_en,
    input [7:0] data_in,
    output [7:0] data_out,
    output full,
    output empty
);
    
    reg [7:0] mem [0:15];
    reg [3:0] wr_ptr, rd_ptr;
    reg [4:0] count;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
            count <= 0;
        end else begin
            // FIFO 控制逻辑...
        end
    end
    
    assign full = (count == 16);
    assign empty = (count == 0);
    
endmodule

3. 分层设计中的关键模块

(* keep_hierarchy = "yes" *)
module aes_encryption_round (
    input [127:0] data_in,
    input [127:0] round_key,
    output [127:0] data_out
);
    
    wire [127:0] sub_bytes_out;
    wire [127:0] shift_rows_out;
    wire [127:0] mix_columns_out;
    
    // AES 轮函数...
    sub_bytes u_sub (.data_in(data_in), .data_out(sub_bytes_out));
    shift_rows u_shift (.data_in(sub_bytes_out), .data_out(shift_rows_out));
    mix_columns u_mix (.data_in(shift_rows_out), .data_out(mix_columns_out));
    
    assign data_out = mix_columns_out ^ round_key;
    
endmodule

四、完整的实际示例

// 通信接收机分层设计
(* keep_hierarchy = "yes" *)
module synchronizer (
    input clk,
    input rst_n,
    input async_signal,
    output sync_signal
);
    
    reg sync_reg1, sync_reg2;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            sync_reg1 <= 1'b0;
            sync_reg2 <= 1'b0;
        end else begin
            sync_reg1 <= async_signal;
            sync_reg2 <= sync_reg1;
        end
    end
    
    assign sync_signal = sync_reg2;
    
endmodule

(* keep_hierarchy = "yes" *)
module deserializer (
    input clk,
    input serial_data,
    output [7:0] parallel_data
);
    
    reg [7:0] shift_reg;
    
    always @(posedge clk) begin
        shift_reg <= {shift_reg[6:0], serial_data};
    end
    
    assign parallel_data = shift_reg;
    
endmodule

module uart_receiver (
    input clk,
    input rst_n,
    input rx_data,
    output [7:0] received_data,
    output data_valid
);
    
    wire synchronized_rx;
    
    // 这些子模块的层次结构会被保留
    synchronizer u_sync (
        .clk(clk),
        .rst_n(rst_n),
        .async_signal(rx_data),
        .sync_signal(synchronized_rx)
    );
    
    deserializer u_deser (
        .clk(clk),
        .serial_data(synchronized_rx),
        .parallel_data(received_data)
    );
    
    // 其他控制逻辑...
    
endmodule

五、应用场景详解

1. 便于时序约束

(* keep_hierarchy = "yes" *)
module clock_domain_crossing (
    input src_clk,
    input dst_clk,
    input [31:0] src_data,
    output [31:0] dst_data
);
    
    // CDC 逻辑...
    // 保持层次便于添加跨时钟域约束
    
endmodule

2. 模块复用和团队协作

(* keep_hierarchy = "yes" *)
module eth_mac_controller (
    input clk_125m,
    input rst_n,
    input [7:0] tx_data,
    output [7:0] rx_data,
    // 其他以太网MAC接口...
);
    
    // 以太网MAC控制器实现
    // 保持层次便于在不同项目中复用
    
endmodule

3. 物理规划保留

(* keep_hierarchy = "yes" *)
module ddr_phy_interface (
    input mem_clk,
    input [63:0] write_data,
    output [63:0] read_data
);
    
    // DDR物理层接口
    // 保持层次便于物理布局规划
    
endmodule

六、相关属性对比

属性描述作用层次
keep_hierarchy="yes"保持模块层次结构模块级别
dont_touch="true"禁止优化逻辑模块、实例、信号级别
black_box="true"视为黑盒模块级别
buffer_type="none"禁止插入缓冲器端口级别

七、工具特定语法

1. Xilinx Vivado

(* keep_hierarchy = "yes" *)        // 推荐写法
(* keep_hierarchy = "soft" *)       // 软约束,允许在必要时展平
(* keep_hierarchy = "no" *)         // 允许展平(默认行为)

2. Synopsys Design Compiler

(* syn_hier = "hard" *)             // 硬层次保留
(* syn_hier = "soft" *)             // 软层次保留

八、多属性组合使用

(* keep_hierarchy = "yes", dont_touch = "true" *)
module critical_submodule (
    input clk,
    input [15:0] data_in,
    output [15:0] data_out
);
    // 既保持层次又禁止优化
    // ...
endmodule

九、注意事项

  1. 性能影响:过度使用可能影响综合优化效果

  2. 面积代价:可能阻止跨模块优化,增加资源使用

  3. 时序考虑:保持层次可能影响时序优化

  4. 调试优势:显著改善调试和分析的便利性

十、典型工作流程

// 1. 在关键模块定义时添加属性
(* keep_hierarchy = "yes" *)
module algorithm_core (...);

// 2. 综合时工具保持模块边界
// 3. 实现阶段维持层次结构
// 4. 便于模块级时序约束和物理规划

十一、实际工程应用

// 大型SoC设计中的层次保留
(* keep_hierarchy = "yes" *)
module cpu_core (
    input clk,
    input rst_n,
    input [31:0] instruction,
    output [31:0] result
);

(* keep_hierarchy = "yes" *)  
module dma_controller (
    input clk,
    input [31:0] src_addr,
    input [31:0] dst_addr
);

module soc_top (
    input system_clk,
    input system_rst_n
);
    
    cpu_core u_cpu (.clk(system_clk), .rst_n(system_rst_n), ...);
    dma_controller u_dma (.clk(system_clk), ...);
    // 其他模块...
    
endmodule

这个属性在以下情况下特别有用:

  • 大型分层设计项目

  • IP核集成和复用

  • 跨团队协作开发

  • 需要模块级时序约束的设计

  • 物理规划驱动的设计

  • 调试和分析复杂系统

为何需要如此复杂的Bitslip才能正常训练: `timescale 1ns / 1ps module BitSlipInLogic_8b #( parameter C_Function = "Slip", // Slip, Nmbr, Comp parameter C_ErrOut = 1, // 1 = ErrOut pin available. parameter C_InputReg = 0 // 0, No, 1 = Yes ) ( input wire [7:0] DataIn_pin, input wire Bitslip_pin, input wire [2:0] SlipVal_pin, input wire [7:0] CompVal_pin, input wire Ena_pin, input wire Rst_pin, input wire Clk_pin, output wire [7:0] DataOut_pin, output wire ErrOut_pin ); // Constants localparam Low = 1'b0; localparam High = 1'b1; // Signals reg [7:0] IntBitSlipPosition; reg IntFrstBitSlipPstn; reg [7:0] IntBitSlipData; wire [7:0] IntRankOne; reg [7:0] IntRankTwo; reg [7:0] IntRankTre; wire IntEnaReg; reg IntEnaReg_d; wire IntShftSlipReg; reg IntSlipPulse_d; reg IntShiftEna_d; wire IntSlipPulse; wire IntShiftEna; wire IntShftCntTc; wire IntShftCntEna; wire IntCompEqu; reg IntCompEqu_d; wire IntCompEqu_Rst; wire IntShftCntRst; wire [2:0] IntBitSlipCntOut; wire IntErrOut; wire IntErrOut_d; // Attributes (* KEEP_HIERARCHY = "YES" *) wire _unused_; // Extra front input register. // Adds one pipeline stage! generate if (C_InputReg == 1) begin : Gen_1_0 reg [7:0] IntRankOne_reg; always @(posedge Clk_pin or posedge Rst_pin) begin if (Rst_pin) IntRankOne_reg <= 8'b00000000; else if (Ena_pin) IntRankOne_reg <= DataIn_pin; end assign IntRankOne = IntRankOne_reg; end else begin : Gen_1_1 assign IntRankOne = DataIn_pin; end endgenerate // These are the bitslip registers. always @(posedge Clk_pin or posedge Rst_pin) begin if (Rst_pin) begin IntRankTwo <= 8'b00000000; IntRankTre <= 8'b00000000; end else begin if (Ena_pin) IntRankTwo <= IntRankOne; if (IntEnaReg) IntRankTre <= IntBitSlipData; end end assign DataOut_pin = IntRankTre; // Mux logic for bit slipping always @(*) begin case({Ena_pin, IntBitSlipPosition}) 9'b100000000: IntBitSlipData = IntRankOne[7:0]; 9'b100000001: IntBitSlipData = {IntRankOne[0], IntRankTwo[7:1]}; 9'b100000010: IntBitSlipData = {IntRankOne[1:0], IntRankTwo[7:2]}; 9'b100000100: IntBitSlipData = {IntRankOne[2:0], IntRankTwo[7:3]}; 9'b100001000: IntBitSlipData = {IntRankOne[3:0], IntRankTwo[7:4]}; 9'b100010000: IntBitSlipData = {IntRankOne[4:0], IntRankTwo[7:5]}; 9'b100100000: IntBitSlipData = {IntRankOne[5:0], IntRankTwo[7:6]}; 9'b101000000: IntBitSlipData = {IntRankOne[6:0], IntRankTwo[7]}; 9'b110000000: IntBitSlipData = IntRankOne[7:0]; default: IntBitSlipData = 8'b00000000; endcase end // This is the bitslip controller. // When the attribute is set to "Slip" the generated controller is simple. // When the attribute is set to "Nmbr" the controller is more complex. always @(posedge Clk_pin or posedge Rst_pin) begin if (Rst_pin) begin IntBitSlipPosition <= 8'b00000000; IntFrstBitSlipPstn <= 1'b0; end else if (Ena_pin) begin if (IntShftSlipReg && !IntFrstBitSlipPstn) IntBitSlipPosition <= {IntBitSlipPosition[6:0], ~IntBitSlipPosition[7]}; else if (IntShftSlipReg && IntFrstBitSlipPstn) IntBitSlipPosition <= {IntBitSlipPosition[6:0], IntBitSlipPosition[7]}; if (IntShftSlipReg) IntFrstBitSlipPstn <= High; end end // Function specific logic // "Slip" mode generate if (C_Function == "Slip") begin : Gen_3 assign IntShftSlipReg = Bitslip_pin; assign IntEnaReg = High; if (C_ErrOut == 0) begin : Gen_3_0 assign ErrOut_pin = Low; end else begin : Gen_3_1 // Got eight bitslips and the value is still not discovered. C3BCEtc C3BCEtc_inst ( .CntClk(Clk_pin), .CntRst(Rst_pin), .CntEna(Bitslip_pin), .CntOut(), .CntTc(IntErrOut) ); FDCE #(.INIT(1'b0)) FDCE_ErrCntTc ( .D(IntErrOut), .CE(Bitslip_pin), .C(Clk_pin), .CLR(Rst_pin), .Q(IntErrOut_d) ); GenPulse GenPulse_ErrCntTc ( .Clk(Clk_pin), .Ena(High), .SigIn(IntErrOut_d), .SigOut(ErrOut_pin) ); end end // "Nmbr" mode else if (C_Function == "Nmbr") begin : Gen_4 always @(posedge Clk_pin or posedge Rst_pin) begin if (Rst_pin) IntSlipPulse_d <= 1'b0; else if (Ena_pin) IntSlipPulse_d <= Bitslip_pin; end always @(posedge Clk_pin) begin if (Rst_pin || Bitslip_pin) IntEnaReg_d <= 1'b0; else if (IntShftCntTc) IntEnaReg_d <= High; end always @(posedge Clk_pin) begin if (IntShftCntTc || Rst_pin) IntShiftEna_d <= 1'b0; else if (IntSlipPulse) IntShiftEna_d <= High; end assign IntSlipPulse = ~Bitslip_pin & IntSlipPulse_d; assign IntShiftEna = IntShiftEna_d | IntSlipPulse; assign IntShftCntEna = IntShiftEna & Ena_pin; assign IntShftSlipReg = IntShiftEna; assign IntEnaReg = IntShftCntTc | IntEnaReg_d; if (C_ErrOut == 0) begin : Gen_4_1 assign ErrOut_pin = Low; end else begin : Gen_4_2 FDCE #(.INIT(1'b0)) FDCE_CntTc ( .D(IntShftCntTc), .CE(High), .C(Clk_pin), .CLR(Rst_pin), .Q(IntErrOut) ); assign ErrOut_pin = IntErrOut; end C3BCEtc_dwnld C3BCEtc_dwnld_inst ( .CntClk(Clk_pin), .CntRst(IntShftCntRst), .CntEna(IntShftCntEna), .CntLoad(Bitslip_pin), .CntLdVal(SlipVal_pin), .CntOut(IntBitSlipCntOut), .CntTc(IntShftCntTc) ); GenPulse GenPulse_inst ( .Clk(Clk_pin), .Ena(High), .SigIn(IntShftCntTc), .SigOut(IntShftCntRst) ); end // "Comp" mode else if (C_Function == "Comp") begin : Gen_5 assign IntShftSlipReg = Bitslip_pin; // Compare bit slipped data with the input data. assign IntCompEqu = (IntBitSlipData == CompVal_pin) ? 1'b1 : 1'b0; assign IntEnaReg = IntCompEqu | IntCompEqu_d; assign IntCompEqu_Rst = Rst_pin | Bitslip_pin; always @(posedge Clk_pin or posedge IntCompEqu_Rst) begin if (IntCompEqu_Rst) IntCompEqu_d <= 1'b0; else if (IntCompEqu) IntCompEqu_d <= High; end if (C_ErrOut == 0) begin : Gen_5_1 assign ErrOut_pin = Low; end else begin : Gen_5_2 FDCE #(.INIT(1'b0)) FDCE_ErrOut ( .D(IntCompEqu), .CE(High), .C(Clk_pin), .CLR(Rst_pin), .Q(ErrOut_pin) ); end end endgenerate endmodule // // Helper Modules - Required by BitSlipInLogic_8b // // C3BCEtc module - 3-bit binary counter with terminal count module C3BCEtc ( input wire CntClk, input wire CntRst, input wire CntEna, output wire [2:0] CntOut, output wire CntTc ); reg [2:0] count; always @(posedge CntClk or posedge CntRst) begin if (CntRst) count <= 3'b000; else if (CntEna) count <= count + 1'b1; end assign CntOut = count; assign CntTc = (count == 3'b111) & CntEna; endmodule // C3BCEtc_dwnld module - 3-bit binary counter with terminal count and load capability module C3BCEtc_dwnld ( input wire CntClk, input wire CntRst, input wire CntEna, input wire CntLoad, input wire [2:0] CntLdVal, output wire [2:0] CntOut, output wire CntTc ); reg [2:0] count; always @(posedge CntClk or posedge CntRst) begin if (CntRst) count <= 3'b000; else if (CntLoad) count <= CntLdVal; else if (CntEna) count <= count + 1'b1; end assign CntOut = count; assign CntTc = (count == 3'b111) & CntEna; endmodule // GenPulse module - Generates a single clock pulse module GenPulse ( input wire Clk, input wire Ena, input wire SigIn, output wire SigOut ); reg sig_d; always @(posedge Clk) begin if (Ena) sig_d <= SigIn; end assign SigOut = SigIn & ~sig_d & Ena; endmodule
最新发布
07-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值