SV学习笔记(八)

简介: SV学习笔记(八)


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

参考资料

目录
相关文章
|
1月前
|
存储 自然语言处理 Java
SV学习笔记(三)
SV学习笔记(三)
41 1
|
1月前
|
存储 自然语言处理 测试技术
SV学习笔记(一)
SV学习笔记(一)
36 1
|
1月前
|
测试技术 Shell Windows
SV学习笔记(二)
SV学习笔记(二)
34 0
|
1月前
|
存储 编译器 C++
SV学习笔记(七)
SV学习笔记(七)
58 0
|
1月前
|
消息中间件 存储 安全
SV学习笔记(六)
SV学习笔记(六)
47 0
|
1月前
|
Java 关系型数据库 测试技术
SV学习笔记(四)
SV学习笔记(四)
39 0
【SV】记录UVM/SV使用过程中遇到的生僻知识点
【SV】记录UVM/SV使用过程中遇到的生僻知识点
78 0
【SV 基础】queue 的一些用法
【SV 基础】queue 的一些用法
1007 0
|
安全 网络协议 网络安全
|
机器学习/深度学习 Unix Shell