공부방/Verilog_vivado

FIFO.SV

맘스터치보단파파이스 2024. 5. 24. 08:52

ENV ( INTERFACE , TRANSACTION ==>  GEN -> DRV -> MON -> SCB )

Transaction : rand변수, constraint  class

Interface     : 전선다발. interface

 

Driver : `include "transaction , interface" : DATA 생성.

drv.reset, drv.run : 초기값 설정.

 

Generatior : `include "transaction" : DATA -> HW 신호로 생성.

randomize() 실행. 

SCB에서 EVENT 받는곳. 

 

Monitor : `include " interface" : DUT 출력신호를 DATA로 변경. HW데이터 -> SW데이터

Scoreboard : `include " transaction " 생성 SW와 DATA를 판단. 

GEN으로 EVENT 보낸다.

 

Envieronment : gen,drv,mon,scb 묶어두는곳.

tb_fifo

ENV에서 실행할 FIFO

`timescale 1ns / 1ps


module fifo #
    (parameter ADDR_WIDTH = 3,
    DATA_WIDTH = 8)(
    input                       clk    ,
    input                       reset  ,
    input                       wr_en  ,
    output                      full   ,
    input [DATA_WIDTH - 1:0]    wdata  ,
    input                       rd_en  ,
    output                      empty  ,
    output[DATA_WIDTH - 1:0]    rdata
    
    );
    wire w_full;
    wire [ADDR_WIDTH - 1:0] w_waddr, w_raddr;

register_file # 
    (.ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(DATA_WIDTH)
    
    )U_register_file(
    .clk(clk)   ,
    .reset(reset) ,
    .wr_en(wr_en & ~full) ,
    .waddr(w_waddr) ,
    .wdata(wdata) ,
    .rd_en(rd_en & ~empty)   ,
    .raddr (w_raddr),
    .rdata(rdata)
);

fifo_control_unit #
    (.ADDR_WIDTH(ADDR_WIDTH
    ))U_fifo_control_unit(
    .clk(clk)     ,
    .reset(reset)   ,
    .wr_en(wr_en)   ,
    .full(full)    ,
    .waddr(w_waddr)   ,
    .rd_en(rd_en)   ,
    .empty(empty)   ,
    .raddr(w_raddr)
    );
endmodule


module register_file # 
    (parameter ADDR_WIDTH = 3, DATA_WIDTH = 8
    )(
    input                       clk   ,
    input                       reset ,
    input                       wr_en ,
    input                       rd_en ,
    input [ADDR_WIDTH - 1:0]    waddr ,
    input [DATA_WIDTH - 1:0]    wdata ,
    input [ADDR_WIDTH - 1:0]    raddr ,
    output[DATA_WIDTH - 1:0]    rdata
);
    reg [DATA_WIDTH-1:0] mem[0:2**ADDR_WIDTH-1];

    always @(posedge clk) begin
        if (wr_en) mem[waddr] <= wdata;
    end

    assign rdata = mem[raddr];
endmodule

module fifo_control_unit #
    (parameter ADDR_WIDTH = 3
    )(
    input                   clk     ,
    input                   reset   ,
    input                   wr_en   ,
    output                  full    ,
    output [ADDR_WIDTH-1:0] waddr   ,
    input                   rd_en   ,
    output                  empty   ,
    output [ADDR_WIDTH-1:0] raddr
    );
    
    reg[ADDR_WIDTH-1:0] wr_ptr_reg, wr_ptr_next;
    reg[ADDR_WIDTH-1:0] rd_ptr_reg, rd_ptr_next;
    reg full_reg, full_next, empty_reg, empty_next;

    assign full = full_reg;
    assign empty = empty_reg;
    assign waddr = wr_ptr_reg;
    assign raddr = rd_ptr_reg;

    always @(posedge clk, posedge reset) begin
        if (reset) begin
            wr_ptr_reg <= 0;
            rd_ptr_reg <= 0;
            full_reg   <= 1'b0;
            empty_reg  <= 1'b0;
        end else begin
            wr_ptr_reg <= wr_ptr_next;
            rd_ptr_reg <= rd_ptr_next;
            full_reg   <= full_next;
            empty_reg  <= empty_next;
        end
    end

    always @(*) begin
        wr_ptr_next = wr_ptr_reg;
        rd_ptr_next = rd_ptr_reg;
        full_next = full_reg;
        empty_next = empty_reg;
        case({wr_en, rd_en})
            2'b01 : begin //read
                if(!empty) begin
                    full_next = 1'b0;
                    rd_ptr_next = rd_ptr_reg +1;
                    if(rd_ptr_next == wr_ptr_reg) begin
                        empty_next = 1'b1;
                    end
                end
            end

            2'b10 : begin //write
                if(!full)begin
                    empty_next = 1'b0;
                    wr_ptr_next = wr_ptr_reg +1;
                    if(wr_ptr_next == rd_ptr_reg)begin
                        full_next = 1'b1;
                    end
                end
            end

            2'b11: begin //write, read
                if(empty_reg)begin
                    wr_ptr_next = wr_ptr_reg;
                    rd_ptr_next = rd_ptr_reg;
                end
                else begin
                    wr_ptr_next = wr_ptr_reg +1;
                    rd_ptr_next = rd_ptr_reg +1;
                end
            end
        endcase      
    end
endmodule

 

wr_en = 1 일 떈 write를 하고  rd_en = 1 일 땐 data를 queue로 부터 pop 시킨다.

if (trans.wr_en & ~trans.full)
else if (trans.rd_en & ~trans.empty)

두가지 상황에 대해서 Fail이 나오게 설정했다. 

FULL 인데 wr_en이 되어 쓰기를 하거나 EMPTY 인데 rd_en 이 되어 값을 읽으려는 두가지 상황에서 오류가 발생했다.