用msys2安装gcc编译工具链(联网 or 离线)、DPI

发布时间:2026/7/15 8:29:58
用msys2安装gcc编译工具链(联网 or 离线)、DPI 文章目录importsv内调用c标准c函数如何与sv对接语法要求sv内导入c函数/任务语法数据类型sv---dpi-c---标准c的类型的对应关系svBitVecVal实际就是uint32_t为什么还要新增svBitVecVal类型sv的任意位宽的bit[N:0] 传给c函数sv的数组 bit[31:0] dny_arr [] 传给c函数c函数的数组 传给 sv的数组 bit[31:0] dny_arr []SV 的 string→ C 的 const char*联网下载msys2更新组件选择并安装GCC工具链配置系统环境变量离线在能联网的电脑下载msys2在能联网的电脑更新组件在能联网的电脑选择并下载离线GCC工具链安装包在不能联网的电脑上安装questasim手册 1941页 要求gcc是Mingw而不是cygwinvlog xx.c 不提示具体错误就告诉错了importsv内调用c标准c函数如何与sv对接标准 C 函数不依赖 svdpi.h和 SystemVerilog 对接本质是写一层 DPI “胶水层”Wrapper把 sv 的世界翻译成 C 的世界。sv 只认识 DPI标准 C 只认识 stdint.hWrapper 是唯一桥梁。sv类型—dpi类型中间层Wrapper—标准c类型。sv与c之间函数形参传递的是都用指针因为在questasim内传int值实际还是地址而不是数值。适配层的函数参数类型不要使用原生c的uint8_t接要使用dpi定义的类型来接。bit [7:0] a ;错误void func1 (uint8_t a ) //应该使用dpi定义的类型 并且要用指针类型正确void func1 (svBitVecVal* a )在适配层的函数体内进行dpi类型转标准c类型。output 数组要先让 SV 侧 new 好大小C 侧只写元素或者 C 侧用 svOpenArrayCreate部分工具扩展非标准建完传回但可移植性差。SV 动态数组的内存归 SV 管C 不能直接 new[]一个 SV 动态数组。IEEE 1800 里 DPI 只规定 C 能接SV 传下来的 svOpenArrayHandle去读/写但没规定 C 能创建SV 动态数组。语法要求sv内导入c函数/任务语法import “DPI-C” function 返回值类型 函数名(参数方向 类型 参数名, …);import “DPI-C” task 任务名(参数方向 类型 参数名, …);真正决定 C 侧看到值还是指针的是“数据类型本身 DPI 的 ABI 映射规则”。在 IEEE 1800 SystemVerilog 标准中凡是“非平凡标量”non-trivial scalar即使它是 input也按“引用”传递。类型DPI 映射C 侧形式byte/ shortint/ int/ longint平凡标量值传递bit单 bit值传递通常bit [N:0]N ≥ 1向量类型vector指针传递 ⚠️logic [N:0]4-state 向量指针传递real/ shortreal浮点值传递string特殊指针svString数组 / struct / union聚合类型指针举例SV 声明C 侧真实参数是否值传递input int aint a✅input byte achar a✅input bit asvBit a✅通常input bit [0:0] aconst svBitVecVal*❌ 指针input bit [7:0] aconst svBitVecVal*❌ 指针input logic [7:0] aconst svLogicVecVal*❌ 指针input int a[]const svOpenArrayHandle❌ 指针input string sconst svString❌ 指针C 侧函数名必须和 SV import 里的一致。string outputC 侧得用 char**且内存由 SV 管别在 C 里 malloc后塞回去容易崩。只读 input 用 const char*最稳。logic四态别用 int接——x/z 会被当 0想保留四态必须用 svLogicVecVal。taskvs functionC 里如果调了 svGetTime()/ 回调 SV task 耗时间SV 侧必须声明成 import “DPI-C” task否则仿真器行为未定义。C 要 extern “C”不然名字 mangling 导致 link 不上DPI导入必须加context避免Questa优化问题。import “DPI-C” context function void dpi_print_all(数据类型SystemVerilogC 类型推荐C 原生替代说明bitsvBituint8_t二值单比特0/1推荐用svBitbit[x:0]svBitVecValuint32_t二值多比特0/1推荐用svBitVecVallogicsvLogic❌四值单比特0/1/X/Z必须用svdpi.hbyteint8_tsigned char8-bit 有符号shortintint16_tshort16-bit 有符号intint32_tint32-bit 有符号longintint64_tlong long64-bit 有符号integerint32_tint同inttimeuint64_tunsigned long long仿真时间realdouble✅双精度浮点shortrealfloat✅单精度浮点stringconst char*✅只读字符串chandlevoid*✅C 指针不透明句柄数值类型用 stdint.hint32_t等跨平台/跨仿真器更稳定。sv—dpi-c—标准c的类型的对应关系dpi-c类型标准C类型SV 类型说明svBitunsigned char二值bit值宏sv_0/sv_1svLogicunsigned char四值logic/reg单比特值宏sv_0/sv_1/sv_z/sv_xsvBitVecVal*uint32_t*任意位宽bit [N:0]packed二值小端排数组SV_PACKED_DATA_NELEMS(N)算 word 数svLogicVecValstructaval bval 两路uint32_tlogic [N:0]/reg [N:0]packed四值每比特 2 位编码0/1/z/xsvOpenArrayHandleopaque pointer (不透明指针)T[]动态数组/T[N:M]open array靠svLeft/svRight/svSize等 API 查维度chandlevoid *chandleSV 侧存 C 不透明指针const char */char **C 字符串string/string[N]只读进const char*可改写走svGetStringsvScopeopaque ptr (不透明指针)module / program / interface 实例svGetScope()/svSetScope()切上下文svUserPtrvoid *挂到 SV 对象的私有数据svSetUserData/svGetUserDatasvClassHandleopaque ptr (不透明指针)class实例C 侧只能持、不能解成员需 export 回 SV 操作svBitVecVal实际就是uint32_t为什么还要新增svBitVecVal类型为了跨仿真器稳定。svdpi.h不是 C 标准库是 IEEE 1800 规定的。所以VCS / Questa / Xcelium / Verilator 的 svdpi.h内容必须一致你看到的 typedef uint32_t svBitVecVal是实现选择标准只说至少是 32-bit unsigned integer-like所以永远用类型名别假设底层否则换仿真器可能翻车sv的任意位宽的bit[N:0] 传给c函数是连续存储的。任意位宽 bit [N:0]→ C 侧一律使用dpi-c内 指针传递 const svBitVecVal* 或 svBitVecVal* 或 svBitVecVal[]sv内 bit [9:0] a ;常见api需求推荐 API含参数读 1 个 bitsvGetBitselBit(const svBitVecVal* s, int i)写 1 个 bitsvPutBitselBit(svBitVecVal* d, int i, svBit val)读字段≤32 bitsvGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i(start), int w)写字段≤32 bitsvPutPartselBit(svBitVecVal* d, const svBitVecVal* s, int i(start), int w)读超宽向量循环调用svGetPartselBit()每次最多 32 bit初始化缓冲区SV_PACKED_DATA_NELEMS(bit_width)返回所需uint32_t数组长度packed struct 拆字段svGetPartselBit()/svPutPartselBit()按字段位偏移和宽度操作sv的数组 bit[31:0] dny_arr [] 传给c函数dpi-c使用svOpenArrayHandlec函数内的d表示维数从 1 开始不是 0这是最容易踩的坑。数组元数据查询API参数返回值 / 用法svDimensions(h)数组总维度数如 int a[][][]→ 3svLeft(h, d)第 d 维声明左边界SV 可 [6:1]left6svRight(h, d)第 d 维声明右边界svLow(h, d)第 d 维实际下界min(left,right)遍历用这个svHigh(h, d)第 d 维实际上界max(left,right)svIncrement(h, d)1表示升序([0:3])-1表示降序([3:0])svSize(h, d)第 d 维元素数 svHigh - svLow 1svSizeOfArray(h)整个数组字节数所有维乘积 × 元素字节取元素 / 取整体指针拿到指针后按 SV 侧类型强转int*/ short*/ double*等。API参数返回值 / 用法svGetArrayPtr(h)整个数组底层连续存储的 void*仅当数组 packed 连续时可靠否则别用svGetArrElemPtr(h, indx1, …)可变参版本按实际维数传索引最通用但慢一点​svGetArrElemPtr1(h, i1)一维数组取第 i1 个元素指针最快推荐svGetArrElemPtr2(h, i1, i2)二维 [i1][i2]svGetArrElemPtr3(h, i1, i2, i3)三维bit类型数组专用≥ 2-state如 bit [7:0][]API参数用法svGetBitArrElem(h, i1…)取单个 bit 元素返回 svBit即 unsigned charsvGetBitArrElem1/2/3(h, i1…)同上固定维数版本svPutBitArrElem/ 1/2/3(h, svBit v, i1…)写单个 bit 元素svGetBitArrElemVecVal/ 1/2/3(d, h, i1…)按 32-bit slice​ 取用于 bit [N:0]多 bit 元素N≥32svPutBitArrElemVecVal/ 1/2/3(h, svBitVecVal*, i1…)按 32-bit slice 写回logic类型数组专用4-state如 logic [3:0][]API参数用法svGetLogicArrElem/ 1/2/3(h, i1…)取单 element 的 svLogic0/1/X/ZsvPutLogicArrElem/ 1/2/3(h, svLogic v, i1…)写单 elementsvGetLogicArrElemVecVal/ 1/2/3(d, h, i1…)按 32-bit slice 取aval bval 两套表征 X/ZsvPutLogicArrElemVecVal/ 1/2/3(h, svLogicVecVal*, i1…)按 32-bit slice 写回c函数的数组 传给 sv的数组 bit[31:0] dny_arr []思路SV 侧先把动态数组 new[size]好以 inout或 input但 C 不改大小传给 CC 用 svGetArrElemPtr1逐个写回。内存/SV 类型全由 SV 管C 只负责填值。错误的指针转换: dyn_arr_tov 是 svOpenArrayHandle 类型 (即 void*)这是一个句柄/描述符不是数组数据的直接指针。直接将其转换为 int* 是错误的。举例// v文件 module tb(); bit [31:0] dyn_arr_toc[]; bit [31:0] dyn_arr_tov[]; int tmp; import DPI-C function void test( input bit [7:0] a, input bit [31:0] insize, input bit [31:0] dyn_arr_toc[], output bit [31:0] outsize, inout bit [31:0] dyn_arr_tov[] // 传递是指针不能是 input 或者 inout ); initial begin dyn_arr_toc new[5]; dyn_arr_tov new[6]; dyn_arr_toc[0] 32h00; dyn_arr_toc[1] 32h11; dyn_arr_toc[2] 32h22; dyn_arr_toc[3] 32h33; dyn_arr_toc[4] 32h44; foreach (dyn_arr_toc[i]) begin $display(sv:dyn_arr_toc[%0d]%h, i, dyn_arr_toc[i]); end // test(9, 5, dyn_arr_toc, tmp, dyn_arr_tov); // $display(sv:tmp%h, tmp); foreach (dyn_arr_tov[i]) begin $display(sv:dyn_arr_tov[%0d]%h, i, dyn_arr_tov[i]); end $stop(); end endmodule//c文件//toc所有元素1写入tovtov额外新增最后一个元素是toc所有元素值sumvoidtest(svBitVecVal*bit9_0,//任意位宽先传递来指针再api小端读取svBitVecVal*size_toc,//任意位宽的变量用svBitVecVal*svOpenArrayHandle dyn_arr_toc,//输入数组svBitVecVal*size_tov,//任意位宽的变量用svOpenArrayHandle dyn_arr_tov//输出值1数组){intcountsvSize(dyn_arr_toc,1);//获取数组第一维维度intint_toc_arr[count];//内部c类型数组intint_tov_arr[count1];//内部c类型数组svBitVecVal cut_bit9_00;//取出对应bitsvGetPartselBit(cut_bit9_0,bit9_0,0,10);//只会修改cut_bit9_0[9:0]printf(\n in a %0x,cut_bit9_0);//打印输入[9:0]printf(\n in count %0x,count);//打印输入元素个数//将dpi-c转为标准cfor(inti0;icount;i){int_toc_arr[i](*(int*)svGetArrElemPtr(dyn_arr_toc,i));}//进行计算操作int_tov_arr[count]0;for(inti0;icount;i){int_tov_arr[i]int_toc_arr[i]1;//内容1int_tov_arr[count]int_tov_arr[count]int_toc_arr[i];//求sum}/* 打印原始参数值 */for(inti0;icount;i){printf(\n c:int_toc_arr[%0d] %08x,i,int_toc_arr[i]);}for(inti0;icount1;i){printf(\n c:int_tov_arr[%0d] %08x,i,int_tov_arr[i]);}printf(\n);//将标准c转为dpi-cintlosvLow(dyn_arr_tov,1);//0inthisvHigh(dyn_arr_tov,1);//5int*p;printf(\n c:lo %0d,hi %0d \n,lo,hi);for(intilo;ihi;i){////0~5p(int*)svGetArrElemPtr1(dyn_arr_tov,i);//获取对应单个元素的地址// 直接写回 SV 动态数组*pint_tov_arr[i];//下面错误的指针转换: dyn_arr_tov 是 svOpenArrayHandle 类型 (即 void*)这是一个句柄/描述符不是数组数据的直接指针。直接将其转换为 int* 是错误的。// p(int*)dyn_arr_tov;// p[i] int_tov_arr[i] ;// printf(\n c:p[%0d] %08x,i,p[i]);}*size_tovcount1;}do文件vlog -ccflags -I./include/ xxx.c vlog -sv tb.sv vsim work.tbSV 的 string→ C 的 const char*生命周期由 SV 控制importDPI-Ccontext functionvoidc_print_string(input string s);voidc_print_string(constchar*s){if(sNULL){printf(C: received NULL string\n);}else{printf(C: received string \%s\\n,s);}}联网下载msys2下载MSYS2msys2-x86_64-20250830.exe更新组件安装完成后从开始菜单运行 MSYS2 UCRT64​ 或 MSYS2 MSYS​ 。在打开的终端中执行以下命令来更新核心包数据库和系统组件。pacman -Sy选择并安装GCC工具链pacman -S --needed base-devel mingw-w64-x86_64-toolchain配置系统环境变量C:\msys64\mingw64\bin离线在能联网的电脑下载msys2下载MSYS2msys2-x86_64-20250830.exe在能联网的电脑更新组件安装完成后从开始菜单运行 MSYS2 UCRT64​ 或 MSYS2 MSYS​ 。在打开的终端中执行以下命令来更新核心包数据库和系统组件。pacman -Sy在能联网的电脑选择并下载离线GCC工具链安装包pacman -Sw mingw-w64-x86_64-toolchain --cachedirC:/msys64/offline-packages 命令说明 -S安装软件包。 -w仅下载软件包不安装。 --cachedir指定软件包的下载目录。请将其中的 /path/to/your/offline-packages替换为你准备好的离线包存放路径例如 D:\msys2-offline-packages。 执行命令后所有必需的 .pkg.tar.zst格式的软件包文件都会被下载到指定的目录中。exe.pkg.tar.zst复制到不能联网的电脑上。在不能联网的电脑上安装指定.pkg.tar.zst文件的路径。questasim手册 1941页 要求gcc是Mingw而不是cygwingcc-4.5.0特殊vlog xx.c 不提示具体错误就告诉错了gcc没有装好gcc --version有还是没有装好重新安装。直到能命令行分步编译成功gcc -E main.c -o main.igcc安装解压即用推荐适合新手步骤1下载MinGW-w64安装包​https://github.com/brechtsanders/winlibs_mingw/releases访问WinLibs MinGW-w64的GitHub发布页面国内访问快提供预编译的最新版本下载64位Windows 10的压缩包链接https://github.com/brechtsanders/winlibs_mingw/releases选择winlibs-x86_64-posix-seh-gcc-xx.x.x-mingw-w64msvcrt-xx.x.x-r1.zip其中xx.x.x为最新版本号如2025年11月的14.2.0。注posix-seh是线程模型支持C11多线程mingw-w64msvcrt是Windows运行时库兼容Win10。end