2015-01-23 2 views
0

비동기 FIFO 버퍼를 작성했지만 실행하면 출력 포트에 XXX가 표시됩니다. 나는 리셋 신호가 작동하도록해야한다고 말한 SO에 관한 우려되는 질문을 언급했다. 그러나 리셋 신호가 작동하더라도 여전히 동일한 문제에 직면하고있다.XXX 출력 포트에

도움이 될 것입니다. 감사 여기서

module fifo 
    #(parameter width =8, 
          addr_width = 4, 
          depth = (1 << addr_width) 
    ) 
    (// Read port 
     output [width - 1:0] dout, 
     output reg     empty_out, 
     input wire     rd_en, 
     input wire    rclk, 
     //write port 
     input wire [width-1:0] din, 
     output reg     full, 
     input wire     wr_en, 
     input wire     wclk, 

     input wire     rst 
); 

(* ram_style = "bram" *) 
reg [width-1:0] memory_s[depth-1:0]; 
reg [31:0] push_ptr; 
reg [31:0] pop_ptr; 

assign dout = memory_s[pop_ptr]; // assign cannot assign values to registers 
always @(posedge wclk) 
    begin 
     if (rst == 1) 
      push_ptr <= 0; 
     else if(wr_en == 1) 
      begin 
       memory_s\[push_ptr\] <= din; 
       //$display("w: %d", push_ptr); 
      if (push_ptr == (depth -1)) 
        push_ptr <= 0; 
      else 
       push_ptr <= push_ptr + 1; 
     end 
    end 

always @ (posedge rclk) 
    if (rst == 1) 
     pop_ptr <= 0; 
    else if (rd_en ==1) 
     begin 
       //dout <= memory_s\[pop_ptr\]; 
       //$display("r: %d", pop_ptr); 
      if (pop_ptr == depth-1) 
       pop_ptr <=0; 
      else 
       pop_ptr <= pop_ptr+1; 
     end 

reg full_s; 
reg overflow; 

always @* 
begin 
     if (rst == 1) 
      full_s <= 0; 
     else if (push_ptr <= pop_ptr) 
      if (push_ptr + 1 == pop_ptr) 
       begin 
       full_s <= 1; 
       $display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s); 
       end 
      else 
       full_s <=0; 
     else 
      if(push_ptr + 1 == pop_ptr + depth) 
       begin 
       full_s <= 1; 
       $display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s); 
       end 
      else 
       full_s <= 0; 

     end 
endmodule] 

는 파형이다

waveform
(external link)

라이트 테스트 벤치 fifoTb 모듈; 당신의 테스트 벤치를 만드는

assign dout = (rd_en) ? memory_s[pop_ptr] : 0; 

추가 팁 :

// Inputs 
reg rd_en; 
reg rclk; 
reg [7:0] din; 
reg wr_en; 
reg wclk; 
reg rst; 

// Outputs 
wire[7:0] dout; 
wire empty_out; 
wire full; 

// Instantiate the Unit Under Test (UUT) 
fifo uut (
    .dout(dout), 
    .empty_out(empty_out), 
    .rd_en(rd_en), 
    .rclk(rclk), 
    .din(din), 
    .full(full), 
    .wr_en(wr_en), 
    .wclk(wclk), 
    .rst(rst) 
); 
initial begin 
    // Initialize Inputs 
    rd_en = 0; 
    rclk = 0; 

    wr_en = 0; 
    wclk = 0; 
    rst = 1; 
    din = 8'h0; 
    // Wait 100 ns for global reset to finish 
    #100; 
    rst = 0; 
    wr_en = 1; 
    din = 8'h1; 
    #101 din = 8'h2; 
    rd_en = 1; 
    // Add stimulus here 

end 

always begin #10 wclk = ~wclk; end 

always begin #10 rclk = ~rclk; end 
endmodule 
+0

재설정이 포함 된 조합 블록에는 코드가 이상하게 보입니다. 일반적으로 재설정은 조합 블록에 포함되지 않습니다. – e19293001

+0

게시판에 테스트 벤치를 포함시키지 않았으므로'memory_s '에 초기화 된 값이 없다고 가정합니다. 따라서'memory_s '는'bx 값 '을 출력합니다. 'wr_en'을 먼저 선언하고 ('memory_s'에 값을 쓰십시오)'rd_en'을 ('memory_s'에 쓰여진 값을 읽으려면) 어서 트하십시오. – e19293001

+0

안녕하세요, 답장을 보내 주셔서 감사합니다. 내 테스트 벤치를 추가했습니다. –

답변

1

나는 memory_s이 초기 값 'bxxx의이 있기 때문에 'bxxx 값을 갖는 피하기 위해 당신의 출력 dout 신호 에 추가 로직을 추가 제안 :

먼저, 기기가 작동합니다.

쓰기 작업 wr_en이 높은 경우, 두 가지 작업이

always @(posedge wclk) 
    begin 
    if (rst == 1) 
     push_ptr <= 0; 
    else if(wr_en == 1) 
     begin 
      memory_s[push_ptr] <= din; 
      if (push_ptr == (depth -1)) 
      push_ptr <= 0; 
      else 
      push_ptr <= push_ptr + 1; 
     end 
    end 

을 수행됩니다 : 당신의 RTL 코드를 읽고시

, 나는 당신의 FIFO가 다음과 같은 방식으로 작동한다는 결론을 내렸다.

  1. din의 값은 wclk의 다음 양의 에지에 push_ptr 가리키는 memory_s에 기록한다. push_ptr(depth -1)와 같으면
  2. 0는 다른 push_ptr 대신 1 씩 증가 레지스터에 레지스터 push_ptr를 기록한다.

    wr_en이 낮 으면 쓰기 작업이 수행되지 않습니다.

판독 동작

assign dout = memory_s[pop_ptr]; 

always @ (posedge rclk) 
    if (rst == 1) 
    pop_ptr <= 0; 
    else if (rd_en ==1) 
    begin 
     if (pop_ptr == depth-1) 
     pop_ptr <=0; 
     else 
     pop_ptr <= pop_ptr+1; 
    end 

rd_en가 높은1 경우 pop_ptr하여 pop_ptr 레지스터를 증분 대신 다른 0으로 물품 depth-1 같지 않다. dout 항상 memory_s의 값을 레지스터 pop_ptr이 가리키는 값으로 유지합니다.

을 수행하려는 모든 작업에 대한 작업을 만드는 것이 일반적으로 편리합니다.

wr_en = 1; 
    din = 8'h1; 
    #101 din = 8'h2; 
    rd_en = 1; 

나는 쓰기를 생성하는 예로서 당신을 위해 작업을 읽고 당신은 위의 코드를 대체 할 을 할 수 있습니다. 여기

task write(input [7:0] pdin); 
    $display("[ testbench ] writing data: %0x", pdin); 
    din <= pdin; 
    wr_en <= 1; 
    @(posedge wclk); 
    din <= 0; 
    wr_en <= 0; 
endtask 

task read(output [7:0] prdata); 
    rd_en <= 1; 
    @(posedge rclk); 
    prdata = dout; 
    rd_en <= 0; 
    $display("[ testbench ] reading data: %0x", prdata); 
endtask 

이 작업을 사용하는 방법입니다 :

write(8'hAA); 
    read(read_data); 

    write(8'hCC); 
    read(read_data); 

    write(8'hBC); 
    read(read_data); 

조합 회로를 작성에서, 그것에에 리셋 논리를 추가하지 않는 것이 좋습니다.

always @* 
begin 
     if (rst == 1) 
      full_s <= 0; . . . 

는 또한 EDA 툴 벤더의 대부분은 순차 회로의 조합 회로와 비 블록 할당 (<=)를 서면 (=) 할당 차단 사용하도록 추천한다.

끝내면 시뮬레이션을 마친 후 $finish으로 전화하십시오.

initial begin 
    #1000; $finish; 
end 
+0

코드는 여기에 있습니다 [link] (http://www.edaplayground.com/x/JjG) – e19293001

+0

의견 및 제안에 감사드립니다. 여기에 두 가지 질문이 있습니다. 각각의 읽기 및 쓰기 작업에서 우리는 이것으로 무엇을 성취합니까? ** @ (posedge wclk) din <= 0; wr_en <= 0; ** 읽음에도 블로킹 할당이 필요한 이유는 무엇입니까? ** prdata = dout; ** –

관련 문제