Device Under Test DUT
interface = H/W신호들 (port list)의 묶음. ==> 케이블같다.
TB : testbench
UVM : universal verification methodology
uvm에서 제동해주는 프레임 ==> env , agent 안에 모니터, 드라이버 등등 드라이버 인터페이스를 통해 모니터를 거쳐 스코어보드로 간다.
transction : test를 위한 데이터의 묶음.
검증용으로 왜 SV를 사용하나.
--> ramdomized stimulus.
--> class 사용 객체지향언어 C++ 사용. VS verilog _ C 절차지향.
객체지향: OOP
객체지향언어의 3대기능 : 캡슐화(추상화), 상속, 다형
1. 캡슐화 : 모듈화한다.
2. 상속 : 재사용성. 새 기능을 사용할 때 기존에 만들어 놓은 것을 사용하는 것.
확장성 : 기존기능 + 새로운기능
3. 다형성 : 같은 객체를 다르게 정의할 수 있다. --> 포인터? 같다 객체들을 상속받는 느낌.
interface : 신호들의 묶음. 케이블처럼.
여태껏 연결을 직접해줬어야했는데,
interface를 선언해놓고 ( 신호선들이 묶여있다.)
interface는 system verilog의 문법이고 합성도 가능한 문법이다. 문제는 베릴로그에서 interface는 지원이 안된다. 베릴로그도 일반적으로는 디자인도 많이 하는데 이로 인해 만들어진 DUT는 사용할 수 없고 SV 에서 사용되는 애들한테만 사용이 가능하다.
자료형은 c언어와 비슷비슷.
verilog 에서 추가된 reg 있고 SV에만 있는 logic이 있다 reg, wire 둘다 사용가능한 logic.
간단한 신호전달. C로따지면 Flag --> Set, true 등등 표현.
신호를 줘서 트리거링을 하는 역할을 한다.
@ 와 wait은 같은 뜻.
객체 1, 2 대기+ 실행 --> 순서를 정한다.
동기화방식으로 된다.
트리거링하는 동기화방식이다.
4bit + 4bit ADDER.
출력이 8bit --> 어떤건 빨리나가고 어떤건 느리게나가는 상황.
이 상황 다음 next에 도착후에 동시에 clk에 출력해주는 작업이 필요하다.
계산은 combination 에서 하고 ( F/F) 순차회로.
출력을 다시 해주는 이런 회로를 주로 사용한다.
아직은 tb_adder.v랑 비슷하다.
`timescale 1ns / 1ps
interface adder_intf;
logic clk;
logic reset;
logic valid;
logic [3:0] a;
logic [3:0] b;
logic [3:0] sum;
logic carry;
endinterface //adder_intf
class transaction;
rand logic [3:0] a;
rand logic [3:0] b;
// rand logic valid;
task display(string name);
$display("[%s] a:%d, b:%d", name, a, b);
//$display("[%s] a:%d, b:%d, vaild:%d", name, a, b, vaild);
endtask
endclass //transaction
class generator;
transaction tr;
function new();
tr = new();
endfunction //new()
task run();
repeat (10) begin
assert (tr.randomize())
else $error("tr.randomize() error!");
tr.display("GEN");
end
endtask //run
endclass //generator
module tb_adder ();
// adder_intf adder_if;
generator gen;
// adder dut (
// .clk (adder_if.clk),
// .reset(adder_if.reset),
// .valid(adder_if.valid),
// .a (adder_if.a),
// .b (adder_if.b),
// .sum (adder_if.sum),
// .carry(adder_if.carry)
// );
// always #5 adder_if.clk = ~adder_if.clk;
// initial begin
// adder_if.clk = 1'b0;
// adder_if.reset = 1'b1;
// end
initial begin
gen = new();
gen.run();
end
endmodule
일단 돌려본거. interface 부분을 일단 주석처리 해둠 GEN 까지 완성.
다음은 DRIVER
GEN -> driver로 보내기 위해 mailbox(queue)를 사용한다.
clk 1번과 2번 사이가 driver의 task run() 앞부분.
virtual 을 넣으면 가상의 인터페이스. 이게 없으면 하드웨어 묶음이 실제로 생겨버린다.
우리는 ta_adder에 실제 묶음을 만들기위해 virtual 쓴다.
new의 reference 값이 넘어간다.
member.adder_if : reference 값.
virtual 과 물리적 interface를 잘 구분해야함.
new()는 class driver만큼 영역을 heap 영역에 생성.
mailbox가 따로있으니까 공유한다는 느낌이 들지 않는다.
쓰레드 사용하면 원하는대로 동작할 것.
folk_join을 통해 따로 따로 한줄 씩 실행.
`timescale 1ns / 1ps
interface adder_intf;
logic clk;
logic reset;
logic valid;
logic [3:0] a;
logic [3:0] b;
logic [3:0] sum;
logic carry;
endinterface //adder_intf
class transaction;
rand logic [3:0] a;
rand logic [3:0] b;
// rand logic valid;
task display(string name);
$display("[%s] a:%d, b:%d", name, a, b);
//$display("[%s] a:%d, b:%d, valid:%d", name, a, b, valid);
endtask
endclass //transaction
class generator;
transaction tr;
mailbox #(transaction) gen2drv_mbox;
event genNextEvent1;
function new();
tr = new();
endfunction //new()
task run();
repeat (10) begin
assert (tr.randomize())
else $error("tr.randomize() error!");
gen2drv_mbox.put(tr);
tr.display("GEN");
@(genNextEvent1);
end
endtask //run
endclass //generator
class driver;
virtual adder_intf adder_if1;
mailbox #(transaction) gen2drv_mbox;
transaction trans;
event genNextEvent2;
function new(virtual adder_intf adder_if2);
this.adder_if1 = adder_if2;
endfunction//new()
task reset();
adder_if1.a <= 0;
adder_if1.b <= 0;
adder_if1.valid <= 1'b0;
adder_if1.reset <= 1'b1;
repeat(5) @(adder_if1.clk);
adder_if1.reset <= 1'b0;
endtask //
task run();
forever begin
gen2drv_mbox.get(trans);
adder_if1.a = trans.a;
adder_if1.b = trans.b;
adder_if1.valid = 1'b1;
trans.display("DRV");
@(posedge adder_if1.clk);
adder_if1.valid = 1'b0;
@(posedge adder_if1.clk);
->genNextEvent2;
end
endtask
endclass//driver
module tb_adder ();
adder_intf adder_interface();
generator gen;
driver drv;
event genNextEvent;
mailbox #(transaction) gen2drv_mbox;
adder dut (
.clk (adder_interface.clk),
.reset(adder_interface.reset),
.valid(adder_interface.valid),
.a (adder_interface.a),
.b (adder_interface.b),
.sum (adder_interface.sum),
.carry(adder_interface.carry)
);
always #5 adder_interface.clk = ~adder_interface.clk;
initial begin
adder_interface.clk = 1'b0;
adder_interface.reset = 1'b1;
end
initial begin
gen2drv_mbox = new();
gen = new();
gen.genNextEvent1 = genNextEvent;
drv = new(adder_interface);
drv.genNextEvent2 = genNextEvent;
gen.gen2drv_mbox = gen2drv_mbox;
drv.gen2drv_mbox = gen2drv_mbox;
drv.reset();
fork
drv.run();
gen.run();
join_any
$display("testbench is finished");
#10 $finish;
end
endmodule
이젠 monitor 와 scoreboard가 남아있다.
trans.a + trans.b <- reference model.
해당 값을 golden reference.
`timescale 1ns / 1ps
interface adder_intf;
logic clk;
logic reset;
logic valid;
logic [3:0] a;
logic [3:0] b;
logic [3:0] sum;
logic carry;
endinterface //adder_intf
class transaction;
rand logic [3:0] a;
rand logic [3:0] b;
logic [3:0] sum;
logic carry;
// rand logic valid;
task display(string name);
$display("[%s] a:%d, b:%d, carry:%d, sum:%d", name, a, b, carry, sum);
endtask
endclass //transaction
class generator;
transaction tr;
mailbox #(transaction) gen2drv_mbox;
event genNextEvent1;
function new();
tr = new();
endfunction //new()
task run();
repeat (10) begin
assert (tr.randomize())
else $error("tr.randomize() error!");
gen2drv_mbox.put(tr);
tr.display("GEN");
@(genNextEvent1);
end
endtask //run
endclass //generator
class driver;
virtual adder_intf adder_if1;
mailbox #(transaction) gen2drv_mbox;
transaction trans;
event genNextEvent2;
event monNextEvent2;
function new(virtual adder_intf adder_if2);
this.adder_if1 = adder_if2;
endfunction//new()
task reset();
adder_if1.a <= 0;
adder_if1.b <= 0;
adder_if1.valid <= 1'b0;
adder_if1.reset <= 1'b1;
repeat(5) @(adder_if1.clk);
adder_if1.reset <= 1'b0;
endtask //
task run();
forever begin
gen2drv_mbox.get(trans);
adder_if1.a = trans.a;
adder_if1.b = trans.b;
adder_if1.valid = 1'b1;
trans.display("DRV");
@(posedge adder_if1.clk);
adder_if1.valid = 1'b0;
@(posedge adder_if1.clk);
->monNextEvent2;
->genNextEvent2;
end
endtask
endclass//driver
class monitor;
virtual adder_intf adder_if3;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
event monNextEvent1;
function new(virtual adder_intf adder_if2);
this.adder_if3 = adder_if2;
trans = new();
endfunction// new()
task run();
forever begin
@(monNextEvent1);
trans.a = adder_if3.a;
trans.b = adder_if3.b;
trans.sum = adder_if3.sum;
trans.carry = adder_if3.carry;
mon2scb_mbox.put(trans);
trans.display("MON");
end
endtask //run()
endclass //monitor
class scoreboard;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
function new();
endfunction //new()
task run();
forever begin
mon2scb_mbox.get(trans);
trans.display("SCB");
if(trans.a + trans.b == {trans.carry, trans.sum})begin
$display(" --> PASS! %d + %d = %d", trans.a, trans.b, {trans.carry, trans.sum});
end
else begin
$display(" --> FAIL! %d + %d = %d", trans.a, trans.b, {trans.carry, trans.sum});
end
end
endtask
endclass //scoreboard
module tb_adder ();
adder_intf adder_interface();
generator gen;
driver drv;
monitor mon;
scoreboard scb;
event genNextEvent;
event monNextEvent;
mailbox #(transaction) gen2drv_mbox;
mailbox #(transaction) mon2scb_mbox;
adder dut (
.clk (adder_interface.clk),
.reset(adder_interface.reset),
.valid(adder_interface.valid),
.a (adder_interface.a),
.b (adder_interface.b),
.sum (adder_interface.sum),
.carry(adder_interface.carry)
);
always #5 adder_interface.clk = ~adder_interface.clk;
initial begin
adder_interface.clk = 1'b0;
adder_interface.reset = 1'b1;
end
initial begin
gen2drv_mbox = new();
mon2scb_mbox = new();
gen = new();
drv = new(adder_interface);
mon = new(adder_interface);
scb = new();
gen.genNextEvent1 = genNextEvent;
drv.genNextEvent2 = genNextEvent;
mon.monNextEvent1 = monNextEvent;
drv.monNextEvent2 = monNextEvent;
gen.gen2drv_mbox = gen2drv_mbox;
drv.gen2drv_mbox = gen2drv_mbox;
mon.mon2scb_mbox = mon2scb_mbox;
scb.mon2scb_mbox = mon2scb_mbox;
drv.reset();
fork
drv.run();
gen.run();
mon.run();
scb.run();
join_any
$display("testbench is finished");
#10 $finish;
end
endmodule
`timescale 1ns / 1ps
interface adder_intf;
logic clk;
logic reset;
logic valid;
logic [3:0] a;
logic [3:0] b;
logic [3:0] sum;
logic carry;
endinterface //adder_intf
class transaction;
rand logic [3:0] a;
rand logic [3:0] b;
logic [3:0] sum;
logic carry;
// rand logic valid;
task display(string name);
$display("[%s] a:%d, b:%d, carry:%d, sum:%d", name, a, b, carry, sum);
endtask
endclass //transaction
class generator;
transaction tr;
mailbox #(transaction) gen2drv_mbox;
event genNextEvent1;
function new();
tr = new();
endfunction //new()
task run();
repeat (10) begin
assert (tr.randomize())
else $error("tr.randomize() error!");
gen2drv_mbox.put(tr);
tr.display("GEN");
@(genNextEvent1);
end
endtask //run
endclass //generator
class driver;
virtual adder_intf adder_if1;
mailbox #(transaction) gen2drv_mbox;
transaction trans;
//event genNextEvent2;
event monNextEvent2;
function new(virtual adder_intf adder_if2);
this.adder_if1 = adder_if2;
endfunction//new()
task reset();
adder_if1.a <= 0;
adder_if1.b <= 0;
adder_if1.valid <= 1'b0;
adder_if1.reset <= 1'b1;
repeat(5) @(adder_if1.clk);
adder_if1.reset <= 1'b0;
endtask //
task run();
forever begin
gen2drv_mbox.get(trans);
adder_if1.a = trans.a;
adder_if1.b = trans.b;
adder_if1.valid = 1'b1;
trans.display("DRV");
@(posedge adder_if1.clk);
adder_if1.valid = 1'b0;
@(posedge adder_if1.clk);
->monNextEvent2;
//->genNextEvent2;
end
endtask
endclass//driver
class monitor;
virtual adder_intf adder_if3;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
event monNextEvent1;
function new(virtual adder_intf adder_if2);
this.adder_if3 = adder_if2;
trans = new();
endfunction// new()
task run();
forever begin
@(monNextEvent1);
trans.a = adder_if3.a;
trans.b = adder_if3.b;
trans.sum = adder_if3.sum;
trans.carry = adder_if3.carry;
mon2scb_mbox.put(trans);
trans.display("MON");
end
endtask //run()
endclass //monitor
class scoreboard;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
event genNextEvent2;
int total_cnt, pass_cnt, fail_cnt;
function new();
endfunction //new()
task run();
forever begin
mon2scb_mbox.get(trans);
trans.display("SCB");
if(trans.a + trans.b == {trans.carry, trans.sum})begin
$display(" --> PASS! %d + %d = %d", trans.a, trans.b, {trans.carry, trans.sum});
pass_cnt++;
end
else begin
$display(" --> FAIL! %d + %d = %d", trans.a, trans.b, {trans.carry, trans.sum});
fail_cnt++;
end
total_cnt++;
->genNextEvent2;
end
endtask
endclass //scoreboard
module tb_adder ();
adder_intf adder_interface();
generator gen;
driver drv;
monitor mon;
scoreboard scb;
event genNextEvent;
event monNextEvent;
mailbox #(transaction) gen2drv_mbox;
mailbox #(transaction) mon2scb_mbox;
adder dut (
.clk (adder_interface.clk),
.reset(adder_interface.reset),
.valid(adder_interface.valid),
.a (adder_interface.a),
.b (adder_interface.b),
.sum (adder_interface.sum),
.carry(adder_interface.carry)
);
always #5 adder_interface.clk = ~adder_interface.clk;
initial begin
adder_interface.clk = 1'b0;
adder_interface.reset = 1'b1;
end
initial begin
gen2drv_mbox = new();
mon2scb_mbox = new();
gen = new();
drv = new(adder_interface);
mon = new(adder_interface);
scb = new();
gen.genNextEvent1 = genNextEvent;
scb.genNextEvent2 = genNextEvent;
mon.monNextEvent1 = monNextEvent;
drv.monNextEvent2 = monNextEvent;
gen.gen2drv_mbox = gen2drv_mbox;
drv.gen2drv_mbox = gen2drv_mbox;
mon.mon2scb_mbox = mon2scb_mbox;
scb.mon2scb_mbox = mon2scb_mbox;
drv.reset();
fork
drv.run();
gen.run();
mon.run();
scb.run();
join_any
$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("========testbench is finished=======");
$display("====================================");
#10 $finish;
end
endmodule
'공부방 > Verilog_노진호교수님_서울기술교육센터_필기' 카테고리의 다른 글
240522_ BRAM (0) | 2024.05.22 |
---|---|
240522_32bit register (0) | 2024.05.22 |
240520 UART (0) | 2024.05.20 |
240517 UART (0) | 2024.05.17 |
240516 FSM_COUNTER , ILA , UART (0) | 2024.05.16 |