我正在调试一段Verilog代码,特别是从FX2LP(赛普拉斯CY7C68016A)USB控制器发送和接收字节。在不涉及许多细节的情况下,数据在每个周期中以字节方式发送和传输。对于我的测试,我使用一个16字节的缓冲区,我先填充然后再传回(echo test)。
我的代码的重要部分如下:
reg [127:0] dataBuf; // 16 byte buffer for USB data
reg [7:0] cntByte; // counter for number of bytes
reg [7:0] nextCntByte;
reg shiftBufRx, shiftBufTx; // flags whether buffer should be shifted
reg [7:0] currentByte; // current read byte
// in transmit cycle, byte is read from USB_DATAOUT
assign USB_DATAOUT = dataBuf[7:0];
always @(posedge FIFO_CLK) begin
// update state variables
CurrentState <= NextState;
cntByte <= nextCntByte;
if(shiftBufRx) begin // cycle was a receive
dataBuf <= { currentByte , dataBuf[127:8] };
end
if(shiftBufTx) begin // cycle was a transmit
dataBuf <= { dataBuf[127-8:0] , 8'h00 };
end
end
always @(*) begin
// avoid race conditions
NextState = CurrentState;
nextCntByte = cntByte;
nextDataBuf = dataBuf;
currentByte = 0;
shiftBufRx = 0;
shiftBufTx = 0;
case(CurrentState)
[...]
STATE_USBRX: begin
if(cntByte < 16) begin
nextCntByte = cntByte + 1;
currentByte = USB_DATAIN; // contains received byte in receive cycle
shiftBufRx = 1; // shift buffer after this cycle
end
[...]
end
STATE_USBTX: begin
if(cntByte < 15) begin
shiftBufTx = 1; // shift buffer after this cycle
nextCntByte = cntByte + 1;
end
[...]
end
[...]
endcase
end
此代码在模拟(iVerilog)中完美运行。但是当在Altera Cyclone上合成和执行时,我会得到非常奇怪的错误。例如,大多数时候,为每个字节读取发送到FPGA的第一个字节。例如,发送11 22 33 44 55 66 ...
即会收到11 11 11 11 11 11 ...
。
现在当我改为引入一个新变量时:
reg [127:0] nextDataBuf;
并将序列always @(posedge FIFO_CLK)
块中的部分替换为:
if(shiftBufRx) begin
dataBuf <= nextDataBuf;
end
if(shiftBufTx) begin
dataBuf <= nextDataBuf;
end
并在组合部分:
STATE_USBRX: begin
if(cntByte < 16) begin
nextCntByte = cntByte + 1;
//currentByte = FIFO_DATAIN;
nextDataBuf = { dataBuf[127-8:0] , FIFO_DATAIN };
shiftBufRx = 1;
end
[...]
end
STATE_USBTX: begin
if(cntByte < 15) begin
shiftBufTx = 1;
nextCntByte = cntByte + 1;
nextDataBuf = { 8'h00 , dataBuf[127:8] };
end
[...]
end
然后它有效!
这意味着:我所做的只是将寄存器从顺序块移位到组合块。
我在代码和模拟中看不到任何竞争条件(iVerilog)两个版本都是相同的。
可能是什么原因?
答案 0 :(得分:0)
首先,你应该发布一个MVCE。这几乎是一个MVCE,但它不包含一个测试平台,省略号[...]模糊了可能与从RX到TX的状态转换相关的事情。
从未如此接近,我建立了一个小型测试平台,并添加了一些最小的代码以使其运行。在我的情况下, NOT 在“模拟中完美地”工作。实际上,正如@greg指出的那样,移位寄存器中存在明确的错误。
在您之前的代码中,您正在向左移出寄存器,但正在传输低字节。第一个周期它们将是8'h11,之后将是8'h00或保持不变,具体取决于shiftBufTx何时为真,这取决于未发布的逻辑。有足够的帖子可以看到它不能正常工作。
assign USB_DATAOUT = dataBuf[7:0];
...
if(shiftBufTx) begin // cycle was a transmit
dataBuf <= { dataBuf[127-8:0] , 8'h00 };
end
在后面的代码中,您正在转移正确的,这就是它工作的原因:
nextDataBuf = { 8'h00 , dataBuf[127:8] };
由于类似的原因,sim可能与合成不匹配。代码看起来相当合成。一些建议:
如果您需要多个条件,则必须有一个else,以确保只有一个路径可以修改每个非阻塞分配,var在任何时钟边缘都是活动的:< / p>
if(shiftBufRx) begin // cycle was a receive
dataBuf <= { currentByte , dataBuf[127:8] };
end
**else** if(shiftBufTx) begin // cycle was a transmit
dataBuf <= **{ 8'h00 , dataBuf[127:8] }**;
end
为什么它似乎在sim中工作?除了小错别字或所谓相同代码的转置之外,sim非常宽容多次写入同一个var(后者将“win”)。
但是综合工具必须将你的意图插入寄存器。根据逻辑的复杂程度,它可能无法知道两个标志不能同时为真。有时它会将这样的事情解释为dataBuf的两个并行“写入启用”条件,并创建两个并行寄存器。第二个副本可能在设置为与症状匹配的8'h11之后从未移出。您应该在详细说明后检查实际输出电路以检测此类错误。不幸的是,并非所有这些都失败甚至发出明显的警告。在Xilinx Vivado中,您可以提取原理图。