module data_byte
bit b_signed_vs_unsigned = 1;
bit b_bit_vs_logic = 1;
bit b_enum_type = 1;
bit b_struct_type = 1;
// TODO-1: distinguish signed and unsigned type
initial begin: signed_vs_unsigned
byte b0;
bite[7:0] b1;
wait(b_signed_vs_unsigned == 1);$display("signed_vs_unsigned process block started");
b0 = 'b1000_0000;
$display("byte variable b0 = %d", b0);
b1 = b0;
$display("bit vector variable b1 = %d", b1)
end
// TODO-2: distinguish bit and logic
initial
initial begin: bit_vs_logic
bit v1;
logic v2;
wait(b_bit_vs_logic == 1); $display("bit_vs_logic process block started");
v2 = 'b1;
$display("logic variable v2 = %d", v2);
v1 = v2;
$display("bit variable v1 = %d", v1);
v2 = 'b0;
$display("logic variable v2 = %d", v2);
v1 = v2;
$display("bit variable v1 = %d", v1);
v2 = 'bx;
$display("logic variable v2 = %d", v2);
v1 = v2;
$display("bit variable v1 = %d", v1);
v2 = 'bz;
$display("logic variable v2 = %d", v2);
v1 = v2;
$display("bit variable v1 = %d", v1);
end
// TODO-3: enum type
initial begin: enum_type
typedef enum {IDLE, START, PROC, END} state_t;
state_t st1, st2;
wait(b_enum_type == 1); $display("enum_type process block started");
st1 = IDLE;
$display("st1 value = %0d (int)", st1);
$display("st1 value = %s (string)", st1); // implicit conversion
$display("st1 value = %s (string)", st1.name());
st2 = state_t'(1);
$display("st1 value = %0d (int)", st2);
$display("st1 value = %s (string)", st2.name());
end
// TODO-4: struct type
initial begin: struct_type
typedef struct {
bit[7:0] addr;
bit[31:0] data;
bit is_write;
int id;
} trans_t;
trans_t t1, t2, t3;
wait(b_struct_type == 1); $display("struct_type process block started");
t1 = '{'h10, 'h1122_3344, 'b1, 'h1000};
$display("t1 data content is %p", t1);
t2.addr = 'h20;
t2.data = 'h5566_7788;
t2.is_write = 'b0;
t2.id = 'h2000;
$display("t2 data content is %p", t2);
t3 = t2;
t3.data = 'h99AA_BBCC;
t3.id = 'h3000;
$display("t3 data content is %p", t3);
$display("t2 data content is %p", t2);
end
endmodule
字符串类型
构建字符串和字符串拼接 (一般常用$sformatf函数)
module string_type;
bit b_string_format = 1;
bit b_string_builtin_function = 1;
// TODO-1 understand how to formulate a new string
initial begin: string_format
string s1, s2, s3, s4;
wait(b_string_format == 1);$display("string_format process block started");
s1 = "Welcome";
s2 = "www.rockeric.com";
s3 = {s1, " to ", s2}; // concatenation operator '{...}'
$display("s3 content: %s", s3);
s4 = $sformatf("%s to %s", s1, s2); // system format function
$display("s4 content: %s", s4);
end
// TODO-2 understand how s3 is composed with s1 and s2
initial begin: string_builtin_function
string s1, s2, s3;
int i1;
wait(b_string_builtin_function == 1); $display("string_builtin_function process block started");
s1 = "RockerIC is established in ";
i1 = 2015;
s2.itoa(i1); // integer converted to string
s3 = {s1.len()+s2.len(){" "}}; // try to comment this line and check the result
for(int i=0; i<s1.len()+s2.len(); i++) begin
s3[i] = i < s1.len() ? s1[i] : s2[i-s1.len()];
end
$display("s3 content: %s", s3);
end
endmodule
数组类型
合并非合并、赋值与循环、动态数组、队列、关联数组
module array_type;
bit b_unpacked_vs_packed = 1;
bit b_array_assigment_and_loop = 1;
bit b_dynamic_array = 1;
bit b_queue_use = 1;
bit b_associate_array = 1;
// TODO-1 learn the difference between unpacked and packed data storage and
// assignment
initial begin: unpacked_vs_packed
bit [7:0] unpacked_word [3:0];
bit [3:0] [7:0] packed_word;
wait(b_unpacked_vs_packed == 1); $display("unpacked_vs_packed process block started");
// legal assignment
unpacked_word[0] = 10;
unpacked_word[1] = 32;
unpacked_word[2] = 54;
unpacked_word[3] = 76;
$display("unpacked_word = %p", unpacked_word);
// legal assignment with '{}
unpacked_word = '{76, 54, 32, 10};
$display("unpacked_word = %p", unpacked_word);
// legal assignment
packed_word[0] = 10;
packed_word[1] = 32;
packed_word[2] = 54;
packed_word[3] = 76;
$display("packed_word = %p", packed_word);
// legal assignment with {} but without '
packed_word = {76, 54, 32, 10};
$display("packed_word = %p", packed_word);
// legal assignment directly like a vector packedt_word[31:0]
packed_word = (76<<24) + (54<<16) + (32<<8) + 10;
$display("packed_word = %p", packed_word);
// illegal assignment
// packed_word = unpacked_word [X]
// unpacked_word = packed_word [X]
// illegal assignment between packed and unpacked array
foreach(packed_word[i])
packed_word[i] = unpacked_word[i];
foreach(unpacked_word[i])
unpacked_word[i] = packed_word[i];
end
// TODO-2 learn the array assignment and foreach loop indexing method
initial begin: array_assigment_and_loop
integer sum [4][2]; // 8*4 size array
wait(b_array_assigment_and_loop == 1); $display("array_assigment_and_loop process block started");
// concatenation and default value
sum = '{0:'{'h21, 'h43}, default:'{default:'x}};
// foreach loop indexing
foreach(sum[i, j]) begin
$display("sum[%0d][%0d] = 'h%0x", i, j, sum[i][j]);
end
end
// TODO-3 learn the dynamic array basics
initial begin: dynamic_array
int dyn1[], dyn2[];
wait(b_dynamic_array == 1); $display("dynamic_array process block started");
dyn1 = '{1, 2, 3, 4};
$display("dyn1 = %p", dyn1);
// copp method option-1
dyn2 = dyn1;
$display("dyn2 = %p", dyn2);
$display("dyn2 size is %0d", dyn2.size());
// copp method option-2
dyn2 = new[dyn1.size()](dyn1);
$display("dyn2 = %p", dyn2);
$display("dyn2 size is %0d", dyn2.size());
dyn2.delete();
$display("dyn2 size is %0d", dyn2.size());
end
// TODO-4: learn queue use
initial begin: queue_use
int que1[$], que2[$];
wait(b_queue_use == 1); $display("queue_use process block started");
que1 = {10, 30, 40};
$display("que1 = %p", que1);
que2 = que1;
$display("que2 = %p", que1);
que1.insert(1, 20);
$display("que1 = %p", que1);
que1.delete(3); // delete que1[3]==40
void'(que1.pop_front()); // pop que[0]==10
$display("que1 = %p", que1);
que1.delete();
$display("que1 = %p", que1);
end
// TODO-5 learn associate array use
initial begin: associate_array
int id_score1[int], id_score2[int]; // key ID, value SCORE
wait(b_associate_array == 1); $display("associate_array process block started");
id_score1[101] = 111;
id_score1[102] = 222;
id_score1[103] = 333;
id_score1[104] = 444;
id_score1[105] = 555;
// associate array copy
id_score2 = id_score1;
id_score2[101] = 101;
id_score2[102] = 102;
id_score2[103] = 103;
id_score2[104] = 104;
id_score2[105] = 105;
foreach(id_score1[id]) begin
$display("id_score1[%0d] = %0d", id, id_score1[id]);
end
foreach(id_score2[id]) begin
$display("id_score2[%0d] = %0d", id, id_score2[id]);
end
end
endmodule
接口的定义与例化
接口里也可以定义方法
// TODO-1 understand how the interface is defined and instantied
// TODO-2 check how to define methods inside interface and call them internally or externally
// TODO-3 understand how to prepare transactions, drive them and monitor them
module interface_type;
typedef struct {
bit[7:0] addr;
bit[31:0] data;
bit write;
int id;
} trans_t;
// struct print utility function
function void trans_print(trans_t t, string name = "trans");
string s;
s = $sformatf("%s struct content is as below \n", name);
s = $sformatf("%s\taddr = 'h%2x \n", s, t.addr);
s = $sformatf("%s\tdata = 'h%8x \n", s, t.data);
s = $sformatf("%s\twrite = 'b%0b \n", s, t.write);
s = $sformatf("%s\tid = 'h%8x \n", s, t.id);
$display("%s", s);
endfunction
interface intf1;
logic [7:0] addr;
logic [31:0] data;
logic write;
int id;
// transaction drive task
task drive_trans(trans_t t);
addr <= t.addr ;
data <= t.data ;
write <= t.write;
id <= t.id ;
endtask
// transaction monitor task
task mon_trans(output trans_t t);
t.addr = addr ;
t.data = data ;
t.write = write;
t.id = id ;
endtask
endinterface
// interface instantiation
intf1 if1();
initial begin
trans_t trans_in[3], trans_mon[3];
// stimulus preparation
trans_in = '{'{'h10, 'h1122_3344, 'b1, 'h1000}
,'{'h14, 'h5566_7788, 'b0, 'h1001}
,'{'h18, 'h99AA_BBCC, 'b1, 'h1002}
};
foreach(trans_in[i]) begin
#10;
// stimulus drive
if1.drive_trans(trans_in[i]);
trans_print(trans_in[i], $sformatf("trans_in[%0d]",i));
#10;
// stimulus monitor
if1.mon_trans(trans_mon[i]);
trans_print(trans_mon[i], $sformatf("trans_mon[%0d]",i));
// transaction comparison
if(trans_in[i] === trans_mon[i])
$display("trans_in[%0d] === trans_mon[%0d]", i, i);
else
$error("trans_in[%0d] !== trans_mon[%0d]", i, i);
end
end
endmodule
类的封装
module class_encapsulation;
bit b_object_instantiation = 1;
class chnl_trans;
bit[31:0] data[];
int ch_id;
int pkt_id;
int data_nidles;
int pkt_nidles;
bit rsp;
int obj_id;
static int global_obj_id = 0;
function new();
global_obj_id++;
obj_id = global_obj_id;
endfunction
function chnl_trans clone();
chnl_trans c = new();
c.data = this.data;
c.ch_id = this.ch_id;
c.pkt_id = this.pkt_id;
c.data_nidles = this.data_nidles;
c.pkt_nidles = this.pkt_nidles;
c.rsp = this.rsp;
return c;
endfunction
function string sprint();
string s;
s = {s, $sformatf("obj_id = %0d: \n", this.obj_id)};
foreach(data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, this.data[i])};
s = {s, $sformatf("ch_id = %0d: \n", this.ch_id)};
s = {s, $sformatf("pkt_id = %0d: \n", this.pkt_id)};
s = {s, $sformatf("data_nidles = %0d: \n", this.data_nidles)};
s = {s, $sformatf("pkt_nidles = %0d: \n", this.pkt_nidles)};
s = {s, $sformatf("rsp = %0d: \n", this.rsp)};
return s;
endfunction
endclass: chnl_trans
// TODO-1 learn the object instantiation
// TODO-2 learn the handle pointting to an object
// TODO-3 learn the class function clone()/sprint()
// TODO-4 compare if t1, t2 and t3 are pointting to the same object?
// TODO-5 check if the t1 pointted object data is exactly the same with the t3
// pointted object?
// TODO-6 learn how to call STATIC member variable/function, and their
// difference with local member variable/function
initial begin: object_instantiation
chnl_trans t1, t2, t3;
wait(b_object_instantiation == 1); $display("b_object_instantiation process block started");
t1 = new();
t1.data = '{1, 2, 3, 4};
t1.ch_id = 2;
t1.pkt_id = 100;
t2 = t1;
$display("t1 object content is as below:\n%s", t1.sprint());
$display("t2 object content is as below:\n%s", t2.sprint());
t3 = t1.clone();
$display("t3 object content is as below:\n%s", t3.sprint());
$display("t1 object ID is [%0d]", t1.obj_id);
$display("t2 object ID is [%0d]", t2.obj_id);
$display("t3 object ID is [%0d]", t3.obj_id);
$display("the latest chnl_trans object iD is [%0d]", chnl_trans::global_obj_id);
end
endmodule
类的继承
module class_inheritance;
bit b_member_override = 1;
class trans;
bit[31:0] data[];
int pkt_id;
int data_nidles;
int pkt_nidles;
bit rsp;
function trans clone(trans t = null);
if(t == null) t = new();
t.data = data;
t.pkt_id = pkt_id;
t.data_nidles = data_nidles;
t.pkt_nidles = pkt_nidles;
t.rsp = rsp;
return t;
endfunction
endclass
class chnl_trans extends trans;
int ch_id; // new member in child class
// member function override with
// same function name, arguments, and return type
// TODO-1 seperately enable the clone function-1 and function-2, and check
// if both of them works, and compare which is better, and why?
// clone function-1
function trans clone(trans t = null);
chnl_trans ct;
if(t == null)
ct = new();
else
void'($cast(ct, t));
ct.data = data;
ct.pkt_id = pkt_id;
ct.data_nidles = data_nidles;
ct.pkt_nidles = pkt_nidles;
ct.rsp = rsp;
ct.ch_id = ch_id; // new member
return ct;
endfunction
// clone function-2
// function trans clone(trans t = null);
// chnl_trans ct;
// if(t == null)
// ct = new();
// else
// void'($cast(ct, t));
// void'(super.clone(ct));
// ct.ch_id = ch_id; // new member
// return ct;
// endfunction
endclass
initial begin: member_override
trans t1, t2;
chnl_trans ct1, ct2;
wait(b_member_override == 1); $display("b_member_override process block started");
ct1 = new();
ct1.pkt_id = 200;
ct1.ch_id = 2;
// t1 pointed to ct1's trans class data base
t1 = ct1;
// t2 copied ct1's trans class data base
t2 = ct1.clone();
void'($cast(ct2, t2));
// TODO-2 why could not clone t1(->ct1) to t2?
// t2 = t1.clone(); // ERROR clone call
// void'($cast(ct2, t2));
$display("ct1.pkt_id = %0d, ct1.ch_id = %0d", ct1.pkt_id, ct1.ch_id);
// TODO-3 uncomment the statement below and consider
// why t1 could not point to ct1.ch_id?
// $display("ct1.pkt_id = %0d, ct1.ch_id = %0d", t1.pkt_id, t1.ch_id);
$display("ct2.pkt_id = %0d, ct2.ch_id = %0d", ct2.pkt_id, ct2.ch_id);
end
endmodule
package的使用
package sky_pkg;
class sun;
typedef enum {RISE, FALL} state_e;
state_e state = RISE;
endclass
sun apollo = new();
class cloud;
endclass
endpackage
package sea_pkg;
class fish;
endclass
class island;
string name;
function new(string name = "island");
this.name = name;
endfunction
endclass
island hainan = new("hainan");
endpackage
module package_usage;
import sky_pkg::cloud;
import sea_pkg::*;
import sea_pkg::hainan;
// TODO-2 why hainan could not be delcared here?
// island hainan;
initial begin
// TODO-1 why sun type is not recognized? how to make it recognizable?
// sun s;
// TODO-2 why hainan could be declared here?
island hainan;
// TODO-3 why apollo is not recognized?
// $display("sun state is %s", apollo.state);
hainan = new("HAINAN");
$display("hainan name is %s", hainan.name);
$display("sea_pkg::hainan name is %s", sea_pkg::hainan.name);
end
endmodule
随机约束
module constrained_random;
bit b_system_random_func = 1;
bit b_class_randomization = 1;
// TODO-1 understand how to use system random function, and its advanced
// method such as to generate unique values
initial begin: system_random_func
int unsigned rval;
int unsigned gen_vals[$];
wait(b_system_random_func == 1); $display("b_system_random_func process block started");
// randomize 10 times, and each rand value doesnot care previous generated
// value
repeat(10) begin
rval = $urandom_range(0, 9);
$display("$urandom_range(0, 9) generated rand value is %0d", rval);
end
// Do you have other ways to generate unique number each time which should
// not be duplicated with previously generate ones?
repeat(10) begin
$display("gen_vals queue content is %p", gen_vals);
std::randomize(rval) with {foreach(gen_vals[i]) rval != gen_vals[i]; rval inside {[0:9]};};
gen_vals.push_back(rval);
$display("std::randomize with inline constrait generated rand value %0d", rval);
end
end
class chnl_trans;
rand bit[31:0] data[];
rand int ch_id;
rand int pkt_id;
rand int data_nidles;
rand int pkt_nidles;
bit rsp;
constraint cstr{
data.size inside {[4:8]};
foreach(data[i]) data[i] == 'hC000_0000 + (this.ch_id<<24) + (this.pkt_id<<8) + i;
ch_id == 1;
pkt_id == 1;
data_nidles inside {[0:2]};
pkt_nidles inside {[1:10]};
};
endclass
// TODO-2 learn basic constraint format, class randomization method, soft
// constraint, and how to avolid constraint conflict?
initial begin: class_randomization
chnl_trans ct1, ct2;
wait(b_class_randomization == 1); $display("b_class_randomization process block started");
ct1 = new();
// is ct1 already randomized?
$display("ct1.data.size = %0d, ct1.ch_id = %0d, ct1.pkt_id = %0d", ct1.data.size(), ct1.ch_id, ct1.pkt_id);
ct2 = new();
// is ct2 already randomized?
$display("ct2.data.size = %0d, ct2.ch_id = %0d, ct2.pkt_id = %0d", ct2.data.size(), ct2.ch_id, ct2.pkt_id);
// why ct2.ch_id and ct2.pkt_id kept the same number even though it has been
// randomized several times?
repeat(5) begin
void'(ct2.randomize());
$display("ct2.data.size = %0d, ct2.ch_id = %0d, ct2.pkt_id = %0d", ct2.data.size(), ct2.ch_id, ct2.pkt_id);
end
// the randomization with inline constraint would meets randomization
// failure, how to modify?
// if(!ct1.randomize() with {ch_id == 2;})
// $error("ct1 randomization failure!");
// else
// $display("ct1.data.size = %0d, ct1.ch_id = %0d, ct1.pkt_id = %0d", ct1.data.size(), ct1.ch_id, ct1.pkt_id);
end
endmodule
线程的同步
module thread_sync;
bit b_event_use = 0;
bit b_mailbox_use = 1;
bit b_mailbox_user_define = 1;
// TODO-1.1 event does not new()
// TODO-1.2 learn event copy (direct assignment between two events)
// TODO-1.3 compare @ operator and triggered() method
initial begin: event_use
event e1, e2, e3a, e3b;
wait(b_event_use == 1); $display("b_event_use process block started");
e3b = e3a; // event copy, e3b and e3a are the same event
->e1; // trigger e1 before @e1;
->e2; // trigger e2 before e2.triggered();
fork
begin @e1; $display("@%0t, @e1 finished" , $time); end
begin wait(e2.triggered()); $display("@%0t, wait(e2.triggered()) finished" , $time); end
begin @e3a; $display("@%0t, @e3a finished", $time); end
begin @e3b; $display("@%0t, @e3b finished", $time); end
join_none
#10ns;
-> e3a;
#10ns;
-> e1; // trigger e1 again
end
class box;
int id;
function new(int id);
this.id = id;
endfunction
endclass
// TODO-2 learn the parameterized mailbox and general storage method
initial begin: mailbox_use
mailbox #(int) mb_id;
mailbox #(box) mb_handle;
box bx[5];
wait(b_mailbox_use == 1); $display("b_mailbox_use process block started");
// mailbox need new(N) for instantiation
mb_id = new();
mb_handle = new();
// mailbox storage
foreach(bx[i]) begin
bx[i] = new(i);
mb_id.put(i);
mb_handle.put(bx[i]);
end
$display("box handles array bx content is %p", bx);
// mailbox extraction
$display("extracting ID and HANDLE from the TWO mailboxes");
repeat(mb_id.num()) begin
int id;
box handle;
mb_id.get(id);
mb_handle.get(handle);
$display("ID:%0d, HANDLE:%p", id, handle);
end
// check mailbox size
$display("ID mailbox size is %0d", mb_id.num());
$display("HANDLE mailbox size is %0d", mb_handle.num());
end
// TODO-3 learn how to maximal utilize the mailbox storage with user defined
// type, we modify the 'mailbox_use' block and give a new block
// 'mailbox_user_define'
typedef struct{
int id;
box handle;
} mb_pair_element_t;
initial begin: mailbox_user_define
mailbox #(mb_pair_element_t) mb_pair;
box bx[5];
wait(b_mailbox_user_define == 1); $display("b_mailbox_user_define process block started");
// mailbox need new(N) for instantiation
mb_pair = new();
// mailbox storage
foreach(bx[i]) begin
bx[i] = new(i);
mb_pair.put('{i, bx[i]});
end
$display("box handles array bx content is %p", bx);
// mailbox extraction
$display("extracting ID and HANDLE from the ONE mailbox");
repeat(mb_pair.num()) begin
mb_pair_element_t pair;
mb_pair.get(pair);
$display("ID:%0d, HANDLE:%p", pair.id, pair.handle);
end
// check mailbox size
$display("PAIR mailbox size is %0d", mb_pair.num);
end
endmodule
线程的控制
module thread_control;
bit b_fork_join = 1;
bit b_fork_join_any = 0;
bit b_fork_join_none = 0;
class box;
int id;
function new(int id);
this.id = id;
endfunction
endclass
box bx[3];
task automatic thread(int id = 1, int t = 10);
$display("@%0t, thread id:%0d entered", $time, id);
bx[id] = new(id); // allocate space
#(t*1ns);
bx[id] = null; // deallocate space
$display("@%0t, thread id:%0d exited", $time, id);
endtask
// TODO-1 learn fork-join thread exited when all sub-thread exit.
initial begin: fork_join
wait(b_fork_join == 1); $display("b_fork_join process block started");
bx = '{null, null, null};
$display("@%0t, fork_join_thread entered", $time);
fork: fork_join_thread
thread(0, 10);
thread(1, 20);
thread(2, 30);
join
$display("@%0t, fork_join_thread exited", $time);
$display("@%0t, box handles array is %p", $time, bx);
#10;
b_fork_join = 0;
b_fork_join_any = 1;
end
// TODO-2.1 learn fork-join_any thread exited when just one sub-thread exites,
// but all other sub-thread are still running.
// TODO-2.2 learn disable BLOCK/fork statement, and check if the running
// sub-threads haven been disabled.
initial begin: fork_join_any
wait(b_fork_join_any == 1); $display("b_fork_join_any process block started");
bx = '{null, null, null};
$display("@%0t, fork_join_any_thread entered", $time);
fork: fork_join_any_thread
thread(0, 10);
thread(1, 20);
thread(2, 30);
join_any
$display("@%0t, fork_join_any_thread exited", $time);
$display("@%0t, box handles array is %p", $time, bx);
disable fork_join_any_thread;
$display("@%0t, disabled fork_join_any_thread", $time);
#100ns;
$display("@%0t, box handles array is %p", $time, bx);
#10ns;
b_fork_join_any = 0;
b_fork_join_none = 1;
end
// TODO-3.1 learn fork-join_none thread exited directly without calling any
// sub-thread, and continue executing other statements. Then the
// fork-join_none sub-threads would be still running.
// TODO-3.2 learn the wait fork statement, and check the time after it is
// satisified. The time should be the point when all fork sub-thread finished.
initial begin: fork_join_none
wait(b_fork_join_none == 1); $display("b_fork_join_none process block started");
bx = '{null, null, null};
$display("@%0t, fork_join_none_thread entered", $time);
fork: fork_join_none_thread
thread(0, 10);
thread(1, 20);
thread(2, 30);
join_none
$display("@%0t, fork_join_none_thread exited", $time);
$display("@%0t, box handles array is %p", $time, bx);
#15ns;
$display("@%0t, box handles array is %p", $time, bx);
wait fork;
$display("@%0t, fork_join_none_thread's all sub-threads finished", $time);
$display("@%0t, box handles array is %p", $time, bx);
end
endmodule
虚方法
// This example is referred to the lec2/class_inheritance
// The purpose is to learn the convenience of virtual method
module virtual_methods;
class trans;
bit[31:0] data[];
int pkt_id;
int data_nidles;
int pkt_nidles;
bit rsp;
virtual function trans clone(trans t = null);
if(t == null) t = new();
t.data = data;
t.pkt_id = pkt_id;
t.data_nidles = data_nidles;
t.pkt_nidles = pkt_nidles;
t.rsp = rsp;
return t;
endfunction
endclass
class chnl_trans extends trans;
int ch_id; // new member in child class
virtual function trans clone(trans t = null);
chnl_trans ct;
if(t == null)
ct = new();
else
void'($cast(ct, t));
void'(super.clone(ct));
ct.ch_id = ch_id; // new member
return ct;
endfunction
endclass
initial begin
trans t1, t2;
chnl_trans ct1, ct2;
ct1 = new();
ct1.pkt_id = 200;
ct1.ch_id = 2;
// t1 pointed to ct1's trans class data base
t1 = ct1;
$display("before cloning ct1 object");
$display("ct1.pkt_id = %0d, ct1.ch_id = %0d", ct1.pkt_id, ct1.ch_id);
// TODO-1 compare with lec2/class_inheritance TODO-2
// why it is legal to call t1.clone() here?
// TODO-2 via this example, please summarize the virtual method
// convenience
t2 = t1.clone();
void'($cast(ct2, t2));
// TODO-3 to access ct2.ch_id, could we directly use t2.ch_id?
// is it possible to add modified virtual before chnl_trans::ch_id, and
// then access it by 't2.ch_id'? and why?
$display("after cloning ct1 object");
$display("ct1.pkt_id = %0d, ct1.ch_id = %0d", ct1.pkt_id, ct1.ch_id);
$display("ct2.pkt_id = %0d, ct2.ch_id = %0d", ct2.pkt_id, ct2.ch_id);
end
endmodule
方法(任务与函数)
module task_and_function;
bit b_function_define = 1;
bit b_task_define = 1;
bit b_inout_vs_ref = 1;
function int double_f0(int a);
return 2*a;
endfunction
function void double_f1(input int a, output int b);
b = 2*a;
endfunction
function void double_f2(inout int a);
a = 2*a;
endfunction
function automatic void double_f3(ref int a);
a = 2*a;
endfunction
task double_t1(input int a, output int b);
b = 2*a;
endtask
task double_t2(inout int a);
a = 2*a;
endtask
task automatic double_t3(ref int a);
a = 2*a;
endtask
task double_t2_delay(inout int a);
a = 2*a;
#10ns;
endtask
task automatic double_t3_delay(ref int a);
a = 2*a;
#10ns;
endtask
// TODO-1 lear the function definition possible ways
initial begin: function_define
int v1, v2;
wait(b_function_define == 1); $display("b_function_define process block started");
v1 = 10;
v2 = double_f0(v1);
$display("v1 = %0d, double function result is %0d", v1, v2);
v1 = 10;
double_f1(v1, v2);
$display("v1 = %0d, double function result is %0d", v1, v2);
v1 = 10;
$display("v1 is %0d before calling double_f2(v1)", v1);
double_f2(v1);
$display("v1 is %0d (result) after calling double_f2(v1)", v1);
v1 = 10;
$display("v1 is %0d before calling double_f3(v1)", v1);
double_f3(v1);
$display("v1 is %0d (result) after calling double_f3(v1)", v1);
end
// TODO-2 learn the task definition possible ways
initial begin: task_define
int v1, v2;
wait(b_task_define == 1); $display("b_task_define process block started");
v1 = 10;
double_t1(v1, v2);
$display("v1 = %0d, double task result is %0d", v1, v2);
v1 = 10;
$display("v1 is %0d before calling double_t2(v1)", v1);
double_t2(v1);
$display("v1 is %0d (result) after calling double_t2(v1)", v1);
v1 = 10;
$display("v1 is %0d before calling double_t3(v1)", v1);
double_t3(v1);
$display("v1 is %0d (result) after calling double_t3(v1)", v1);
end
// TODO-3 compare the inout and ref argument between function and task use
initial begin: inout_vs_ref
int v1, v2;
wait(b_inout_vs_ref == 1); $display("b_inout_vs_ref process block started");
v1 = 10;
$display("v1 is %0d before calling double_t2_delay(v1)", v1);
fork
double_t2_delay(v1);
begin #5ns; $display("@%0t v1 = %0d in task call double_t2_delay(v1)", $time, v1); end
join
$display("v1 is %0d (result) after calling double_t2_delay(v1)", v1);
v1 = 10;
$display("v1 is %0d before calling double_t3_delay(v1)", v1);
fork
double_t3_delay(v1);
begin #5ns; $display("@%0t v1 = %0d in task call double_t3_delay(v1)", $time, v1); end
join
$display("v1 is %0d (result) after calling double_t3_delay(v1)", v1);
end
endmodule
SV用于设计
module sv_for_design;
bit b_always_compare = 1;
bit b_compare_operator = 1;
bit b_inside_operator = 1;
bit b_case_statement = 1;
// TODO-1 why l2 != l3 at time 0 ?
logic l1 = 0, l2, l3;
always @(l1) l2 <= l1;
always_comb l3 = l1;
initial begin: always_compare
wait(b_always_compare == 1); $display("always_compare process block started");
#0;
$display("@%0t, l2 = %b", $time, l2);
$display("@%0t, l3 = %b", $time, l3);
#10;
l1 <= 1;
#1;
$display("@%0t, l2 = %b", $time, l2);
$display("@%0t, l3 = %b", $time, l3);
end
// TODO-2 learn the compare operators' difference
initial begin: compare_operator
logic [3:0] v1, v2;
wait(b_compare_operator == 1); $display("compare_operator process block started");
v1 = 'b111x;
v2 = 'b1110;
if(v1 != v2) // binary logical equality operator
$display("v1 %b != v2 %b", v1, v2);
else
$display("v1 %b == v2 %b", v1, v2);
$display("the operator result (v1 != v2) is %b", (v1 != v2));
if(v1 !== v2) // binary case equality operator
$display("v1 %b !== v2 %b", v1, v2);
else
$display("v1 %b === v2 %b", v1, v2);
$display("the operator result (v1 !== v2) is %b", (v1 !== v2));
end
// TODO-3 learn the inside operator
initial begin: inside_operator
bit [2:0] v1;
wait(b_inside_operator == 1); $display("inside_operator process block started");
v1 = 'b100;
if(v1 == 'b100 || v1 == 'b010 || v1 == 'b001)
$display("v1: %0b meets onehot vector requirement!", v1);
else
$display("v1: %0b does not meet onehot vector requirement!", v1);
if(v1 inside {'b100, 'b010, 'b001})
$display("v1: %0b meets onehot vector requirement!", v1);
else
$display("v1: %0b does not meet onehot vector requirement!", v1);
if($onehot(v1) == 1)
$display("v1: %0b meets onehot vector requirement!", v1);
else
$display("v1: %0b does not meet onehot vector requirement!", v1);
end
// TODO-4 learn {unique, priority} case{ ,x, z} statement
initial begin: case_statement
parameter width_p = 4;
bit [width_p-1:0] v_arr[3];
wait(b_case_statement == 1); $display("case_statement process block started");
v_arr = '{'b1000, 'b1111, 'b0110};
foreach(v_arr[i]) begin
unique case(v_arr[i])
'b0001, 'b0010, 'b0100, 'b1000: $display("v1: %0b meets onehot vector requirement!", v_arr[i]);
0: $display("v1: %0b is ZERO", v_arr[i]);
'b1111: $display("v1: %0b is ALL ONES", v_arr[i]);
default: $display("v1: %0b has [2~%0d] ones", v_arr[i], width_p-1);
endcase
end
end
endmodule