繁体   English   中英

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

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

我要调试几天的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 daccess-ods.un.org daccess-ods.un.org这几乎是一个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指出的,如果它们发生冲突会怎样? 这可能SIM卡还可以,但不会在硬件工作。
  • 您可以只使用一个标志并将其设置在每个状态的输出中。
  • 如果您需要多个条件,则必须具有另一个条件,以确保只有一个路径可以修改每个无阻塞分配给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 

为什么它似乎在sim中工作? 除了一些小的错别字或本应相同代码的转置之外,sim卡还是非常宽容地对同一变量进行多次写入(后者会“获胜”)。

但是综合工具必须将您的意图引入寄存器。 根据逻辑的复杂程度,它可能无法知道两个标志不能同时为真。 有时它将这样的事情解释为dataBuf的两个并行“写使能”条件,并创建两个并行寄存器。 将第二个副本设置为匹配症状的8'h11之后,可能再也不会移回该副本。 详细说明后,您应该检查实际的输出电路以检测这种错误。 不幸的是,并非所有人都失败了,甚至没有给出明显的警告。 在Xilinx Vivado中,您可以拉起原理图。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM