공부방/Verilog_노진호교수님_서울기술교육센터_필기

240522_ BRAM

맘스터치보단파파이스 2024. 5. 22. 16:54

brock ram = sram과 비슷하다.

FPGA에서 만드는 ram은  bram이라한다.

ram을 어떻게 컨트롤 할지가 더 어렵다.

clk, wr, address, wdata, radta

address 1에 a , 2에 b가 저장된다.

wr값에 따라 write, read 가 달라진다.

read : 조합회로.

wirte 할 때도 address 값이 막 나올 때가 있다.

write인지 read인지 모를 땐 두줄로 표시.

`timescale 1ns / 1ps

module ram(
    input           clk     ,
    input     [9:0] address ,
    input     [7:0] data_in ,
    input           wr_en   ,
    output    [7:0] data_out
    );

    reg [7:0] mem[0 : 2**10-1];

    always @(posedge clk) begin
       if (wr_en) begin
            mem[address] <= data_in;
       end 
    end
    assign data_out = mem[address];

endmodule

 

Write, Read 각각 검증.

`timescale 1ns / 1ps

module ram (
    input        clk,
    input  [2:0] address,
    input  [7:0] wdata,
    input        wr_en,
    output [7:0] rdata
);

    reg [7:0] mem[0:2**3-1];

    integer i;

    initial begin
        for (i = 0; i < 2 ** 3; i = i + 1) begin
            mem[i] = 0;
        end
    end

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

    assign rdata = mem[address];

endmodule

제약사항.

`timescale 1ns / 1ps

interface ram_interface;
    logic clk;
    logic wr_en;
    logic [9:0] addr;
    logic [7:0] wdata;
    logic [7:0] rdata;
endinterface //ram_interface

class transaction;
    rand bit       wr_en;
    rand bit [9:0] addr;
    rand bit [7:0] wdata;
    bit       [7:0] rdata;

    task display(string name);
        $display("[%s] wr_en: %x, address: %x, wdata: %x, rdata: %x", name, wr_en, addr, wdata, rdata);
    endtask

//    constraint c_adr {addr < 10;}
    constraint c_addr   {addr inside{[10:19]};}
    constraint c_wdata1 {wdata<100;}
    constraint c_wdata2 {wdata>10;}
//    constraint c_wr_en {wr_en dist{0:=100, 1:=110};}
    constraint c_wr_en {wr_en dist{0:/60, 1:/40};}
endclass //transaction

class generator;
    transaction trans;
    mailbox #(transaction) gen2drv_mbox;
    event gen_next_event;

    function new(mailbox #(transaction) gen2drv_mbox, event gen_next_event);
        this.gen2drv_mbox = gen2drv_mbox;
        this.gen_next_event = gen_next_event;
    endfunction //new()

    task  run(int count);
        repeat(count) begin
            trans = new();
            assert (trans.randomize()) 
            else   $error("[GEN] trans.randomize() error!");
            gen2drv_mbox.put(trans);
            trans.display("GEN");
            @(gen_next_event);
        end
    endtask //
endclass //generator

class driver;
    transaction trans;
    mailbox #(transaction) gen2drv_mbox;
    virtual ram_interface ram_intf;

    function new(virtual ram_interface ram_intf, mailbox #(transaction) gen2drv_mbox);
        this.ram_intf = ram_intf;
        this.gen2drv_mbox = gen2drv_mbox;
    endfunction //new()

    task reset();
        ram_intf.wr_en  <= 1'b0;
        ram_intf.addr   <= 0;
        ram_intf.wdata  <= 0;
        repeat(5) @(posedge ram_intf.clk);
    endtask//

    task  run();
        forever begin
            gen2drv_mbox.get(trans);
            ram_intf.wr_en  <= trans.wr_en;
            ram_intf.addr   <= trans.addr;
            ram_intf.wdata  <= trans.wdata;
         
            trans.display("DRV");
            @(posedge ram_intf.clk);
        end
    endtask //
endclass //driver

class monitor;
    virtual ram_interface ram_intf;
    mailbox #(transaction) mon2scb_mbox;
    transaction trans;
    function new(virtual ram_interface ram_intf, mailbox #(transaction) mon2scb_mbox);
        this.ram_intf = ram_intf;
        this.mon2scb_mbox = mon2scb_mbox;
    endfunction //new()

    task  run();
        forever begin
            trans = new();
            @(posedge ram_intf.clk);
            trans.wr_en = ram_intf.wr_en;
            trans.addr  = ram_intf.addr;
            trans.wdata = ram_intf.wdata;
            trans.rdata = ram_intf.rdata;
            mon2scb_mbox.put(trans);
            trans.display("MON");     
        end   
    endtask //
endclass //monitor

class scoreboard;
    mailbox #(transaction) mon2scb_mbox;
    transaction trans;
    event gen_next_event;

    int total_cnt, pass_cnt, fail_cnt, write_cnt;
    logic [7:0] mem[0:2**10-1];

    function new(mailbox #(transaction) mon2scb_mbox, event gen_next_event);
        this.mon2scb_mbox = mon2scb_mbox;
        this.gen_next_event = gen_next_event;
        total_cnt   = 0;
        pass_cnt    = 0;
        fail_cnt    = 0;
        write_cnt   = 0;
        for(int i = 0; i<2**10; i++) begin
            mem[i] = 0;
        end
    endfunction //new()

    task run();
        forever begin
            mon2scb_mbox.get(trans);
            trans.display("SCB");
            if(trans.wr_en) begin // read
                if(mem[trans.addr]==trans.rdata) begin
                    $display("--> READ PASS! mem[%x] == %x", trans.addr, trans.rdata);
                    pass_cnt++;
                end
                else begin
                    $display("--> READ FAIL! mem[%x] == %x", trans.addr, trans.rdata);
                    fail_cnt++;
                end
            end
            else begin //write
                mem[trans.addr] = trans.wdata;
                $display("--> WRITE! mem[%x] == %x", trans.addr, trans.wdata);
                write_cnt++;           
            end

         total_cnt++;
        ->gen_next_event;
        end
    endtask
endclass //scoreboard

class enviroment;
    generator       gen;
    driver          drv;
    monitor         mon;
    scoreboard      scb;

    event gen_next_event;
    mailbox #(transaction) gen2drv_mbox;
    mailbox #(transaction) mon2scb_mbox;

    function new(virtual ram_interface ram_intf);
        gen2drv_mbox = new();
        mon2scb_mbox = new();

        gen = new(gen2drv_mbox, gen_next_event);
        drv = new(ram_intf, gen2drv_mbox);
        mon = new(ram_intf, mon2scb_mbox);
        scb = new(mon2scb_mbox, gen_next_event);
    endfunction //new()

    task report();
        $display("=============================");
        $display("========Final Report=========");
        $display("=============================");
        $display("Total Test  : %d", scb.total_cnt);
        $display("Pass Count  : %d", scb.pass_cnt);
        $display("Fail Count  : %d", scb.fail_cnt);
        $display("Write Count : %d", scb.write_cnt);
        $display("=============================");
        $display("===test bench is finished!===");
    endtask

    task pre_run();
        drv.reset();
    endtask
    task run();
        fork
            gen.run(50);
            drv.run();
            mon.run();
            scb.run();
        join_any
            report();
            #10 $finish;
    endtask

    task run_test();
        pre_run();
        run();
    endtask
endclass //enviroment
    
module tb_ram();
    enviroment env;
    ram_interface ram_intf();

ram dut(
    .clk(ram_intf.clk),
    .address(ram_intf.addr),
    .wdata(ram_intf.wdata),
    .wr_en(ram_intf.wr_en),
    .rdata(ram_intf.rdata)
    );

    always #5 ram_intf.clk = ~ram_intf.clk;

    initial begin
        ram_intf.clk = 0;
    end

    initial begin
        env = new(ram_intf);
        env.run_test();
    end
endmodule

'공부방 > Verilog_노진호교수님_서울기술교육센터_필기' 카테고리의 다른 글

240524 FIFO+UART  (0) 2024.05.24
240523 FIFO  (0) 2024.05.23
240522_32bit register  (0) 2024.05.22
240521_ TB_ADDER.SV  (0) 2024.05.21
240520 UART  (0) 2024.05.20