我在工作中继承了一些传统的VHDL,并一直在试图弄清楚问题 . 首先让我说我对Verilog更有经验但是已经花了一段时间用VHDL来解决这个问题 .
因此,我们的产品自2011年以来一直运行良好 . 但是,我们需要更改FPGA,因此我们正在移植代码 . 该代码的高级视图是FPGA在板载闪存中存储CPU的引导加载程序 . 上电时,CPU读取FPGA以提取引导加载程序 . 在我们的旧设计上它运作良好 . 在新设计中,它在寒冷时不起作用,在温暖的温度下也不是100%可靠 .
我注意到很多代码都完成了我认为奇怪的事情,其中触发器用信号而不是时钟来计时 . 一个例子:
process( N_RESET, DATA_READ, START_ADDRESS, END_ADDRESS )
begin
if( N_RESET = '0' ) then
ADDR_TMP <= START_ADDRESS;
elsif( DATA_READ'event and (DATA_READ='0') ) then
if( ADDR_TMP <= END_ADDRESS ) then
ADDR_TMP <= ADDR_TMP + "10";
incremented_tmp <= incremented_tmp xor '1';
end if;
end if;
end process;
因此,生成的RTL最终成为由DATA_READ计时的触发器 . 数据读取是来自CPU的读取使能信号 . CPU正在尝试读取该寄存器 .
这是一种有效的做事方式吗?我真的不喜欢自己使用读取启用作为时钟的想法 . 我在Verilog中写了一个使用时钟来检测DATA_READ的上升沿:
always@(posedge CLK, negedge RESETn )
begin
if(RESETn == 1'b0) begin
end else begin
last_usr_read_n <= usr_read;
// Next state logic, only transition on de-assertion of usr_read
if (last_usr_read_n == 1'd0 && usr_read == 1'd1) begin
// check next state logic
envm_internal_address <= envm_internal_address + 18'h2; // incrmeent address counter
incremented<= incremented^ 1'b1;
end
endmodule
我注意到在执行期间VHDL停止改变incremented_tmp,而我的verilog代码继续按预期执行 .
我们遇到的主要问题是设计在寒冷时不起作用 . 我不知道为什么 . 设计中有一堆闩锁,我已尽力去除 . 剩下的就是这样的代码(并且有很多代码) . 我的问题是:这是一个为触发器计时的有效方法吗?它会引起我们所看到的意外问题吗?
谢谢,尼克
2 回答
VHDL代码在DATA_READ信号上创建一个生成的时钟,与Verilog代码的等效代码不同 . 虽然这在某种意义上肯定是“有效的”,因为它是可综合的,如果不能正确约束,这可能会产生时间问题和边缘行为,就像你在寒冷和炎热时所看到的那样 . 首选解决方案是使用同步边沿检测电路替换生成的时钟,就像您在Verilog代码中所做的那样 .
不幸的是,如果您需要清理大量代码,我不知道自动执行此操作的好方法 . 如果代码遵循这些构造的相同通用结构,则可以尝试搜索和替换 . 我建议开发一个可靠的回归测试套件(如果还没有),以验证您的更改没有任何不受欢迎的副作用 .
或者,您可以尝试在布局布线工具中识别和约束所有生成的时钟,并注意在时钟域交叉处保持时间 . 特别是如果在同一时钟边沿上启动END_ADDRESS和DATA_READ,则需要通过添加延迟来解决信号之间的竞争条件 . 但是,如果您计划将来重用此代码,那么最好在RTL中修复它 .
代码是一团糟 - 转储它,重新开始 . 关于它的一切都是一面红旗 . 具体问题:
检查CPU数据表
DATA_READ
- 它's not usable as a clock if it'不保证单调 . 它可能只是保证了相对于其他信号的设置和保持,所以它可以在其他时间做任何想做的事情,可能为你的代码计时 .见TJ的回答 . 另请注意,如果原作者使用大量其他信号执行此操作,您的P&R软件可能没有将
DATA_READ
分配给时钟网,并且您的FPGA中的时钟网络已用完incremented_tmp
在时钟分支中分配,但不在异步重置分支中分配 . 这是在寻找麻烦 - 当N_RESET
为低并且's a clock edge, so you'已经有锁存行为时,它必须保持,并且N_RESET
的时序相对于DATA_READ
有问题 .