Verilog ACC 子程序列表
Verilog ACC(Access)子程序列表
在 Verilog 仿真中,ACC(Access)子程序是 Verilog PLI(Programming Language Interface)的一部分,用于与仿真器交互,访问和操作 Verilog 模型的内部数据结构(如信号、模块、实例等)。ACC 子程序由 IEEE 1364 标准定义,主要用于仿真环境中的调试、测试和数据提取,不适用于逻辑综合,因为它们是仿真专用的接口,无法映射到硬件。
以下是 Verilog ACC 子程序的概述、分类、常见子程序列表,以及使用注意事项。鉴于 ACC 子程序通常用于与 C/C++ 接口开发复杂仿真功能,我会尽量简洁清晰,并提供一个简单的示例说明其用法。
ACC 子程序概述
- 作用:
- ACC 子程序允许用户通过 C/C++ 程序访问 Verilog 仿真器的内部数据,如信号值、模块层次、时间信息等。
- 常用于自定义仿真工具、测试平台、波形生成或与外部软件交互。
- 使用场景:
- 读取/修改信号值(如
$monitor
的增强版)。 - 遍历设计层次结构(如模块、实例、端口)。
- 控制仿真流程(如暂停、获取时间)。
- 不可综合性:
- ACC 子程序仅用于仿真环境(如 ModelSim、VCS),无法综合为硬件。
- 逻辑综合时,应避免在 Verilog 代码中使用 PLI 调用。
- 调用方式:
- 在 Verilog 代码中通过系统任务(如
$acc_task
)调用 C 函数。 - 在 C/C++ 代码中,使用 ACC 库函数(如
acc_fetch_value
)操作仿真数据。
ACC 子程序分类
ACC 子程序按功能分为以下几类(基于 IEEE 1364-2005 标准):
- 对象访问:
- 用于获取 Verilog 对象(如模块、信号、端口)的句柄(handle)。
- 示例:
acc_handle_tfarg
、acc_handle_object
。
- 值操作:
- 读取或修改信号值、参数值。
- 示例:
acc_fetch_value
、acc_set_value
。
- 层次遍历:
- 遍历设计层次,如模块、实例、端口、网线。
- 示例:
acc_next_child
、acc_next_port
。
- 时间与控制:
- 获取仿真时间、控制仿真流程。
- 示例:
acc_fetch_timescale
、acc_set_interactive_scope
。
- 属性查询:
- 获取对象属性(如信号类型、宽度、方向)。
- 示例:
acc_fetch_type
、acc_fetch_direction
。
- 错误与调试:
- 处理错误、输出调试信息。
- 示例:
acc_error_flag
、acc_vcl_add
(值变化检测)。
常见 ACC 子程序列表
以下是常用的 ACC 子程序,按功能分类,包含简要说明和典型用法:
- 对象访问:
acc_handle_tfarg(int n)
:获取系统任务第n
个参数的句柄。- 用法:
handle = acc_handle_tfarg(1);
(获取$acc_task(arg1)
的句柄)
- 用法:
acc_handle_object(char *name)
:通过名称获取对象句柄。- 用法:
handle = acc_handle_object("top.module1.sig1");
- 用法:
acc_handle_tfinst()
:获取当前系统任务实例的句柄。- 用法:
handle = acc_handle_tfinst();
- 用法:
- 值操作:
acc_fetch_value(handle, char *format)
:读取对象的值(格式如"b"
二进制、"d"
十进制)。- 用法:
char *val = acc_fetch_value(sig_handle, "b");
- 用法:
acc_set_value(handle, value, mode)
:设置对象的值。- 用法:
acc_set_value(sig_handle, &new_val, accForce);
- 用法:
acc_fetch_paramval(handle)
:获取参数值。- 用法:
double val = acc_fetch_paramval(param_handle);
- 用法:
- 层次遍历:
acc_next_child(handle, prev_handle)
:获取模块的下一个子模块。- 用法:
child_handle = acc_next_child(module_handle, NULL);
- 用法:
acc_next_port(handle, prev_handle)
:获取模块的下一个端口。- 用法:
port_handle = acc_next_port(module_handle, NULL);
- 用法:
acc_next_net(handle, prev_handle)
:获取模块的下一个网线。- 用法:
net_handle = acc_next_net(module_handle, NULL);
- 用法:
- 时间与控制:
acc_fetch_timescale(handle)
:获取模块的时间刻度。- 用法:
char *ts = acc_fetch_timescale(module_handle);
- 用法:
acc_fetch_simtime()
:获取当前仿真时间。- 用法:
double time = acc_fetch_simtime();
- 用法:
acc_set_interactive_scope(handle)
:设置交互作用域。- 用法:
acc_set_interactive_scope(module_handle);
- 用法:
- 属性查询:
acc_fetch_type(handle)
:获取对象类型(如模块、寄存器、网线)。- 用法:
int type = acc_fetch_type(handle);
- 用法:
acc_fetch_fullname(handle)
:获取对象全路径名。- 用法:
char *name = acc_fetch_fullname(handle);
- 用法:
acc_fetch_direction(handle)
:获取端口方向(输入、输出、双向)。- 用法:
int dir = acc_fetch_direction(port_handle);
- 用法:
- 值变化检测(VCL):
acc_vcl_add(handle, callback, user_data, vcl_reason)
:注册值变化回调。- 用法:
acc_vcl_add(sig_handle, monitor_cb, NULL, vcl_value_change);
- 用法:
acc_vcl_delete(handle, callback)
:删除值变化回调。- 用法:
acc_vcl_delete(sig_handle, monitor_cb);
- 用法:
使用 ACC 子程序的注意事项
- 仿真专用:
- ACC 子程序仅用于仿真环境(如 VCS、ModelSim),不可用于综合(如 Vivado、Design Compiler)。
- 综合代码应使用纯 Verilog 构造(如
always
、assign
)。
- 环境配置:
- 需要链接 ACC 库(通常由仿真工具提供)。
- C/C++ 代码需包含
acc_user.h
:c #include "acc_user.h"
- 性能开销:
- ACC 子程序涉及 C/Verilog 交互,可能影响仿真速度。
- 尽量减少频繁调用(如值变化检测仅用于关键信号)。
- 兼容性:
- ACC 是 Verilog-2001/2005 标准的一部分,现代仿真器(如 VCS、QuestaSim)支持良好。
- 部分子程序可能因工具而异,需查阅工具文档。
- 调试:
- 使用
acc_error_flag
检查错误。 - 使用
acc_fetch_fullname
确认对象路径。
示例:使用 ACC 子程序监控信号值
以下是一个简单的 Verilog 和 C 代码示例,展示如何使用 ACC 子程序监控 Verilog 模块中信号的变化。
Verilog 代码(test.v):
module test (
input wire clk,
input wire rst_n,
output reg [3:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) count <= 4'b0;
else count <= count + 1;
end
// 调用自定义 PLI 任务
initial begin
$monitor_count(count);
end
endmodule
C 代码(monitor_count.c):
#include "acc_user.h"
#include <stdio.h>
// 回调函数:当信号值变化时调用
void monitor_callback(handle sig, char *user_data) {
char *value = acc_fetch_value(sig, "b"); // 获取二进制值
char *name = acc_fetch_fullname(sig); // 获取信号全路径
printf("Time: %g, Signal: %s, Value: %s\n",
acc_fetch_simtime(), name, value);
}
// PLI 任务:注册信号监控
int monitor_count_calltf(char *user_data) {
handle arg_handle = acc_handle_tfarg(1); // 获取第一个参数(count)
if (arg_handle == NULL) {
printf("Error: Cannot get handle for argument\n");
return 0;
}
// 注册值变化回调
acc_vcl_add(arg_handle, monitor_callback, NULL, vcl_value_change);
return 0;
}
// PLI 注册函数
void acc_register() {
s_tfcell veriusertfs[] = {
{usertask, 0, 0, 0, monitor_count_calltf, 0, "$monitor_count"},
{0} // 结束标志
};
acc_initialize();
acc_configure(accEnableArgs, "true");
acc_configure(accDisplayWarnings, "true");
acc_register_tfs(veriusertfs);
}
编译与运行(以 VCS 为例):
# 编译 Verilog 和 C 代码
vcs -full64 -P pli.tab test.v monitor_count.c -o simv
# 运行仿真
./simv
pli.tab 文件:
$monitor_count call=monitor_count_calltf acc=rw:%1
输出示例:
Time: 5, Signal: test.count, Value: 0001
Time: 15, Signal: test.count, Value: 0010
Time: 25, Signal: test.count, Value: 0011
...
说明:
- Verilog 模块
test
是一个 4 位计数器。 - C 代码通过
$monitor_count(count)
注册信号count
的值变化监控。 acc_handle_tfarg
获取信号句柄,acc_vcl_add
注册回调,acc_fetch_value
读取值。- 每次
count
变化,C 函数打印时间、信号名和值。
扩展建议
- 复杂信号监控:
- 使用
acc_next_net
遍历模块所有信号,批量注册监控:c handle module = acc_handle_object("test"); handle net = NULL; while ((net = acc_next_net(module, net)) != NULL) { acc_vcl_add(net, monitor_callback, NULL, vcl_value_change); }
- 与前端交互:
- 将 ACC 获取的数据通过 socket 或文件传输到前端(如 JavaScript 网页)。
- 示例:将信号值写入文件,JavaScript 读取并显示:
c FILE *fp = fopen("output.txt", "a"); fprintf(fp, "%g %s %s\n", acc_fetch_simtime(), name, value); fclose(fp);
- 动态控制仿真:
- 使用
acc_set_value
动态修改信号值:c s_acc_value new_val = {accBinVal, "1010"}; acc_set_value(sig_handle, &new_val, accForce);
- 替代方案:
- 现代设计中,推荐使用 SystemVerilog DPI(Direct Programming Interface)替代 ACC,语法更简洁。
- 示例(SystemVerilog DPI):
verilog import "DPI-C" function void monitor_count(input int count);
注意事项与限制
- 不可综合:
- ACC 子程序仅用于仿真,不能用于逻辑综合。
- 综合代码需使用纯 Verilog 构造(如之前的计数器示例)。
- 工具依赖:
- ACC 子程序实现因仿真器(VCS、ModelSim、QuestaSim)而异,需参考工具手册。
- 确保链接正确的 ACC 库(如
-lacc
)。
- 性能:
- 频繁调用 ACC(如监控大量信号)可能降低仿真速度。
- 使用
acc_vcl_add
仅监控关键信号。
- 调试:
- 检查
acc_error_flag
捕获错误。 - 使用
acc_fetch_fullname
验证对象路径。
参考与资源
- 标准:IEEE 1364-2005 Verilog PLI 标准,定义 ACC 子程序。
- 书籍:
- 《Verilog PLI Handbook》(Stuart Sutherland):详细讲解 ACC 和 PLI。
- 《Writing Testbenches》(Janick Bergeron):测试平台开发。
- 工具文档:
- Synopsys VCS User Guide:PLI 和 ACC 配置。
- Mentor QuestaSim User Manual:ACC 子程序支持。
- 开源资源:
- Verilog PLI 示例:GitHub 上有许多 PLI 教程和代码。
总结
ACC 子程序是 Verilog PLI 的核心,用于仿真环境中访问和操作设计数据,常见功能包括信号监控、值修改和层次遍历。上述示例展示了如何使用 acc_vcl_add
监控信号变化,适合调试和测试平台开发。但 ACC 子程序不可综合,实际硬件设计应使用可综合 Verilog 代码(如状态机、计数器)。
如果需要更复杂的 ACC 示例(如遍历模块层次、与前端交互或集成到特定仿真器),或希望转向 SystemVerilog DPI,请提供具体需求!我也可以结合之前的可综合计数器示例,扩展为带 PLI 监控的完整测试平台。