• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

顺序模块中的位移失败,组合不成功。为什么?

verilog 来源:divB 4次浏览

我正在调试一段Verilog代码,特别是从FX2LP(Cypress CY7C68016A)USB控制器发送和接收字节。没有进入许多细节,数据在每个周期中按字节发送和传输。对于我的测试,我使用了一个16字节的缓冲区,我首先填充然后传回(回波测试)。顺序模块中的位移失败,组合不成功。为什么?

我的代码的显著部分看起来像:

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)中看不到任何竞态条件,两个版本都是相同的。

可能是什么原因?


===========解决方案如下:

首先你应该肯定发帖MVCE。这几乎是一个MVCE,但它不包含测试平台,省略号隐藏了可能相关的事情,例如从RX到TX的状态转换。

从来没有,因为它接近,我建立了一个小测试台,并添加了一些最低限度的代码让它运行。在我的情况下,它确实不是工作“完美的模拟”。实际上,正如@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卡没有类似的原因匹配的合成。代码看起来相当合成。几点建议:

  • 没有理由对Tx和Rx
  • 作为@serge独立的旗帜指出,会发生什么,如果他们发生冲突?这可能会模拟好,但不是工作在硬件。
  • 您可以使用一个标志并将其设置在每个状态的输出中。
  • 如果你需要不止一个条件,你必须有一个保证,只有一个路径可以修改其他每个非阻塞赋值给一个变种是活跃在任何时钟边沿:

    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的多次写入是非常宽容的(后者会“赢”)。

但综合工具必须将你的意图转化为注册表。根据逻辑的复杂程度,它可能无法知道两个标志不能同时为真。有时它会将这样的事情解释为dataBuf的两个并行“写入使能”条件,并创建两个并行寄存器。第二个副本在被设置为符合症状的8’h11之后可能从未被移出。完成后应检查实际输出电路以检测此类错误。不幸的是,并非所有这些都失败了,甚至没有给出明显的警告在Xilinx Vivado中,您可以拉出原理图。


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)