gpt4 book ai didi

verilog - 为什么不将更改直接写到输出寄存器?

转载 作者:行者123 更新时间:2023-12-01 10:36:35 25 4
gpt4 key购买 nike

我是verilog的新手。我找到了这个pwm代码:

module pwm #(parameter CTR_LEN = 8) (
input clk,
input rst,
input [CTR_LEN - 1 : 0] compare,
output pwm
);

reg pwm_d, pwm_q;
reg [CTR_LEN - 1: 0] ctr_d, ctr_q;

assign pwm = pwm_q;

always @(*) begin
ctr_d = ctr_q + 1'b1;

if (compare > ctr_q)
pwm_d = 1'b1;
else
pwm_d = 1'b0;
end

always @(posedge clk) begin
if (rst) begin
ctr_q <= 1'b0;
end else begin
ctr_q <= ctr_d;
end

pwm_q <= pwm_d;
end

endmodule

(来源:Embeddedmicro.com)

我不明白为什么总是有两个街区。为什么寄存器要加倍?
为什么不只有一个计数器和pwm寄存器,只有posege块并直接操作这些寄存器?像那样:
module pwm #(parameter CTR_LEN = 8) (
input clk,
input rst,
input [CTR_LEN - 1 : 0] compare,
output pwm
);

reg pwm;
reg [CTR_LEN - 1: 0] ctr;

always @(posedge clk) begin
if (rst) begin
ctr = 1'b0;
end else begin
ctr = ctr + 1'b1;
end

if (compare > ctr)
pwm = 1'b1;
else
pwm = 1'b0;
end

endmodule

最佳答案

它是部分编码风格的偏爱,部分编码风格的最佳实践以及合成器如何优化的一些内容。
您可以将其写为一个始终阻止,如下所示(与您提供的内容不同):

module pwm #(parameter CTR_LEN = 8) (
input clk,
input rst,
input [CTR_LEN - 1 : 0] compare,
output reg pwm // Note the 'reg'
);

//reg pwm; // You cannot define pwm on separate lines as output and reg with ANSI style
reg [CTR_LEN - 1: 0] ctr;

always @(posedge clk) begin
if (rst) begin
ctr <= 1'b0; // use non-blocking ('<='), instead of blocking ('=')
end else begin
ctr <= ctr + 1'b1; // use non-blocking ('<='), instead of blocking ('=')
end

if (compare > ctr)
pwm <= 1'b1; // use non-blocking
else
pwm <= 1'b0; // use non-blocking
end

endmodule

最佳实践:
  • 使用非阻塞(<=)分配触发器和锁存器。
  • 这将删除Verilog仿真调度程序中的竞争条件,而不会影响综合。如果不使用非阻塞,则仿真和电路之间的功能行为可能会有所不同。非阻塞将立即进行评估,但是直到在同一戳记中完成所有操作后才应用新值。这意味着每次对触发器进行采样时,它将始终是不早于时钟的值,而不是新值。
  • 使用阻塞(=)分配组合逻辑。
  • 组合逻辑需要立即评估和更新。
  • 纯组合逻辑应与翻牌圈分开放置
  • 如果始终阻塞,则不完整的组合逻辑将转换为同步逻辑。这浪费了面积和失败,很难找到。
  • 如果两个总是块,则不完整的组合逻辑将推断出锁存器;通常是复杂的闩锁。闩锁不如触发器理想,但是,整理工具,综合工具和逻辑等效性检查工具通常会发出有关闩锁的警告。这些警告是查找意外推断的闩锁的一种方式。
    注意:SystemVerilog添加了关键字,以标识预期的组合逻辑(always_comb块)和预期的锁存器(always_latch块)。
  • 建议不要将具有重置/设置(特别是异步重置/设置)的触发器放在没有重置/设置的始终块中。
  • 一些合成器将使用相同的触发器类型,并且将设置/重置的时间设置为常数,这可能会浪费面积,因为该触发器通常更大。
  • 具有顺序逻辑(触发器)的模块的输出应为触发器。
  • 此规则与时间有关。预测模块中的组合延迟很容易。
    例如,assign pwm = (compare >= ctr);将为接收pwm作为输入的下游模块增加额外的延迟和噪声(在合成之后)。作为触发器,输出信号是干净的。

  • 一些设计人员将#3视为更高的纯度,并将翻牌圈的所有计算转移到组合块中。顺序块(始终带有时钟的块)被简化为简单的分配和复位(有时设置)逻辑。这样做的优点:
  • 对于大代码,这会减少代码的总行数。
  • 由于它们是独立的信号,因此允许查看触发器的当前值和下一个值。
  • 一些ASIC设计师发现,这种样式更容易将手动错误校正应用于硅掩膜。
  • 进行高级逻辑优化的合成器往往会在两个总是块结构的情况下产生更好的结果。在尝试满足时间调整大小要求时,这一点至关重要。

  • 唯一的缺点是小模块中多了几行。在典型项目中为统一编码风格付出的微不足道的价格。

    我更喜欢不直接将触发器分配给输出线(例如: assign pwm = pwm_q;)。我唯一想使用它的情况是它使连接更容易。准许作者保持 _d(翻牌输入) _q(翻牌输出)编码风格。我个人会用一个简单的 pwm(和 ctr)作为翻牌输出名称,并将 nextns作为后缀或前缀。但这仅仅是编码风格上的差异。

    电线输出方法确实具有一个优点。如果两个模块碰巧驱动 pwm,则在值冲突时会看到X。 As output reg X仅在父模块中可见。整理和综合都会为此警告或错误。这只是Verilog仿真中的视觉检查。

    如果您确实希望在仿真时保证一个驱动器输出一个触发器,那么最好启用SystemVerilog并使用 output logic pwm,并在 pwm块中分配 always_ff。如果其他任何块也在其中分配了受尊重的左侧值,则 always_ffalways_combalways_latch在编译/精化时会引发错误。

    关于verilog - 为什么不将更改直接写到输出寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34366297/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com