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

240522_32bit register

맘스터치보단파파이스 2024. 5. 22. 13:50

generator : transction 생성.

gen. put(tr)

gen --> drv : transction DATA를 mailbox를 통해 넘겨준다.

gen.get(tr)

driver : SW DATA를 HW DATA로 바꿔준다.

 

monitor : HW신호를 SW데이터로 바꿔준다.

mon.put(tr)

mon --> scb :  transction DATA를 mailbox를 통해 넘겨준다.

mon.get(tr)

scb : golden reference와 data의 값을 비교하여 Pass/Fail 비교.

모든 파트는 객체 CLASS로 구성되어 있다.

interface는 전선묶음. HW이다.

 

앞에 조합회로가 없기 때문에

state register 부분에서 다 해결해주는 것이 가능하다.

trans = new() : 만들어진 객체 new()를 계속 trans에 넣어준다. 

 

new()의 생성과정 대해 알아보자.

trans = new(); --> transaction이 memory heap의 어느영역에 실체화가 된다. 포인터처럼 사용하려고 transaction trans;를 통해서 쓴다.  trans는 randomize()되고 그 뒤에 mailbox.put을 통해 mailbox에 값이 들어가게 된다.

이 상황에 대해서 transaction 3 처럼 계속 mailbox에 값이 들어가게 된다. 메모리에 값이 계속 쌓이게 되는 문제가 생길거 같은데 생기지 않는다. mailbox.get()해서 가져간다.

mailbox.ge() 할 때 마다 한개 씩 가져간다. 포인터느낌으로 가져간다. 하지만 실체화 된, 메모리에 실체화되어있는 transaction은 어떻게 되는가? (ex) 자바는 reference값을 가지고 있는 변수가 하나도 없을 때 garbage collection으로 메모리를 정리하며 알아서 정리한다. system verilog도 역시 garbage collection이 동작해서 memory 에 transaction class instance data가 자동으로 정리된다. C++에서는 그런 기능이 없다. 그래서 memory leak 현상이 나타난다.

trans : SW , interface : HW

하지만 run이 무한으로 돌게 된다. 이를 방지해야한다. 두가지 방법이 있다.

1. event를 받아서 drv에 받아서 진행.

2. clk이발생하게되면 ( 같은 clk) 실제 출력이 나오니까. 과연 동기화는 잘 될까?

 

1.event

`timescale 1ns / 1ps

interface reg_interface;
    logic clk     ;
    logic reset   ;
    logic [31:0] d;
    logic [31:0] q;
endinterface //reg_interface

class transaction;

    rand logic [31:0] data;
    logic [31:0] out ;

    task display(string name);
        $display("[%s] data : %x, out: %x", name, data, out);
    endtask
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 reg_interface reg_intf;
    event drv_next_event;

    function new(virtual reg_interface reg_intf, mailbox #(transaction) gen2drv_mbox, event drv_next_event);
        this.reg_intf = reg_intf;
        this.gen2drv_mbox = gen2drv_mbox;
        this.drv_next_event = drv_next_event;
    endfunction //new()

    task reset();
        reg_intf.d <= 0;
        reg_intf.reset <= 1'b1;
        repeat(5) @(posedge reg_intf.clk);
        reg_intf.reset <= 1'b0;
    endtask//

    task  run();
        forever begin
           // @(posedge reg_intf.clk);
            gen2drv_mbox.get(trans);
            @(posedge reg_intf.clk);
            reg_intf.d <= trans.data;
            
            trans.display("DRV");
            
            ->drv_next_event;
        end
    endtask //
endclass //driver

class monitor;
    virtual reg_interface reg_intf;
    mailbox #(transaction) mon2scb_mbox;
    transaction trans;
    event drv_next_event;

    function new(virtual reg_interface reg_intf, mailbox #(transaction) mon2scb_mbox, event drv_next_event);
        this.reg_intf = reg_intf;
        this.mon2scb_mbox = mon2scb_mbox;
        this.drv_next_event = drv_next_event;
    endfunction //new()

    task  run();
        forever begin
            @(drv_next_event);
            trans = new();
            //@(posedge reg_intf.clk)
            trans.data = reg_intf.d;
            @(posedge reg_intf.clk);
            trans.out = reg_intf.q;
            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;

    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;
    endfunction //new()

    task run();
        forever begin
            mon2scb_mbox.get(trans);
            trans.display("SCB");
            if(trans.data == trans.out)begin
                $display("-->PASS! %x = %x", trans.data, trans.out);
                pass_cnt++;
            end
            else begin
                $display("-->FAIL %x = %x", trans.data, trans.out);
                fail_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;
    event drv_next_event;

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

    function new(virtual reg_interface reg_intf);
        gen2drv_mbox = new();
        mon2scb_mbox = new();

        gen = new(gen2drv_mbox, gen_next_event);
        drv = new(reg_intf, gen2drv_mbox, drv_next_event);
        mon = new(reg_intf, mon2scb_mbox, drv_next_event);
        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("============================");
        $display("test bench is finished!");
    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 //enviroment
    
module tb_register();
    enviroment env;
    reg_interface reg_intf();

    register dut(
    .clk(reg_intf.clk),
    .reset(reg_intf.reset),
    .d(reg_intf.d),
    .q(reg_intf.q)
    );

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

    initial begin
        reg_intf.clk = 0;
    end

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

2.. CLK

`timescale 1ns / 1ps

interface reg_interface;
    logic clk     ;
    logic reset   ;
    logic [31:0] d;
    logic [31:0] q;
endinterface //reg_interface

class transaction;

    rand logic [31:0] data;
    logic [31:0] out ;

    task display(string name);
        $display("[%s] data : %x, out: %x", name, data, out);
    endtask
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 reg_interface reg_intf;

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

    task reset();
        reg_intf.d <= 0;
        reg_intf.reset <= 1'b1;
        repeat(5) @(posedge reg_intf.clk);
        reg_intf.reset <= 1'b0;
    endtask//

    task  run();
        forever begin
            @(posedge reg_intf.clk);
            gen2drv_mbox.get(trans);
            reg_intf.d <= trans.data;
            trans.display("DRV");
            @(posedge reg_intf.clk);
        end
    endtask //
endclass //driver

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

    task  run();
        forever begin
            trans = new();
            @(posedge reg_intf.clk)
            trans.data = reg_intf.d;
            @(posedge reg_intf.clk);
            trans.out = reg_intf.q;
            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;

    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;
    endfunction //new()

    task run();
        forever begin
            mon2scb_mbox.get(trans);
            trans.display("SCB");
            if(trans.data == trans.out)begin
                $display("-->PASS! %x = %x", trans.data, trans.out);
                pass_cnt++;
            end
            else begin
                $display("-->FAIL %x = %x", trans.data, trans.out);
                fail_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 reg_interface reg_intf);
        gen2drv_mbox = new();
        mon2scb_mbox = new();

        gen = new(gen2drv_mbox, gen_next_event);
        drv = new(reg_intf, gen2drv_mbox);
        mon = new(reg_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("============================");
        $display("test bench is finished!");
    endtask

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

    task run_test();
        pre_run();
        run();
    endtask
endclass //enviroment
    
module tb_register();
    enviroment env;
    reg_interface reg_intf();

    register dut(
    .clk(reg_intf.clk),
    .reset(reg_intf.reset),
    .d(reg_intf.d),
    .q(reg_intf.q)
    );

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

    initial begin
        reg_intf.clk = 0;
    end

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

 

2 개선. clk 조절.

`timescale 1ns / 1ps

interface reg_interface;
    logic clk     ;
    logic reset   ;
    logic [31:0] d;
    logic [31:0] q;
endinterface //reg_interface

class transaction;

    rand logic [31:0] data;
    logic [31:0] out ;

    task display(string name);
        $display("[%s] data : %x, out: %x", name, data, out);
    endtask
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 reg_interface reg_intf;

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

    task reset();
        reg_intf.d <= 0;
        reg_intf.reset <= 1'b1;
        repeat(5) @(posedge reg_intf.clk);
        reg_intf.reset <= 1'b0;
    endtask//

    task  run();
        forever begin
            //@(posedge reg_intf.clk);
            gen2drv_mbox.get(trans);
            reg_intf.d <= trans.data;
            trans.display("DRV");
            @(posedge reg_intf.clk);
        end
    endtask //
endclass //driver

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

    task  run();
        forever begin
            trans = new();
            //@(posedge reg_intf.clk)
            trans.data = reg_intf.d;
            @(posedge reg_intf.clk);
            trans.out = reg_intf.q;
            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;

    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;
    endfunction //new()

    task run();
        forever begin
            mon2scb_mbox.get(trans);
            trans.display("SCB");
            if(trans.data == trans.out)begin
                $display("-->PASS! %x = %x", trans.data, trans.out);
                pass_cnt++;
            end
            else begin
                $display("-->FAIL %x = %x", trans.data, trans.out);
                fail_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 reg_interface reg_intf);
        gen2drv_mbox = new();
        mon2scb_mbox = new();

        gen = new(gen2drv_mbox, gen_next_event);
        drv = new(reg_intf, gen2drv_mbox);
        mon = new(reg_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("============================");
        $display("test bench is finished!");
    endtask

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

    task run_test();
        pre_run();
        run();
    endtask
endclass //enviroment
    
module tb_register();
    enviroment env;
    reg_interface reg_intf();

    register dut(
    .clk(reg_intf.clk),
    .reset(reg_intf.reset),
    .d(reg_intf.d),
    .q(reg_intf.q)
    );

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

    initial begin
        reg_intf.clk = 0;
    end

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

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

240523 FIFO  (0) 2024.05.23
240522_ BRAM  (0) 2024.05.22
240521_ TB_ADDER.SV  (0) 2024.05.21
240520 UART  (0) 2024.05.20
240517 UART  (0) 2024.05.17