| SystemVerilog Type | C Type |
|---|---|
| byte | char |
| int | int |
| longint | long long |
| shortint | short int |
| real | double |
| shortreal | float |
| chandle | void* |
| string | char* |
2011年5月7日 星期六
Systemverilog與C變數對照表
DPI再了解(九)
Chandle data type
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, 而不能當作一般變數來用
請參考表格
從書上剪下的例子
#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
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 ;
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
— Equality (==), inequality (!=) with another chandle or with null
— Case equality (===), case inequality (!==) with another chandle or with null (same semantics as == and !=)
— 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);
}
}
從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
關於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.
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 上的使用
節錄一段文字, 對此有些說明
function void create(ref Transaction tr);
...
endtask
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
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.
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.
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
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
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 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 handlefunction 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
function void create(ref Transaction tr);
...
endtask
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
##1 x |-> ##[2:10] y;
//antecedent |-> consequent
endproperty
cover property (rule6_with_type) $display (“enable rule6_with_type coverage”);
2. Data-oriented :
偏向於bus bits之間變化,因此除了可用來檢查資料變化方向,也可用來檢查FSM的state變化方向
使用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
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
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
希望對大家有參考的價值
補放這個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
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).
目前只支援到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
這個例子是在Cadence的IUS9.2的cdnshelp上所找到的
這是個dynamic array的case
另外所寫的static array的case在Cadence 上測不過
但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 , b為output
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 [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
$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
這個例子是在Cadence的IUS9.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");
}
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
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 是systemverilog在DPI 上傳送用的一個 open arrays
上面有用到svLeft及svRight, 他們屬於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所佔用的記憶體
DPI再了解(二)
一個簡單的import and export case
這個例子是在Cadence的IUS9.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 對所有的C及C++檔案有宣告 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來做練習
先用IUS來做練習
一個簡單的import case
這個例子是在Cadence的IUS9.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
這樣可以更直接及省事一些
可直接用數值加上時間單位來控制延遲的時間
單位可用
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日 星期日
訂閱:
文章 (Atom)