I am debugging a piece of Verilog code for days, particularly sending and receiving bytes from an FX2LP (Cypress CY7C68016A) USB controller. 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).
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). But when synthesizing and executing on an Altera Cyclone, I get very strange errors. For example, most of the time the first byte transmitted to the FPGA is read for each byte. For example, sending 11 22 33 44 55 66 ...
would receive 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:
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.
What could be the reason?