2017-12-03 1 views
0

며칠 동안 Verilog 코드를 디버깅하고 있는데, 특히 FX2LP (Cypress CY7C68016A) USB 컨트롤러에서 바이트를 보내고받는 것이 중요합니다. 많은 세부 사항을 고려하지 않고도 데이터가 전송되어 각주기마다 바이트 단위로 전송됩니다. 내 테스트를 위해 필자가 먼저 채운 16 바이트 버퍼를 사용하여 다시 송신한다 (에코 테스트). 이 코드는 시뮬레이션 (iVerilog)에서 완벽하게 작동순차 블록에서 비트 시프트가 실패합니다. 왜?

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 

: 같은

내 코드의 상당 부분이 보인다. 그러나 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

Tx/Rx 플래그 간의 관계를 확인하십시오. 두 가지가 동시에 일어난다면 이상한 노래가 일어날 수 있습니다. – Serge

+0

데이터 구조가 일치하지 않습니다. '{dataBuf [127-8 : 0], 8'h00}'! ='{8'h00, dataBuf [127 : 8]}' – Greg

답변

0

먼저 MVCE을 게시해야합니다. 이것은 거의 MVCE이지만 테스트 벤치가 포함되어 있지 않고 줄임표 [...]는 RX에서 TX로 상태가 전환되는 것과 관련 될 수있는 사항을 모호하게 만듭니다.

적은 수의 테스트 벤치를 구축하고 실행하기 위해 최소한의 코드를 추가했습니다. 내 경우에는 이 아니며은 "완벽하게 시뮬레이션 중"으로 작동합니다. 사실 @greg이 지적했듯이 시프트 레지스터에는 확실한 오류가 있습니다.

이전 코드에서는 레지스터가 왼쪽으로 이동하지만 하위 바이트는 전송 중입니다. ShiftBufTx가 true 인 시점에 따라 8'h11 이후의 첫 번째 사이클이 8'h00이거나 동일하게 유지되며 이는 게시되지 않은 논리에 따라 달라집니다. 있는 그대로 제대로 작동하지 않을 수 있는지 확인하기에 충분합니다. 에서

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] }; 

심 비슷한 이유로 합성 일치하지 않을 가능성이 있습니다. 코드는 상당히 합성 가능합니다.제안 :

  • 지적 Tx 및 @serge으로 수신
  • 에 대한 독립적 인 플래그을 할 이유가 없습니다, 그들이 무엇을 충돌하면 어떻게됩니까? 이것은 괜찮을 수도 있지만 은 하드웨어가 아닌이 아닙니다.
  • 단일 플래그를 사용하여 각 상태의 출력에 설정할 수 있습니다.
  • 하나 이상의 조건이 필요하면, 당신은 단지 하나 경로를 수정할 수 있음을 보장 else가 있어야합니다 각각의 비 차단 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 
    

왜 시뮬레이션에서 작동하는 것으로 보입니까? 똑같은 코드의 작은 오타 또는 전치를 넘어서는 시뮬레이션은 같은 var에 여러 번 쓰기를 매우 용인합니다 (나중에 "이기게"됩니다).

그러나 합성 도구는 사용자의 의도를 레지스터로 이해해야합니다. 논리가 얼마나 복잡한 지에 따라 두 플래그가 동시에 참이 될 수 없다는 것을 알지 못할 수도 있습니다. 때로는 dataBuf에 대해 두 개의 병렬 "쓰기 가능"조건으로 해석하고 두 개의 병렬 레지스터를 생성합니다. 두 번째 사본은 아마도 증상과 일치하는 8'h11로 설정된 후에는 절대로 뒤로 이동하지 않았을 것입니다. 이러한 종류의 오류를 탐지하기 위해 정교한 후에 실제 출력 회로를 검사해야합니다. 불행히도 그들 모두가 실패하거나 명백한 경고를하지는 않습니다. Xilinx Vivado에서 회로도를 끌어 올 수 있습니다.

관련 문제