简体   繁体   English

顺序块中的移位失败,但组合中没有。 为什么?

[英]Bit shifting in sequential block fails, in combinational not. Why?

I am debugging a piece of Verilog code for days, particularly sending and receiving bytes from an FX2LP (Cypress CY7C68016A) USB controller. 我要调试几天的Verilog代码,尤其是从FX2LP(Cypress CY7C68016A)USB控制器发送和接收字节的过程。 Without going into many details, data is sent and transmitted byte-wise in each cycle. 无需赘述,数据在每个周期中按字节发送和传输。 For my test, I use a 16 byte buffer which I first fill and then transmit back (echo test). 对于我的测试,我使用一个16字节的缓冲区,该缓冲区首先填充然后传回(回声测试)。

The significant part of my code looks like: 我的代码的重要部分如下所示:

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

This code works perfectly in simulation (iVerilog). 该代码在模拟(iVerilog)中可完美运行。 But when synthesizing and executing on an Altera Cyclone, I get very strange errors. 但是当在Altera Cyclone上进行合成和执行时,我得到了非常奇怪的错误。 For example, most of the time the first byte transmitted to the FPGA is read for each byte. 例如,大多数情况下,每个字节都读取传输到FPGA的第一个字节。 For example, sending 11 22 33 44 55 66 ... would receive 11 11 11 11 11 11 ... . 例如,发送11 22 33 44 55 66 ...将接收11 11 11 11 11 11 ...

Now when I instead introduce a new variable: 现在,当我改为引入一个新变量时:

reg [127:0] nextDataBuf;

and replace the part in the sequential always @(posedge FIFO_CLK) block with: 并用以下命令替换顺序always @(posedge FIFO_CLK)块中的部分:

if(shiftBufRx) begin
    dataBuf <= nextDataBuf;
end
if(shiftBufTx) begin
    dataBuf <= nextDataBuf;
end

and in the combinational part: 在组合部分:

        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

Then it works! 然后就可以了!

That means: All I am doing is to move the shifting of the register from the sequential block to the combinational block. 这意味着:我要做的就是将寄存器的移位从顺序块移至组合块。

I do not see any race conditions in my code and in simulation (iVerilog) both versions are identical. 在我的代码和仿真(iVerilog)中,我看不到任何竞争条件,这两个版本是相同的。

What could be the reason? 可能是什么原因?

First of all you should definitely post a MVCE . 首先,您绝对应该发布MVCE This is almost an MVCE, but it doesn't contain a testbench and the ellipsis [...] obscures things that could be relevant like the state transitions from RX to TX. daccess-ods.un.org daccess-ods.un.org这几乎是一个MVCE,但是它不包含测试平台,并且省略号掩盖了可能相关的事情,例如从RX到TX的状态转换。

Never the less, as it was close, I built a small test bench and added some minimal code to get it running. 一直以来,我都建立了一个小型测试台,并添加了一些最少的代码来使其运行。 In my case it did NOT work "perfectly in simulation". 在我的情况下,它不能 “完全在模拟中”工作。 In fact, as @greg pointed out, there is a definite error in the shift register. 实际上,正如@greg指出的那样,移位寄存器中存在确定的错误。

In your before code, you are shifting left out of register, but are transmitting the low bytes. 在您的之前代码中,您将移出寄存器,但正在传输低字节。 The first cycle they will be 8'h11 and afterward will either be 8'h00 or stay the same, depending on when shiftBufTx is true, and this depends on logic that isn't posted. 它们的第一个周期为8'h11,之后为8'h00或保持不变,具体取决于shiftBufTx何时为真,这取决于未发布的逻辑。 There is enough posted to see that it cannot possibly work correctly as is. 有足够的帖子显示它可能无法正常工作。

    assign USB_DATAOUT = dataBuf[7:0];
    ...
    if(shiftBufTx) begin // cycle was a transmit
        dataBuf <= { dataBuf[127-8:0] , 8'h00 };
    end

In the after code, you are shifting right and this is why it works: 在后面的代码中,您正在向右移动,这就是它起作用的原因:

nextDataBuf = { 8'h00 , dataBuf[127:8] };

It is possible that the sim does not match synthesis for a similar reason. 由于类似原因,sim卡可能与合成不匹配。 The code looks fairly synthesizable. 该代码看起来可以合成。 Some suggestions: 一些建议:

  • There is no reason to have independent flags for Tx and Rx 没有理由为Tx和Rx设置独立的标志
  • As @serge pointed out, what happens if they conflict? 正如@serge指出的,如果它们发生冲突会怎样? This may sim okay but will not work in hardware. 这可能SIM卡还可以,但不会在硬件工作。
  • You could just use a single flag and set it in the output of each state. 您可以只使用一个标志并将其设置在每个状态的输出中。
  • If you need more than one condition, you must have an else that insures that only one path can modify each non-blocking assignment to a var is active at any clock edge: 如果您需要多个条件,则必须具有另一个条件,以确保只有一个路径可以修改每个无阻塞分配给var的值,该路径在任何时钟沿都处于活动状态:

     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 

Why did it appear to work in sim? 为什么它似乎在sim中工作? Beyond small typos or transpositions of supposedly identical code, the sim is very forgiving of multiple writes to the same var (the later will "win"). 除了一些小的错别字或本应相同代码的转置之外,sim卡还是非常宽容地对同一变量进行多次写入(后者会“获胜”)。

But the synthesis tool must intuit your intent into registers. 但是综合工具必须将您的意图引入寄存器。 Depending on how complex the logic is, it might not be able to know that both flags can't be true at the same time. 根据逻辑的复杂程度,它可能无法知道两个标志不能同时为真。 Sometimes it will interpret things like this as two parallel "write enable" conditions for dataBuf and create two parallel registers. 有时它将这样的事情解释为dataBuf的两个并行“写使能”条件,并创建两个并行寄存器。 The 2nd copy probably just never shifted back out after being set to 8'h11 which matches the symptoms. 将第二个副本设置为匹配症状的8'h11之后,可能再也不会移回该副本。 You should examine the actual output circuit after elaboration to detect this kind of error. 详细说明后,您应该检查实际的输出电路以检测这种错误。 Unfortunately not all of them fail or even give obvious warnings. 不幸的是,并非所有人都失败了,甚至没有给出明显的警告。 In Xilinx Vivado you can pull up the schematic. 在Xilinx Vivado中,您可以拉起原理图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Verilog中拆分顺序和组合 - How to split the sequential and the combinational in verilog 在verilog中增加计数器变量:组合或顺序 - Incrementing a counter variable in verilog: combinational or sequential 如何在组合块Verilog中提供1个时钟周期的延迟 - How to give a delay of 1 clock cycle in a combinational block verilog 在 Verilog 中对组合电路使用分配和始终块有什么区别? - What is the difference between using assign and always block for combinational circuit in Verilog? Always模块和组合模块中的总和结果之间的差异 - difference between the result of the sum in the always block and combinational module Verilog:顺序阻止时间 - Verilog: Sequential Block Time 在verilog中实例化顺序块的方法 - Method of instantiating sequential block in verilog 有人可以解释为什么这会导致组合反馈循环吗? (Vivado Verilog) - Can someone please explain why this causes a combinational feedback loop? (Vivado Verilog) 如何在组合Always块中为输出分配默认值,以便即使使用了不完整的if-else语句也不会推断出锁存器 - How to assign default values to outputs in a combinational always block so latches are not inferred even if incomplete if-else statements are used 使用加法和移位的 8 位顺序乘法器 - 8 bit sequential multiplier using add and shift
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM