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 |