我是Verilog的新手,所以这个问题可能很愚蠢。
我在尝试:我有一个具有clk,8位输入和8位输出的组件。它应该做的是:
如果时钟事件是负边沿,则应将输出设置为0 如果时钟事件是正边沿,则应将输出设置为此时边缘事件的任何输入。在时钟的高电平阶段,无论输入如何变化,输出都不应改变。
到目前为止我尝试了什么:
always @(negedge clk)
_ledOut <= 0;
always @(posedge clk)
_ledOut[RowSize-1:0] <= ledIn[RowSize-1:0];
这告诉我,它无法解析net _ledOut的多个常量驱动程序。
然而,把它放在一个总是@(negedge clk,posedge clk)告诉我,它不能测试这两个条件。
所以我试着只创建一个@(clk)块然后使用if语句:
always @(clk) begin
if(clk == 0)
_ledOut <= 0;
else if(clk == 1)
_ledOut[RowSize-1:0] <= ledIn[RowSize-1:0];
end
但这并没有打开clk事件。在时钟的高阶段期间,它将_ledOut与ledIn链接,因此ledIn上的更改也会对_ledOut产生影响。我在这里做错了什么?
祝你好运, 迈克尔
答案 0 :(得分:5)
这告诉我,它无法解析net的多个常量驱动程序 _ledOut。
对于综合,您无法从多个始终块中分配reg类型。
然而,把它放在一个总是@(negedge clk,posedge clk)告诉我,它无法测试这两种情况。
这基本上描述了DDR寄存器。虽然许多FPGA器件具有这些,但它们通常无法合成。如果您确实需要此功能,Xilinx将使用ODDR2和IDDR2原语。
如果时钟事件是负边沿,则应将输出设置为0 If 时钟事件是正边沿,它应该将输出设置为任何值 输入是在边缘事件的这个时刻。在高阶段期间 时钟,输出不应改变,无论如何变化 输入
如果这就是你所需要的,那么你可以在输出端使用带有AND门的D触发器。触发器将在clk的每个上升沿采样ledIn,并且只要时钟为零,AND门将屏蔽输出。这并不理想,因为您通常不希望时钟接触非顺序逻辑,但避免这种情况可能意味着改变您的要求。
正如工具所示,您发布的代码将起作用,但您应该了解代码将合成到由clk控制的多路复用器。
答案 1 :(得分:1)
考虑以下刺激措施:
module tb;
parameter RowSize = 8;
reg clk;
reg [7:0] ledIn, _ledOut;
always @(clk) begin
if(clk == 0)
_ledOut <= 0;
else if(clk == 1)
_ledOut[RowSize-1:0] <= ledIn[RowSize-1:0];
end
initial begin
$monitor($time, " clk=%b ledIn=%h _ledOut=%h", clk, ledIn, _ledOut);
ledIn = 0;
#22 ledIn = 8'h55;
#20 $finish;
end
always begin
#5 clk <= 0;
#5 clk <= 1;
end
endmodule
它产生这个输出:
0 clk=x ledIn=00 _ledOut=xx 5 clk=0 ledIn=00 _ledOut=00 10 clk=1 ledIn=00 _ledOut=00 15 clk=0 ledIn=00 _ledOut=00 20 clk=1 ledIn=00 _ledOut=00 22 clk=1 ledIn=55 _ledOut=00 25 clk=0 ledIn=55 _ledOut=00 30 clk=1 ledIn=55 _ledOut=55 35 clk=0 ledIn=55 _ledOut=00 40 clk=1 ledIn=55 _ledOut=55
请注意,在时间22,当ledIn
发生变化时,_ledOut
输出不会发生变化。 _ledOut
仅在时间30的下一个clk
位置发生变化。因此,always @(clk)
解决方案正在执行您想要的操作:输出仅在时钟边缘发生变化,如您指定的那样。 / p>
答案 2 :(得分:1)
好的,这是我现在的工作解决方案。也许这不是你在那里看到的最好的verilog代码。 ;)然而,这是我用它做的第一件事,作为我大学的一个项目。所以只要它做我想做的事,这对我来说是一个巨大的成功! ;)
以下是我现在使用的代码,感谢Adam12:
parameter RowSize = 8;
input clk;
input [RowSize-1:0] ledIn;
output [RowSize-1:0] ledOut;
reg[RowSize-1:0] _ledOut;
assign ledOut = _ledOut & {RowSize{clk}};
always @(posedge clk) begin
_ledOut[RowSize-1:0] <= ledIn[RowSize-1:0];
end
答案 3 :(得分:0)
这是一个非常不寻常的问题,它使我建议您需要提供有关您实际想要实现的目标的更多信息,因为如果这是针对FPGA的话,则很可能会影响时序性能和时钟限制。已经提到了综合,但是您将把时钟门控输出馈入什么呢?如果是针垫,则应阅读设备规格中的DDR垫缓冲区,并推断出特定原语以驱动DDR信号。
如果您将此信号保留在芯片中,那么这是一个非常奇怪的要求。如果需要生成该波形,则可能会使用PLL以两倍于基频的频率生成锁相时钟,然后将门控数据放入该域中,并通过拨动开关应用桅杆,以便工具能够适当地分析时钟穿越,并且结果数据路径仍在单个边沿上有效过渡。
上面的答案推断一个带有强制输出的组合多路复用器的寄存器很有趣,但是无论将其输入什么,都必须处理尴尬的设置/保持条件,而且如果在片上,则只能采样一个边沿无论如何,所以这有点多余。