[하만]세미콘 아카데미/verilog

0522 RAM SystemVerilog verification

내머리속은이런걸로 2024. 7. 9. 17:43

Block RAM (BRAM)

: FPGA와 같은 프로그래머블 로직 장치 내부

  • 내장형 메모리 : FPGA 내부에 위치하여 고속 접근이 가능하다.
  • 크기 및 구성 : 18Kb 또는 36Kb 크기이며, 단일 포트 RAM, 듀얼 포트 RAM, FIFO 등으로 사용할 수 있다.
  • 용도 : 임시 데이터 저장, 버퍼링, 캐시 메모리 등 다양한 용도로 사용되며, 고속 데이터 접근이 필요한 곳에 주로 사용된다. 
  • 동기화 : FPGA의 클럭과 동기화되어 동작하며, 안정적인 데이터 저장 및 접근을 보장한다.

 

BRAM

  • write : memory에 저장한다.
  • read : memory 주소의 Data가 바로 출력된다.

SRAM

: Static Ramdom Access Memory, 전원이 공급되는 동안 데이터가 유지되는 비휘발성 메모리이다.

 

  • 구조 : 플립플롭 회로를 사용하여 각 비트를 저장하며, DRAM과 달리 데이터 유지를 위해 주기적인 리프레시가 필요하지 않는다.
  • 속도 : 매우 빠른 데이터 접근 시간을 가지며, 고속 캐시 메모리, 레지스터 파일 등에 사용된다.
  • 용량과 비용 : 비트당 더 많은 트랜지스터를 사용하므로 용량당 비용이 높다. 대용량 메모리 구현에는 적합하지 않지만, 고속 접근이 필요한 소규모 메모리에 적합하다.

rand 난수 생성

  • rand : 무작위 random 난수 생성한다.
  • randc : 순환 random으로, 정수를 중복 없이 생성한다.

constraint, 제약 사항 설정

: constraint 이름 {제약조건;}

  • constraint c_addr {addr inside[10:19];} : addr을 10~19 사이 값으로 생성한다.
  • constraint c_wdata1 {wdata < 100;} : wdata를 100 미만으로 생성한다.
  • constraint c_wdata1 {wdata > 10;} : 위의 조건과 같이 생성 시, 위의 조건을 만족하면서 wdata를 10 초과로 생성한다.
  • constraint c_wr_en {wr_en dist {0:=100, 1:=110};} : 0을 100/210, 1을 110/210 비율로 생성한다.
  • constraint c_wr_en {wr_en dist {0:/60, 1:/40};] : 0을 보낼 확률이 60%, 1을 보낼 확률이 40%이다.

Block RAM

ram.v

`timescale 1ns / 1ps

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

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

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

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

    assign rdata = mem[addr];

endmodule

 

tb_ram.sv

`timescale 1ns / 1ps

interface ram_interface;
    logic       clk;
    logic [9:0] addr;
    logic [7:0] wdata;
    logic       wr_en;
    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, addr: %x, wdata: %x, rdata: %x", name, wr_en,
                 addr, wdata, rdata);
    endtask

    //constraint c_addr {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};}   // 0은 100만큼, 1은 110만큼 발생
    constraint c_wr_en {wr_en dist {0:/60, 1:/40};} // 0은 60%, 1은 40%
endclass

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

    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;
            trans.display("MON");

            mon2scb_mbox.put(trans);
        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 environment;
    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

    task report();
        $display("=======================================");
        $display("            Final Report");
        $display("=======================================");
        $display("Total Test   : %d", scb.total_cnt);
        $display("Pass Counter : %d", scb.pass_cnt);
        $display("Fail Counter : %d", scb.fail_cnt);
        $display("WRITE CNT : %d", scb.write_cnt);
        $display("=======================================");
        $display("       test bench is finished!");
        $display("=======================================");
        #10 $finish;
    endtask

    task pre_run();
        drv.reset();
    endtask

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

    task run_test();
        pre_run();
        run();
    endtask
endclass

module tb_ram ();

    environment env;
    ram_interface ram_intf ();

    ram dut (
        .clk  (ram_intf.clk),
        .addr (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

 

simulation

'[하만]세미콘 아카데미 > verilog' 카테고리의 다른 글

0524 uart fifo  (0) 2024.07.09
0523 FIFO Systemverilog verification  (0) 2024.07.09
0522 32bit register.sv  (0) 2024.07.09
0521 num.sv  (0) 2024.07.09
0521 system verilog, adder.sv  (0) 2024.07.09