首先认识一下,压缩数组和非压缩数组
压缩数组(Packed arrays)
对于某些数据类型,你可能希望既可以访问整个值,也可以将其分成更小的元素。 例如,你可能有一个32位寄存器,有时你希望将其视为四个8位值,而在其他时候则视为单个无符号值。 压缩数组被视为数组和单个值。 与非压缩的数组不同,它存储为一组连续的没有未使用空间的位。可以方便地将其作为数组元素进行访问。
压缩数组:在数据类型标识符名称之前声明的维度
bit [7:0] p;
// packed array of scalar bit types
bit [3:0] [7:0] bytes
// 4 bytes packed into 32-bits
压缩数组仅可以有单bit数据类型组成(bit, logic, reg)
具有预定义宽度的整数类型不能声明为带维度的压缩数组。 这些类型是byte,shortint,int,longint,integer和time。 虽然是具有预定义宽度n的整数类型,它不是一个打包数组,但其自身是可以分解为子字段的,就像它是一个具有单个[n-1:0]维度的压缩数组类型。
byte c2; // same as bit signed [7:0] c2;
integer i1; // same as logic signed [31:0] i1;
非压缩数组(Unpacked arrays)
非压缩数组可以由任何数据类型组成。每个固定大小的维度应由地址范围(例如[1:1024])或单个正数来表示,以指定固定大小的非压缩数组的大小,如C中所示。换句话说,[size]变为与[0:size-1]相同。
非压缩数组:在数据类型标识符名称后声明的维度
bit u [7:0];
int Array[0:7][0:31]; // array declaration using ranges
int Array[8][32]; // array declaration using sizes
SV 索引 [min:max] -> C端数组索引从0开始
SV: a[1:7] -> C: a[7]
SV: a[1] -> C: a[0], SV a[7] -> C: a[6]
SV压缩数组被当做一维数组对待
SV端 a[l][m][n]中的一个bit转换到 C端 a[n+mk+lj*k]
bit[5:2]a; a[5]=1 a[4]=0 a[3]=1 a[2]=0; -> C: a=10
所有数据类型最终都等同于最多32位的压缩数组
SV byte -> C int,只使用低8位
C char数组无法映射到SV byte类型的非压缩数组
混合压缩和非压缩的数组
bit [3:0] Bytes [0:2] [0:5]
SV_PACKED_DATA_NELEMS(width)
C marco SV_PACKED_DATA_NELEMS(width)从位转换为元素数
在bit和word之间转换
SV_PACKED_DATA_NELEMS(40)将40位转换为2个32位的字
#include "svdpi.h"
void packet_C(const svLogicVecVal* packet) {
const unsigned elements=SV_PACKED_DATA_NELEMS(128);
svLogicVecVal mem[elements];
memcpy(mem,packet,sizeof(mem));
io_printf(“C: data from SV side\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
for (unsigned i=0;i< elements;i++){
io_printf("mem[%2d]={%4x,%4x}\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n",i,mem[i].aval,mem[i].bval);
}
}
module test;
import "DPI-C" function void packet_C( input logic [127:0]);
logic [127:0] packet;
initial begin
packet=128'h1234_5678_aaaa_bbbb_cccc_dddd_eeee_ffff;
$display(“SV: data sent to C side: %x",packet);
packet_C(packet);
end
endmodule
bit和logic标量和矢量的使用
在svdpi.h的头文件中,有如下自定义类型声明:
typedef uint8_t svScalar;
typedef svScalar svBit; /* scalar */
typedef svScalar svLogic; /* scalar */
typedef unsigned int svBitVecVal;
Typedef struct{
unsigned int aval;
unsigned int bval;
} svLogicVecVal;
具体SV端和C端的对应关系如下:
SV bit -> C bit, SV bit[n:0] -> C svBitVecVal
SV logic -> C svLogic,SV logic[n:0] -> C svLogicVecVal
bit是二值逻辑,SV端和C端的数值是一样的。但是logic是四值逻辑,SV端的值怎么和C端的值对应起来呢?请看下表:
4-state value | bval | aval |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
z | 1 | 0 |
x | 1 | 1 |
#include <stdio.h>
#include <svdpi.h>
void show(svLogic a){
if(a == 0)
printf(" a is 0 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
else if(a == 1)
printf(" a is 1 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
else if(a == 2)
printf(" a is x \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
else if(a == 3)
printf(" a is z \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
}
program main;
logic a;
import "DPI-C" function void show(logic a);
initial begin
a = 1'b0;
show(a);
a = 1'b1;
show(a);
a = 1'bX;
show(a);
a = 1'bZ;
show(a);
end
endprogram
#include <stdio.h>
#include "svdpi.h"
void displaylogicvec(svLogicVecVal *l) {
printf (" data = %d control = %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", l->aval, l->bval) ;
}
void displaybitvec(const svBitVecVal *k) {
printf (" data = %d\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n " , k) ;
}
module top;
import "DPI-C" function void displaylogicvec(logic [7:0] i);
import "DPI-C" function void displaybitvec(bit [7:0] i);
bit [7:0] k ;
logic [7:0] l ;
initial begin
k = 25 ;
l = 40 ;
displaylogicvec(l) ;
l = 4’hx;
displaylogicvec(l) ;
l = 8’hz;
displaylogicvec(l) ;
displaybitvec(k) ;
$display("The End.");
end
endmodule
在DPI中使用数组
使用压缩数组(Packed Arrays)
压缩数组表示为一个或多个元素的数组,每个元素表示一组32位数据
#include "svdpi.h"
void get_nums (svLogicVecVal nums[10]) {
int i;
for (i=0; i<10; i++) {
nums[i] = i ;
}
}
program main;
import "DPI-C" function void get_nums(output logic [15:0] nums[10]);
logic [15:0] nums[10];
initial begin
get_nums(nums);
foreach (nums[i])
$display(i,nums[i]);
end
endprogram
使用开放数组(Open arrays)
压缩数组维度,非压缩维度或两个维度的大小可以保持未指定,这种情况称为开放数组(或未定义大小的数组)
先看个例子:
#include <stdio.h>
#include <svdpi.h>
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");
}
program 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
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
pass_array( fxd_arr_2 );
end
endprogram
开放数组提供了一系列查询和访问数组的方法
function | Description |
---|---|
int svLeft(const svOpenArrayHandle h, int d); | Left bound for dimension d |
int svRight(h, d) | Right bound for dimension d |
int svLow(h, d) | Low bound for dimension d |
int svHigh(h, d) | High bound for dimension d |
int svIncrement(h, d) | If left >= right 1 else -1 |
int svSize(h, d) | Number of elements in dimension d: svHigh−svLow+1 |
int svDimensions(h) | Number of dimensions in open array |
int svSizeOfArray(h) | Total size of array in bytes |
void *svGetArrayPtr(const svOpenArrayHandle h) | storage for the entire array |
void svGetArrElemPtr(const svOpenArrayHandle h, int i1, …) | an element in the array |
void *svGetArrElemPtr1(h, i1) | an element in a 1-D array |
void *svGetArrElemPtr2(h, i1, i2) | an element in a 2-D array |
void *svGetArrElemPtr3(h, i1, i2, i3) | an element in a 3-D array |
开放数组查询方法实例:
#include <stdio.h>
#include <svdpi.h>
void pass_array(const svOpenArrayHandle dyn_arr ) {
printf("Array Pointer is %x \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svGetArrayPtr(dyn_arr) );
printf(" Lower index %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svLow(dyn_arr,1));
printf(" Higher index %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svHigh(dyn_arr, 1) );
printf(" Left index %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svLeft(dyn_arr,1));
printf(" Right index %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svRight(dyn_arr, 1) );
printf(" Length of array %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svLength(dyn_arr,1) );
printf(" Incremental %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n",svIncrement(dyn_arr,1));
printf("Dimentions of Array %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svDimensions(dyn_arr ));
printf("Size of Array in bytes %d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", svSizeOfArray(dyn_arr) );
}
program main;
int fxd_arr_1[8:3];
int fxd_arr_2[1:13];
import "DPI-C" context function void pass_array(input int dyn_arr[] );
initial
begin
$display("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n Passing fxd_arr_1 to C \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
pass_array( fxd_arr_1 );
$display("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n Passing fxd_arr_2 to C \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
pass_array( fxd_arr_2 );
end
endprogram
打印信息如下:
Passing fxd_arr_1 to C
Array Pointer is 80fdc58
Lower index 3
Higher index 8
Left index 8
Right index 3
Length of array 6
Incremental 1
Dimentions of Array 1
Size of Array in bytes 24
Passing fxd_arr_2 to C
Array Pointer is 80fdc70
Lower index 1
Higher index 13
Left index 1
Right index 13
Length of array 13
Incremental -1
Dimentions of Array 1
Size of Array in bytes 52
在DPI中使用结构体
- 在传递“struct”数据类型时,数据被打包到数组中并从SV传递到C,然后数组被解码回到C中的“struct”中
#include "stdio.h"
#include "svdpi.h"
extern "C" {
typedef struct{
int a;
int b;
char c;
} C_struct;
extern void export_func(svBitVecVal x[3] );
void import_func() {
C_struct s_data;
unsigned int arr[3];
s_data.a = 51;
s_data.b = 242;
s_data.c = 35;
printf( "C : s_data.a = %d\\\\\\\\\\\\\\\\n", s_data.a );
printf( "C : s_data.b = %d\\\\\\\\\\\\\\\\n", s_data.b );
printf( "C : s_data.c = %d\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\n", s_data.c );
arr[0] = s_data.a ;
arr[1] = s_data.b ;
arr[2] = s_data.c ;
export_func(arr);
}
program main;
export "DPI-C" function export_func;
import "DPI-C" function void import_func();
typedef struct packed{
int a;
int b;
byte c;
} SV_struct;
function void export_func(input int arr[3]);
SV_struct s_data;
s_data.a = arr[0];
s_data.b = arr[1];
s_data.c = arr[2];
$display("SV: s_data.a = %0d", s_data.a );
$display("SV: s_data.b = %0d", s_data.b );
$display("SV: s_data.c = %0d \\\\\\\\\\\\\\\\n", s_data.c );
endfunction
initial begin
import_func();
end
endprogram
- 在SV和C/C++代码使用定义的未压缩的结构体数据类型
#include "stdio.h"
#include "svdpi.h"
extern "C" {
typedef struct {
int a;
int b;
} mystruct;
void mydisplay(mystruct *s1) {
int s2;
printf("C: gets values from SV, s1.a=%d, s1.b=%d\\\\\\\\\\\\\\\\n",s1->a,s1->b);
s1->a = 100;
s1->b = 200;
printf("C: set values, s1.a=%d, s1.b=%d\\\\\\\\\\\\\\\\n",s1->a,s1->b);
}
}
program p1;
typedef struct {
int a;
int b;
} mystruct;
import "DPI-C" function void mydisplay(inout mystruct s1);
mystruct s1;
initial begin
s1.a =10;
s1.b =20;
$display("SV: s1.a=%0d,s1.b=%0d",s1.a,s1.b);
mydisplay(s1);
$display("SV after DPI call: s1.a=%0d,s1.b=%0d",s1.a,s1.b);
end
endprogram
试着将上面例子中sv端结构体,改为packed类型,试试看C端打印信息会是什么样的?
- 压缩的结构体是包含packed保留字的结构体。 在结构内,保证了位连续性。 因此,成员也必须是矢量类型。 (不要混合real / shortreal。)如果混合使用2值或者4值逻辑,它们将在内存布局方面生成4个值,因此不要混用它们。
#include "svdpi.h"
extern void func(svBitVecVal*);
int struct_operation()
{
svBitVecVal rgb;
svPutPartselBit(&rgb,1,0,8);//b
svPutPartselBit(&rgb,2,8,8);//g
svPutPartselBit(&rgb,3,16,8);//r
func(&rgb);
svBitVecVal blue=0;
svBitVecVal red=0;
svBitVecVal green=0;
svGetPartselBit(&blue,&rgb,0,8);
svGetPartselBit(&green,&rgb,8,8);
svGetPartselBit(&red,&rgb,16,8);
io_printf("C: data from SV side. red %3d green %3d blue %3d.\\\\\\\\\\\\\\\\n",red,green,blue);
return 0;
}
module root_scope;
export "DPI-C" function func;
import "DPI-C" context task struct_operation();
typedef struct packed {
byte red;//MSB
byte green;
byte blue;//LSB ↑
} RGB_TYPE;
function void func(inout RGB_TYPE A);
$display("SV: data from C side. red=%3d blue=%3d green=%3d.",A.red,A.green,A.blue);
A.blue=101;
A.green=102;
A.red=103;
$display("SV: data change for C side read.");
endfunction
initial begin
struct_operation();
end
endmodule