SV入门练习
基本数据类型
- 有符号无符号、四状态双状态、枚举类型、结构体
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