2011年5月7日 星期六

Systemverilog與C變數對照表

SystemVerilog Type
C Type
byte char
int int
longint long long
shortint short int
real double
shortreal float
chandle void*
string char*

DPI再了解(九)

Chandle data type

The chandle data type represents storage for pointers passed using the DPI
The chandle data type allows you to store a C or C++ pointer in your SystemVerilog code. A chandle variable is wide enough to hold a pointer on the machine where the code was compiled, i.e. 32- or 64-bits.

The syntax to declare a handle is as follows:
chandle variable_name ; 

where variable_name is a valid identifier. Chandles shall always be initialized to the value null, which has  a  value  of  0  on  the  C  side.  Chandles  are  restricted  in  their  usage,  with  the  only  legal  uses  being  as follows:

Only the following operators are valid on chandle variables:
—  Equality (==), inequality (!=) with another chandle or with null 
—  Case  equality  (===),  case  inequality  (!==)  with  another  chandle  or  with  null  (same semantics as == and !=)

Only the following assignments can be made to a chandle:
—     Assignment from another chandle
—     Assignment to null

Chandles can be inserted into associative arrays , but the relative ordering of any two
entries in such an associative array can vary, even between successive runs of the same tool.

Chandles can be used within a class.
—     Chandles can be passed as arguments to subroutines.
—     Chandles can be returned from functions

Chandles shall not be used as follows:
—     In any expression other than as permitted in this subclause
—     As ports
—     In sensitivity lists or event expressions
—     In continuous assignments
—     In untagged unions
—     In packed types

就是說chandle只能當作pointer, 而不能當作一般變數來用

 請參考表格

Operation C pointer SV object
handle
SV chandle
Arithmetic operations (such as incrementing)  Allowed Not Allowed Not Allowed
For arbitrary data types Allowed Not Allowed Not Allowed
Dereference when null Error Not Allowed Not Allowed
Casting Allowed Limited Not Allowed
Assignment to an address of a data type Allowed
 
Not Allowed
 
Not Allowed
 
Unreferenced objects are garbage collected No Yes No
Default value Undefined Null Null
For classes (C++) Allowed Not Allowed
 



從書上剪下的例子
#include <svdpi.h>
#include <malloc.h>
#include <veriuser.h>
typedef struct {  // Structure to hold counter value
  unsigned char cnt;
} c7;
// Construct a counter structure
void* counter7_new() {
  c7* c = (c7*) malloc(sizeof(c7));
  c->cnt = 0;
  return c;
}
// Run the counter for one cycle
void counter7(c7 *inst,
              svBitVecVal* count,
              const svBitVecVal* i,
              const svBit reset,
              const svBit load) {
  if (reset)     inst->cnt = 0;  // Reset
  else if (load) inst->cnt = *i; // Load value
  else           inst->cnt++;    // Count
  inst->cnt &= 0x7f;             // Mask upper bit
  *count = inst->cnt;            // Write to output
  io_printf("C: count=%d, i=%d, reset=%d, load=%d\n",
            *count, *i, reset, load);
}

import "DPI-C" function chandle counter7_new();
import "DPI-C" function void counter7
      (input chandle inst,
       output bit [6:0] out,
       input  bit [6:0] in,
       input  bit  reset, load);

program automatic test;
// Test two instances of the counter
  initial begin
    bit [6:0] o1, o2, i1, i2;
    bit       reset, load, clk1;
    chandle   inst1, inst2;     // Points to storage in C
    inst1 = counter7_new();
    inst2 = counter7_new();
    fork
      forever #10 clk1 = ~clk1;
      forever @(posedge clk1) begin
        counter7(inst1, o1, i1, reset, load); // 傳入所配置的記憶體位址
        counter7(inst2, o2, i2, reset, load);
      end
    join_none
    reset = 0;
    load = 0;
    i1 = 120;
    i2 = 10;
    @(negedge clk1);
    load = 1;
    @(negedge clk1);
    load = 0;
    ...
  end
endprogram

 另一個書上的例子

import "DPI-C" function chandle counter7_new();
import "DPI-C" function void counter7_count(input chandle inst);
import "DPI-C" function void counter7_load(input chandle inst,
                                           input bit [6:0] i);
import "DPI-C" function void counter7_reset(input chandle inst);
import "DPI-C" function int counter7_get(input chandle inst);
// Wrap the counter interface with a class
// to hide the C++ instance handle
class Counter7;
   chandle inst;
   function new;
      inst = counter7_new();
   endfunction
   function void count();
      counter7_count(inst);
   endfunction
   function void load(bit [6:0] val);
      counter7_load(inst, val);
   endfunction
   function void reset();
      counter7_reset(inst);
   endfunction
   function bit [6:0] get();
      return counter7_get(inst);
   endfunction
endclass : Counter7

2011年5月6日 星期五

DPI再了解(八)

DPI long  常數資料的傳送
從VCS的example整理出來的

module main();
    longint i1;
   
    import "DPI" function void mydisplay(inout longint i1);
    initial begin
        i1=64'h1234_5678_9000;
        $display("SV: i1 is %0h",i1);
        mydisplay(i1);
        $display("SV(after DPI call): i1 is %0h",i1);
    end

endmodule

#include "svdpi.h"
//#include "vcsuser.h"

#include <stdlib.h>
#include <stdio.h>

extern "C" {
    void mydisplay(long long *i1) {
        printf("C: size of long long is %0d bytes\n",sizeof(long long));
        printf("C: i1 is %llx\n",*i1);
        (*i1) = (*i1) * 2;   
        printf("C: change i1 to %llx\n",*i1);
       
    }
}

SVA 再了解(一)

這是一個簡單的 SVA測試例
關於sequence 及property的用法

module test;

reg clk, rst_n;

wire ph1, ph2, ph3;

reg [1:0] ph_fsm;

reg vsync, vsync_d, vsync_start;

reg [9:0] ph1_cnt, ph2_cnt, ph3_cnt;

reg [7:0] phase_loop_cnt;
wire phase_loop_end;

parameter ph1_value =10;
parameter ph2_value =15;
parameter ph3_value =35;

always #5 clk = ~clk;

initial begin
clk =0;
vsync = 0;
rst_n =1;
#100;
rst_n =0;
#100;
rst_n =1;

@(posedge phase_loop_end)
vsync =1;

@(posedge phase_loop_end)
vsync =0;

end

always @(posedge clk or negedge rst_n) begin
if (~rst_n)
ph_fsm <=0;
else begin
if (ph_fsm ==0)
ph_fsm = 1;
else if (ph_fsm == 1 && ph1_cnt == ph1_value)
ph_fsm =2;
else if (ph_fsm == 2 && ph2_cnt == ph2_value)
ph_fsm =3;
else if (ph_fsm == 3 && ph3_cnt == ph3_value)
ph_fsm =1;
else
ph_fsm = ph_fsm;

end
end

assign phase_loop_end = (ph_fsm ==3 && ph3_cnt==ph3_value);

always @(posedge clk or negedge rst_n) begin
if (~rst_n)
ph1_cnt <= 1'b0;
else if(ph_fsm == 2'b01)
ph1_cnt ++;
else
ph1_cnt <= 1'b0;
end

always @(posedge clk or negedge rst_n) begin
if (~rst_n)
ph2_cnt <= 1'b0;
else if(ph_fsm == 2'b10)
ph2_cnt ++;
else
ph2_cnt <= 1'b0;
end

always @(posedge clk or negedge rst_n) begin
if (~rst_n)
ph3_cnt <= 1'b0;
else if(ph_fsm == 2'b11)
ph3_cnt ++;
else
ph3_cnt <= 1'b0;
end

assign ph1 = (ph_fsm == 2'b01);
assign ph2 = (ph_fsm == 2'b10);
assign ph3 = (ph_fsm == 2'b11);

initial begin
$fsdbDumpfile("./test.fsdb");
$fsdbDumpvars(0, test);
$fsdbDumpSVA(0, test);
end

initial begin
#1ms;
$finish;
end

sequence s_ph12_chk_seq;
@(posedge clk) ph1 [->ph1_value] ##1 ph2;
endsequence

sequence s_ph23_chk_seq;
@(posedge clk) ph2 [->ph2_value] ##1 ph3;
endsequence

sequence s_ph31_chk_seq;
@(posedge clk) ph3 [->ph3_value] ##1 ph1;
endsequence

property p_ph1231_chk1;
@(posedge clk) $rose(ph1) |-> ##ph1_value $rose(ph2) |-> ##ph2_value
$rose(ph3) |-> ##ph3_value ph1;
endproperty

property p_ph1231_chk2;
@(posedge clk) s_ph12_chk_seq |-> s_ph23_chk_seq |-> s_ph31_chk_seq;
endproperty

ph1231_chk_sva1: assert property (p_ph1231_chk1)
else begin
$display("\n Fail in ph1231 sva1\n");
#1000;
$finish;
end

ph1231_chk_sva2: assert property (p_ph1231_chk2)
else begin
$display("\n Fail in ph1231 sva2\n");
#1000;
$finish;
end

endmodule

2011年5月5日 星期四

pure_virtual

They have the same meaning as in C++. A virtual function can be overridden in a derived class. If a object of that derived class is accessed using a handle to its base class, the function call is performed polymorphically(可到需要時再定義) - the function called is determined by the type of the object pointed to, not the type of the handle (so the overridden function is called if the object pointed to is of the derived class type).

A pure virtual function is a member of an "abstract" base class. You cannot create an object of an abstract class. No implementation need be provided for the pure virtual function in the base class but it must be overridden in a derived class if you want to create objects of that type. Pure virtual functions are used to create "interface" classes (port, export…) (not to be confused with the SystemVerilog interface structure). You find examples of these in the OVM TLM classes where they are used to define the set of interface methods required by ports and provided by exports.

範例
virtual class BasePacket;
pure virtual function integer send(bit[31:0] data); // No implementation
endclass
這樣的好處在原始的base class不用特定去決定現在的function design
純粹只定義一個function 名字
到了沿用(extends)這個base class, 才去決定implement要用到的功能設計

class EtherPacket extends BasePacket;
virtual function integer send(bit[31:0] data);
// body of the function
...
endfunction
endclass

另一種定義模式的範例
pure virtual function void get_provided_to(ref uvm_port_list list);

ref 在port 上的使用

節錄一段文字, 對此有些說明


Passing by reference is like passing a pointer as the argument. When passed by reference, any change on the outside is immediately reflected inside the task.And any change made inside the task is immediately reflected out-side
Task ports can now be declared ref. A reference gives the task body direct access to the source arguments. in the caller's scope. Since it is operating on the original variable itself, rather than a copy of the argument's value, the task/function can modify variables (but not nets) in the caller's scope in realtime. The inout/output port-declarations pass variables by value, and defer updating the caller-scope variable until the moment the task exits.
也就是 ref 相當於將這個port 設成 C語言的 pointer一樣的用法
任何內外資料的改變, 會立即傳出/入 task

請參考例子

未使用ref的例子
class arbiter;
...
// This task will not work...
task request(output logic bus_rq,
             input  logic bus_gt);
   // The new value does not "flow" out
   bus_rq <= 1’b1;
   // And changes do not "flow" in
   wait bus_gt == 1’b1;
endtask: request
...
endclass: arbiter

使用ref的例子
class arbiter;
task request(ref output logic bus_rq,
             ref input  logic bus_gt);
   // The new value will "flow" out
   bus_rq <= 1’b1;
   // And changes will "flow" in
   wait bus_gt == 1’b1;
endtask: request
endclass: arbiter

另一個例子用array
因為array的資料量較大, 如果用ref可以加快模擬的速度
如果怕資料被更改, 可以使用const ref的模式,
這樣在compiler階段就會顯示出是否有問題

Sample 3.10 Passing arrays using ref and const
function void print_checksum (const ref bit [31:0] a[]);
  bit [31:0] checksum = 0;
  for (int i=0; i
    checksum ^= a[i];
  $display("The array checksum is %0d", checksum);
endfunction

Always  use  ref  when  passing  arrays  to  a  routine  for  best  perfor-
mance. If you don’t want the routine to change the array values, use
the const ref type, which causes the compiler to check that your
routine does not modify the array.

關於ref的用法在thread(fork/join)上的好處
The  second  benefit  of  ref  arguments  is  that  a  task  can  modify  a  variable  and  is
instantly seen by the calling function. This is useful when you have several threads
executing concurrently and want a simple way to pass information.
 Using ref across threads
task bus_read(input logic [31:0] addr,
              ref   logic [31:0] data);
  // Request bus and drive address
  bus.request = 1Õb1;
  @(posedge bus.grant) bus.addr = addr;
  // Wait for data from memory
  @(posedge bus.enable) data = bus.data;
  // Release bus and wait for grant
  bus.request = 1Õb0;
  @(negedge bus.grant);
endtask
logic [31:0] addr, data;
initial
  fork
    bus_read(addr, data);
    thread2: begin
      @data;  // Trigger on data change
      $display("Read %h from bus", data);
    end
  join

function也是可以使用ref的語法
function void print_checksum(ref bit [31:0] a[],
                             input bit [31:0] low = 0,
                             input int high = -1);
  bit [31:0] checksum = 0;
  if (high == -1 || high >= a.size())
    high = a.size()-1;
  for (int i=low; i<=high; i++)
    checksum += a[i];
  $display("The array checksum is %0d", sum);
endfunction

Passing an array to a function as a ref argument
function void init(ref int f[5], input int start);
  foreach (f[i])
    f[i] = i + start;
endfunction
int fa[5];
initial begin
  init(fa, 5);
  foreach (fa[i])
    $display("fa[%0d] = %0d", i, fa[i]);
end

另外在function呼叫class(object), 要使用ref
 Bad transaction creator task, missing ref on handle
function void create(Transaction tr); // Bug, missing ref
  tr = new();
  tr.addr = 42;
  // Initialize other fields
  ...
endfunction
Transaction t;
initial begin
  create(t);            // Create a transaction
  $display(t.addr);     // Fails because t=null
  end
 Good transaction creator task with ref on handle
function void create(ref Transaction tr);
  ...
endtask

systemverilog 的edge

除了 posedge and negedge
還有 edge可用

always @(edge clk iff clkEnable)

Function coverage

Function coverage 分成兩種

1.      Control-oriented : 
  偏向於不同信號線之間交互作用,因此大部分用來檢查protocol

使用Assertion來寫
property rule6_with_type(bit x, bit y);
     ##1 x   |->   ##[2:10] y;
//antecedent |->   consequent
endproperty

cover property (rule6_with_type) $display (“enable rule6_with_type coverage”);

2.      Data-oriented :
偏向於bus bits之間變化,因此除了可用來檢查資料變化方向,也可用來檢查FSMstate變化方向

使用covergroup來寫
bit [0:2] y;
    
    covergroup cg;
      cover_point_y : coverpoint y
                      { bins a = {0,1};
                       bins b = {2,3};
                       bins c = {4,5};
                       bins d = {6,7};   }
    endgroup

如何用systemverilog 來寫入binary file

這是我比較喜歡的做法,其它的作法請參考
IEEE1800-2009 , page593, chapter 21.3.2

integer fp_w;

bit [7:0] A_value, B_value;

initial begin
fp_w = $fopen(“test.jpg”, “wb”);

$fwriteh (fp_w, “%c%c%c”, “J”, “P”, “G”); // 寫一個Byte Char

$fwriteh (fp_w, “%c%c”, A_value, B_value); // 寫一個Byte value

$fclose(fp_w);

end

一個自己寫來測試semaphore用的例子

An example of creating a semaphore is as follows:
semaphore smTx;
Semaphore is a built-in class that provides the following methods:
—     Create a semaphore with a specified number of keys: new()
—     Obtain one or more keys from the bucket: get()
—     Return one or more keys into the bucket: put()
—     Try to obtain one or more keys without blocking: try_get()
先看一下原始文件上對semaphore 這個內建的class的說明
semaphore 如同一個桶子
成立時會先放一個標記在裡面
然後我們可用get()或try_get()去取出
如果semaphore 這個桶子裡
裡面已經沒有標記了
然後我們用get()時
整個模擬程序就會開始等待標記
直到semaphore 桶子裡有新放入的標記(用put放入)


module top;

   semaphore sem;
   initial sem = new(1);

   task automatic driver (input string nn, input time delay1, input time delay2); 
      #delay1;
      sem.get(1);
      $display($time, nn, "entering active section");
      #delay2;
      $display($time, nn, "leaving active section");
      sem.put(1);
   endtask
 
   initial begin
      sem.put(1);
      fork
         driver("AgentA  ", 10,30);
         driver("AgentB  ", 20, 40);
         driver("AgentC  ", 25, 20);
      join
   end
 
endmodule     

在我寫的例子裡
一開始我就先再放入一個標記
所以一開始就有兩個標記


do vsim.do
# resume
#                   10AgentA  entering active section 讀出第一個標記
#                   20AgentB  entering active section 讀出第二個標記, 因為一開始有再多放一個標記
#                   40AgentA  leaving active section  AgetnA放入一個新的標記
#                   40AgentC  entering active section  讀出第三個標記此為AgentA放的標記
#                   60AgentB  leaving active section   依時間AgetnB放入一個新的標記
#                   60AgentC  leaving active section   

2011年5月4日 星期三

DPI再了解(七)

 想到忘了將DPI的Input及output 放上來
 補放這個Case

// test.cpp
#include "svdpi.h"
#include <stdlib.h>
#include <stdio.h>

extern "C" void test(int *value) {

   *value = 12;

}

extern "C" void test1(int in_value) {

   printf("C1: Hello from C1 -> %d", in_value);

}

module main();

   import "DPI-C" function void test1(input int in_value);

   import "DPI-C" function void test(output int out_value);

    int out_value;
   
    initial begin

       test1(5);

       test(out_value);
      
       $display("\n\nout_value = %d\n\n", out_value);

   end

endmodule

希望對大家有參考的價值

2011年5月3日 星期二

DPI再了解(六)

一個DPI 用的簡單的Makefile

ARCH = linux

SPATH = .

INTDIR = $(SPATH)

CFLAGS = -g -Wno-deprecated -DGEN_MIF

INC_PATH = /mnt/eda/Cadence/IUS92/tools/include/

INCS = -I$(INC_PATH) \
       -I$(SPATH) \
       -I$(SPATH)/../../include

LIBS = -L/usr/lib
LDFLAGS = -lm -Wl, -E -shared

APP=test

#all: test.so

all :  bcpp
  
bcpp:
    g++ -o $(APP).so -I$(INC_PATH) $(CFLAGS) -shared $(APP).cpp
 
clean:
    rm -rf *.so

DPI再了解(五)

在IUS9.2的svOpenArrayHandle

目前只支援到32bits

所以在作傳值時
資料寬度必須在32bits以內
否則會傳送有錯誤的值


此處要參考下文
VPI 64-Bit Applications
The simulator enables you to run VPI applications written for a 64-bit execution environment. The 64-bit version of the simulator operates in the LP64 data model on UNIX platforms, which means that long and pointer are 64-bit data types and integers are 32 bits in size.

Some of your application code might assume that integers, long, and pointers are the same size. For this reason, if you need to run your existing 32-bit applications with the 64-bit simulator, you must revise your code in order to make it compliant with the 64-bit version of the simulator. In general, you should identify the code based on the assumption that integer and long types are equivalent and correspond to 32-bit quantities. As there is also a difference in pointer size between the two versions, make sure to modify any integer type that contains a pointer so it specifies the long internal type.

If your functions accept or return pointers, you must explicitly prototype them using the proper types for parameters and return values. If your C functions use implicit references regarding their type signatures, you must fix them to make your code 64-bit portable. In particular, ensure that all functions have a correct prototype declaration in scope. If you reference system functions, you should include the correct header file to bring the required types and prototypes into scope.

You can determine at compile time whether long is 32 or 64 bits in size by testing the value of sizeof(long).

DPI再了解(四)

一個簡單的DPI Array Packed case
這個例子是在CadenceIUS9.2cdnshelp上所找到的
這是個dynamic arraycase
另外所寫的static arraycaseCadence 上測不過
VCS上似乎可用, static array還要多花一些時間測試

gcc –I/IUS9.2/linux/tools/include/ -shared –o test.so test.c
使用gcc, 副檔名必須為c

g++ –I/IUS9.2/linux/tools/include/ -shared –o test.so test.cpp
使用g++, 副檔名必須為cpp

irun_92 main.sv –sv_lib test.so

//test.c
#include <stdio.h>
#include “svdpi.h”
#include <stdlib.h>
void reverse_logic_vec(const svOpenArrayHandle a, const svOpenArrayHandle b) {  
// test.cpp 如果用g++ 就改成下面這一行
// extern “C” void reverse_logic_vec
// (const svOpenArrayHandle a, const svOpenArrayHandle b) {  
// 此處 a input , boutput

        int i;
        int left, right, low, high;
svLogicVecVal *bv1, *bv2, *bv3, *bv4;
bv1 = (svLogicVecVal *) malloc (sizeof(svLogicVecVal) *1);
bv2 = (svLogicVecVal *) malloc (sizeof(svLogicVecVal) *1);
bv3 = (svLogicVecVal *) malloc (sizeof(svLogicVecVal) *1);
bv4 = (svLogicVecVal *) malloc (sizeof(svLogicVecVal) *1);

        svGetLogicArrElem1VecVal(bv1, a, 0);
array a[0]的值傳給bv1
svGetLogicArrElem1VecVal(bv2, a, 1); array a[1]的值傳給bv2
svGetLogicArrElem1VecVal(bv3, a, 2); array a[2]的值傳給bv3
svGetLogicArrElem1VecVal(bv4, a, 3);  array a[3]的值傳給bv4

svPutLogicArrElem1VecVal(b, bv1, 3); bv1的值傳給array b[3]
svPutLogicArrElem1VecVal(b, bv2, 2); bv2的值傳給array b[2]
svPutLogicArrElem1VecVal(b, bv3, 1); bv3的值傳給array b[1]
svPutLogicArrElem1VecVal(b, bv4, 0); bv4的值傳給array b[0]
}

module main();
    
          logic [4:1] input_1 [3:0];
          logic [0:3] output_1 [3:0];

           import "DPI-C"  function void reverse_logic_vec (input logic [3:0] i[ ], output logic [3:0] o[ ] );
          
           initial  begin
         input_1[0] = 4’b1111;
             input_1[1] = 4’b0000;
         input_1[2] = 4’bxxxx;
         input_1[3] = 4’bzzzz;

         #5 reverse_logic_vec(input_1, output_1);
         // input_1 對應到C code上的array a,
         // output_1對應到C code上的array b,    

for (int i = 0; i<4 ; i++) begin
                      $display("input[%d] = %b, output[%d] = %b\n ",i, input_1[i], i, output_1[i] );
              end
          
                #5 $finish;            
endmodule

上面有用到svLogicVecVal, 照文件上的說明
svBitVecVal canonical form for 2-state packed arrays 
svLogicVecVal canonical form for 4-state packed arrays

DPI再了解(三)

一個簡單的DPI Array case
這個例子是在CadenceIUS9.2上面所測的

gcc –I/IUS9.2/linux/tools/include/ -shared –o test.so test.c
使用gcc, 副檔名必須為c

g++ –I/IUS9.2/linux/tools/include/ -shared –o test.so test.cpp
使用g++, 副檔名必須為cpp

irun_92 main.sv –sv_lib test.so

//test.c
#include <stdio.h>
#include “svdpi.h”
void pass_array(const svOpenArrayHandle dyn_arr ) {  
// test.cpp 如果用g++ 就改成下面這一行
// extern “C” void pass_array(const svOpenArrayHandle dyn_arr ) {  

        int i;
      
        printf("Array Left %d, Array Right %d \n\n", 
svLeft(dyn_arr,1), svRight(dyn_arr, 1) );
        for (i= svRight(dyn_arr,1); i <= svLeft(dyn_arr,1); i++) {
             printf("C: %d %d \n", i,  *(int*)svGetArrElemPtr1(dyn_arr, i) );
        }
        printf("\n\n");
    
      }

module main();
    
           int fxd_arr_1[8:3];
           int fxd_arr_2[12:1];
          
           import "DPI-C" context function void pass_array(input int dyn_arr[] );
          
           initial
           begin
              for (int i = 3; i<=8 ; i++)
              begin
                   fxd_arr_1[i] = $random() ;
                 $display("SV:fxd_arr_1  %0d %d ",i, fxd_arr_1[i] );
              end
          
              $display("\n Passing fxd_arr_1 to C \n");
              pass_array( fxd_arr_1 );
            
              for (int i = 1; i<=12 ; i++)
              begin
                   fxd_arr_2[i] = $random() ;
                   $display("SV: fxd_arr_2 %0d %d ",i, fxd_arr_2[i] );
              end
          
              $display("\n Passing fxd_arr_2 to C \n");
              pass_array( fxd_arr_2 );
           end
      endprogram

svOpenArrayHandle systemverilogDPI 上傳送用的一個 open arrays 

上面有用到svLeftsvRight, 他們屬於Array querying functions, 列表如下
/* h= handle to open array, d=dimension */
int svLeft(const svOpenArrayHandle h, int d); // 回傳 left bound of the array
int svRight(const svOpenArrayHandle h, int d); // 回傳 right bound of the array
int svLow(const svOpenArrayHandle h, int d);// == svLeft
int svHigh(const svOpenArrayHandle h, int d);// == svRight
int svSizeOfArray (const svOpenArrayHandle h);//回傳array所佔用的記憶體

沒列出來的就是在Cadence沒有支援

DPI再了解(二)

一個簡單的import and export case
這個例子是在CadenceIUS9.2上面所測的
看起來Cadence export使用task會有問題, VCS似乎沒有此種限制,
因此本例只使用function

gcc –I/IUS9.2/linux/tools/include/ -shared –o test.so test.c
使用gcc, 副檔名必須為c

g++ –I/IUS9.2/linux/tools/include/ -fPIC -shared –o test.so test.cpp
使用g++, 副檔名必須為cpp
-fPIC 對所有的CC++檔案有宣告 extern項目的code是必要的

irun_92 main.sv –sv_lib test.so

//test.c
#include <stdio.h>
#include “svdpi.h”
extern void ex_task(); // 使用外部的function

void import_task() {
   printf(“C: Before calling export function\n”);
   ex_task();
   printf(“C: After calling export function\n”);
}

//test.cpp
#include <stdio.h>
#include “svdpi.h”
//extern void ex_task();

void import_task() {
   //printf(“C: Before calling export function\n”);
   //ex_task();  Cadence加上g++ 不能使用此種回叫模式
   printf(“C: After calling export function\n”);
}

// DPI case
`timescale 1ns/100ps
module main();
   export “DPI-C” ex_task = function export_task; //export_task放給外面使用,
   並將名稱改成ex_task, 所以在C/C++中的使用名稱為ex_task, 但在systemverilog的原始定義為export_task()

import “DPI-C” context function void test();

function export_task();
   $display(“SV: Entered the export function, wait for some time: %0d”, $time);  
endfunction

initial begin
   $display(“SV: Before calling import function %0d”, $time);
   #1;
   import_task();
   #1;
   $display(“SV: After calling function %0d”, $time);
   end
endmodule

DPI再了解(一)

複習一下DPI的使用
先用IUS來做練習


一個簡單的import case
這個例子是在CadenceIUS9.2上面所測的

gcc –I/IUS9.2/linux/tools/include/ -shared –o test.so test.c
使用gcc, 副檔名必須為c

g++ –I/IUS9.2/linux/tools/include/ -shared –o test.so test.cpp
使用g++, 副檔名必須為cpp

irun_92 main.sv –sv_lib test.so

//test.c
#include <stdio.h>
#include “svdpi.h”
void test() {
   printf(“C: Hello from C”);
}
void test1(int in_value) {
   printf(“C1: Hello from C1 -> %d”, in_value);
}

//test.cpp
#include <stdio.h>
#include “svdpi.h”
extern “C” void test() {
   printf(“C: Hello from C”);
}
extern “C” void test1(int in_value) {
   printf(“C1: Hello from C1 -> %d”, in_value);
}

// DPI case
module main();
   import “DPI-C” function void test1(int in_value);
import “DPI-C” function void test();
initial begin
test1(5);
        test();
   end
endmodule

2011年5月2日 星期一

一個自己寫來測試mailbox用的例子

// my mailbox
module top();

   mailbox my_mailbox;
  
   initial begin
      my_mailbox = new();
      if (my_mailbox) begin
         //fork
            put_packets();
           
            $display ("my_mailbox.num = %d",my_mailbox.num());
           
            try_put_packets();
           
            $display ("After try put my_mailbox.num = %d",my_mailbox.num());
           
            peek_packets();
           
            $display ("After Peek, my_mailbox.num = %d",my_mailbox.num());
           
            try_get_packets();
           
            $display ("After Try Get, my_mailbox.num = %d",my_mailbox.num());
           
            try_peek_packets();
           
            $display ("After Try Peek, my_mailbox.num = %d",my_mailbox.num());
           
           
            get_packets();
           
            $display ("After Got, my_mailbox.num = %d",my_mailbox.num());
           
            #10000;
         //join_any
      end
     
      #1000;
      $display("END of Program");
   end
  
   task put_packets();
      integer i;
      begin
         for(i=0; i<6; i++) begin
            #10;
            my_mailbox.put(i);
            $display("Done putting packet %d @time %d",i,$time);
         end
      end
   endtask
  
   task try_put_packets();
      integer i;
      begin
         for(i=7; i<16; i++) begin
            #10;
            my_mailbox.try_put(i);
            $display("Done Try putting packet %d @time %d",i,$time);
         end
      end
   endtask
  
   task get_packets();
      integer i, packet;
      begin
         for (i=0;i<18;i++) begin
            my_mailbox.get(packet);
            $display("Got packet %d @time %d",packet,$time);
         end
      end
   endtask
  
   task try_get_packets();
      integer i, packet;
      begin
         for (i=0;i<6;i++) begin
            my_mailbox.try_get(packet);
            $display("Try Get packet %d @time %d",packet,$time);
         end
      end
   endtask
  
  
   task peek_packets();
      integer i, packet;
      begin
         for (i=0;i<16;i++) begin
            my_mailbox.peek(packet);
            $display("Peek packet %d @time %d",packet,$time);
         end
      end
   endtask
  
   task try_peek_packets();
      integer i, packet;
      begin
         for (i=0;i<6;i++) begin
            my_mailbox.try_peek(packet);
            $display("Try Peek packet %d @time %d",packet,$time);
         end
      end
   endtask
  
  
endmodule

        
以下是mailbox的基本物件
class mailbox #(type T = dynamic_singular_type) ;
function new(int bound = 0);
function int num();   /// 檢察現在mailbox中有寫入但位讀出的資料數量
task put( T message);    放一筆資料
function int try_put( T message);  如果mailbox可以寫入就寫入一筆資料
task get( ref T message );   讀出一筆資料
function int try_get( ref T message );  如果有資料就讀出一筆資料
task peek( ref T message );   將最上層的資料預讀一筆, mailbox中的數量未改變
function int try_peek( ref T message ); 如果有資料就預讀一筆
endclass

systemverilog簡易的時間控制

Systemverilog提供直接定義的時間控制如下

可直接用數值加上時間單位來控制延遲的時間

單位可用
ns
us
ms

example: 
program tst;
   initial begin
   # 200ms;
   expect( @(posedge clk) a ##1 b ##1 c ) else $error( "expect failed" );
        ABC: ...
   end
endprogram 

這樣可以更直接及省事一些

2011年5月1日 星期日