RTL | OOP | |
---|---|---|
Block definition | module | class |
Block instance | instance | object |
Block name | instance name | object handle |
Data types | registers and wires | variables |
Functionality | tasks, functions, behavioral blocks(always, initial) | subroutines(tasks, functions) |
class Packet;
string name;
bit[3:0] sa, da;
bit[7:0] payload[];
task send();
send_addrs();
send_pad();
send_payload();
endtask: send
endclass: Packet
Variables = properties
Subroutines = methods
Properteis & methods = members of class
program automatic test;
Packet pkt1 = new();
Packet pkt2;
initial begin
pkt2 = new();
pkt1.sa = 3;
end
endprogram: test
program automatic test;
class Packet;
string name;
bit[3:0] sa, da;
bit[7:0] payload[];
function new(bit[3:0] init_sa, init_da, int init_payload_size);
this.sa = init_sa;
this.da = init_da;
this.payload = new[init_payload_size];
endfunction: new
task send();
send_addrs();
send_pad();
send_payload();
endtask: send
endclass: Packet
initial begin
Packet pkt1 = new(3, 7, 2);
end
endprogram
VCS는 garbage collector 있음.
class Packet;
int count;
Payload p;
endclass: Packet
Packet pkt1 = new();
Packet pkt1_copy;
pkt1_copy = new pkt1;
pkt1_copy 가 원래 가리키던 메모리 공간 접근 불가하므로 garage collector가 제거함.
class 안에 있는 class(Payload p
)는 카피가 안됨.copy()
함수 구현해서 사용.
program automatic test;
class driver;
local int max_err_cnt = 0, err_cnt = 0;
task run();
if (error_cond()) err_cnt++;
if ((max_err_cnt != 0) && (err_cnt >= max_err_cnt))
$finish;
endtask
function set_max_err_cnt(int max_err_cnt);
if (max_err_cnt < 0) begin
this.max_er_cnt = 0;
return;
end
else this.max_err_cnt = max_err_cnt;
endfunction
function new();
endfunction
endclass: driver
initial begin
driver drv = new();
drv.set_max_err_cnt(-1);
drv.run();
end
endprogram: test
static
Membersclass Packet;
static int count = 0;
int id;
static function int get_count();
return count;
endfunction
function new();
this.id = count++;
endfunction
endclass: Packet
virtual
subroutines는 접근 못함
class의 모든 objects가 공유함
const
Propertiesclass Packet;
static int count = 0;
const int id; // instance constant
static const string type_name = "Packet"; // global constant
static function int get_count();
return count;
endfunction
function new();
this.id = count++; // instance constant can only be assigned in new()
endfunction
endclass: Packet
Global constant - tipically declared
static
Instance constant - can not bestatic
initial
, always
사용 불가fork-join_none
으로 구현class Driver
task run();
fork
forever
send();
join_none
endtask: run
endclass: Driver
program automatic test;
typedef class stack;
stack addr_stack;
stack #(Packet, 128) data_stack;
class stack #(type T = int, bit[11:0] depth = 1024);
protected T items[$:depth];
function T pop();
function viod push ( T a );
...
endclass: stack
initial begin
...
end
endprogram: test
class node;
static int count = 0;
node next;
...
extern task ping();
endcalss: node
task node::ping();
...
endtask: ping
namespace 사용가능
class Driver;
virtual router_io.TB rtr_io_ref;
...
function new(virtual router_io.TB rtr_io_arg);
this.rtr_io_ref = rtr_io_arg;
endfunction: new
task send_addrs();
this.rtr_io_ref.cb.frame_n[sa] <= 1'b0;
for (int i = 0; i < 4; i++) begin
this.rtr_io_ref.cb.din[sa] <= da[i];
@(this.rtr_io_ref.cb);
end
endtask: send_addrs
endclass: Driver
공유 가능
package ComplexPkg;
class Complex;
float i, r;
extern virtual task display();
endclass: Complex
function automatic Complex add(Complex a, b);
add = new();
add.r = a.r + b.r;
add.i = a.i + b.i;
endfunction: add
function automatic Complex mul(Complex a, b);
mul = new();
mul.r = (a.r * b.r) - (a.i * b.i);
mul.i = (a.r * b.i) + (a.i * b.r);
endfunction: mul
endpackage: ComplexPkg
processes 쓰면 안됨 - wire 도 안됨
hierarchical references 쓰면 안됨
ComplexPkg::Complex count = ComplexPkg::mul(a, b);
로 사용
import ComplexPkg::*;
도 가능
Packages를 import 해서 package 만들었으면export ComplexPkg::*;
사용
randomize()
: function built into every classrand
: 주사위 굴리기randc
: 카드 뽑기class Packet;
randc bit[3:0] sa, da;
rand bit[7:0] payload[];
endclass: Packet
program automatic test;
int run_for_n_pkts = 100;
Packet pkt = new();
initial begin
...
repeat (run_for_n_pkts)
beegin
if(!pkt.randomize()) ... ;
fork
send();
recv();
join
check();
end
end
endprogram: test
class Packet;
randc bit[3:0] sa, da;
rand bit[7:0] payload[];
constraint corner_test {
sa == 12;
da inside {2,4, [6:10]};
payload.size() >= 2;
payload.size() <= 4;
}
endclass: Packet
constraint Limit {
sa dist {[5:7]:=30, 9:=20}; // 5,6,7의 weight는 30, 9는 20
da dist {[5:7]:/30, 9:=20}; // 5,6,7의 weight는 10, 9는 20
}
class Config;
rand bit[7:0] addrs[10];
rand bit drivers_in_use[16];
rand int num_of_driers, one_addr;
constraint limit {
num_of_drivers inside { [1:16] };
drivers_in_use.sum() with (int'(item)) == num_of_drivers;
foreach(addrs[idx]) (idx > 0) -> addrs[idx] > addrs[idx-1];
one_addr inside addrs;
}
endclass: Config
typedef enum { low, mid, high, any } AddrTyp_e;
class MyBus;
rand bit[7:0] addr;
rand AddrTyp_e atype;
constraint addr_range {
(atype == low ) <=> addr inside { [0:15] };
(atype == mid ) <=> addr inside { [16:127] };
(atype == high) <=> addr inside { [128:255] };
}
endclass: MyBus
class C;
rand bit [2:0] a[7];
rand bit [2:0] b;
constraint cst1 {
unique { a[0:2], a[6]. b };
}
endclass: C
unique
안에 있는 값들은 서로 다른 값을 가진다.
randc
가 rand
보다 우선순위
class MyBus;
rand bit flag;
rand bit[11:0] addr;
constraint addr_range {
if ( flag == 0 ) addr == 0;
else addr inside { [1:1024] };
solve flag before addr;
}
endclass: MyBus
program automatic test;
class demo;
rand int x, y, z;
constraint Limit1 { x > 0; x <= 5; }
endclass: demo
initial bgin
demo obj_a = new();
if (!obj_a.randomize() with { x > 3 && x < 10; }) ...;
end
endprogram: test
class Packet;
rand bit [11:0] len;
rand int min, max;
constraint len_c { soft len inside {[min:max]};}
constraint range { soft min == 0; soft max == 10;}
endclass: Packet
Packet p,q;
int tmin,tmax;
stat = p.randomize() with {
soft len inside {[tmin:tmax]};
}
rand
변수만 가능.randc
불가능
inline constraint가 우선임
randomize()
class Packet;
int test_mode;
rand bit[3:0] sa, da;
rand bit[7:0] payload[];
bit[15:0] crc;
constraint LimitA {
sa inside { [0:7] };
da inside { [0:7] };
payload.size() inside {[2:4]};
}
function void pre_randomize();
if(test_mode) sa.rand_mode(0)
endfunction
function void post_randomize();
gen_crc(); // user method
endfunction
endclass: Packet
randomize()
호출시
pre_randomize()
호출하고
변수 랜덤 돌리고
post_randomize()
호출
rand_mode(0 | 1)
rand_mode()
는program
의initial
안에서도 사용가능
constraint_mode()
class demo;
rand int x, y, z;
constraint no_error { x > 0; x <= 5; }
static constraint with_err { x > 0; x <= 32; }
endclass: demo
program automatic test;
initial begin
demo obj_a = new();
obj_a.no_error.constraint_mode(0);
if(!obj_a.randomize()) ... ;
end
endprogram: test
seed 값을 저장하는 습관을 가지자!
class BadPacket extends Packet;
으로 상속
$cast(bad_pkt, pkt);
또는 pkt = bad_pkt;
로 derive 가능
handle이 다르면 안됨.
즉, 부모 클래스 핸들에 자식 클래스 핸들을 주는건 가능 반대는 불가능
$cast
사용시에도 같음.
부모 호출시에
function bit[31:0] compute_crc()
this.crc = super.compute_crc();
return(crc = is_bad ? ~crc : crc);
endfunction: compute_crc
virtual
함수로 parent꺼 말고 child꺼 사용가능
task transmit(Packet pkt);
...
pkt.crc = pkt.compute_crc();
...
endtask: transmit
Packet p = new();
BadPacket bp = new();
p.crc = p.compute_crc();
bp.crc = bp.compute_crc();
transmit(p);
transmit(bp);
직접 호출시에는 상관없는데
transmit
task 같은 경우 부모꺼만 호출됨
부모 함수에virtual
keyword 사용
class data;
rand bit[31:0] x, y;
constraint valid {
x > 0; y >= 0;
}
endclass: data
class Generator;
data blueprint;
...
while (...)
...
blueprint.randomize();
...
endclass: Generator
program automatic test_corner_case;
class test_data extends data;
constraint corner_case {
x == 5; y == 10;
}
endclass: test_data
initial begin
test_data tdata = new();
Generator gen = new();
gen.blueprint = tdata;
...
end
endprogram: test_corner_case
local
: members of a base class are not accessible in the derived class
protected
: members of a base class are accessible in the derived class but not to external code
new()
문제점program test;
class A;
protected int a;
function int get_a();
get_a = a;
endfunction
function new(int b);
a = b;
endfunction
endclass
class B extends A;
protected int b = 1000;
function new(int b);
super.new(b);
endfunction
task print_a();
$display("a is %d", get_a());
endtask: print_a
endclass
class C extends B;
function new(int c);
a = c;
endfunction
endclass
initial begin
C test_c = new(10);
test_c.print_a();
end
endprogram
B class에서
new()
function 없으면 에러 발생