Iverilog 源码分析 -- VPI的实现

在IVerilog中VVP可以通过-m或者-M制定需要加载的模块,本文介绍一下VPI的模块工作机制。
每个模块通过vpip_load_module来加载指定的动态链接库, 然后在动态链接库里面找到“vpip_set_callback”函数来设定vpip_routines_s 结构内的函数指针,这些函数是VerilogLRM预定义的37个函数, 参考Verilog LRM 27章: VPI routines definition, 这些函数定义在vvp/vpi_private.cc里面;
然后查找vlog_startup_routines 内指定的启动函数并且逐个执行;
vlog_startup_routines是一个注册函数列表, 每个自定义的模块要首先在该列表里面注册:

void vpip_load_module(const char*name) {
    // buf 保存了模块的路径、名称
     dll = ivl_dlopen(buf, export_flag);
     
      void*function = ivl_dlsym(dll, "vpip_set_callback");
      if (function) {
            vpip_set_callback_t set_callback = (vpip_set_callback_t)function;
            if (!set_callback(&vpi_routines, vpip_routines_version)) ;
	          return;
            }
      }

      void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU);
      
      vpi_mode_flag = VPI_MODE_REGISTER;
      vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
      for (unsigned tmp = 0 ;  routines[tmp] ;  tmp += 1)
	    (routines[tmp])();
      vpi_mode_flag = VPI_MODE_NONE;
 }

VPI 的模块启动函数设定在vpi/sys_table.cc, 设定如下:

void (*vlog_startup_routines[])(void) = {
      sys_convert_register,
      sys_countdrivers_register,
      sys_darray_register,
      sys_fileio_register,
      sys_finish_register,
      sys_deposit_register,
      sys_display_register,
      sys_plusargs_register,
      sys_queue_register,
      sys_random_register,
      sys_random_mti_register,
      sys_readmem_register,
      sys_scanf_register,
      sys_time_register,
      sys_lxt_or_vcd_register,
      sys_sdf_register,
      sys_special_register,
      table_model_register,
      vams_simparam_register,
      0
};

这里定义了很多的自定义加载模块, 每个模块通过如下的方式来注册函数进行模块与simulator之间的交互, 使得用户模块可以访问simulator的内存状态信息。

typedef struct t_vpi_systf_data {
      PLI_INT32 type;
      PLI_INT32 sysfunctype;
      const char *tfname;
      PLI_INT32 (*calltf)   (ICARUS_VPI_CONST PLI_BYTE8*);
      PLI_INT32 (*compiletf)(ICARUS_VPI_CONST PLI_BYTE8*);
      PLI_INT32 (*sizetf)   (ICARUS_VPI_CONST PLI_BYTE8*);
      ICARUS_VPI_CONST PLI_BYTE8 *user_data;
} s_vpi_systf_data, *p_vpi_systf_data;

     s_vpi_systf_data tf_data;
      vpiHandle res;

      tf_data.type        = vpiSysFunc;
      tf_data.tfname      = "$time";
      tf_data.sysfunctype = vpiTimeFunc;
      tf_data.calltf      = sys_time_calltf;
      tf_data.compiletf   = sys_no_arg_compiletf;
      tf_data.sizetf      = 0;
      tf_data.user_data   = "$time";
      res = vpi_register_systf(&tf_data);
      vpip_make_systf_system_defined(res);

每当在Verilog里面调用$time(), 系统自动调用compiletf指针指向的函数,来检验函数调用的参数检查, 通过calltf函数指针来执行相关的操作。

在VVP目录下面, 存在很多的vpi_xxx.cc文档, 他们实现了VVP调用vpi模块的框架函数。

文件主要功能
vpi_modules.cc实现了load_vpi_module, 其功能如上面分析
vpi_task.cc记录系统函数或者系统任务, 任务的调用等
vpi_scope.cc定义了__vpiScope以及其字对象, 主要记录了模块以及子模块,参考: VPI scope
vpi_signal.cc定义了signal的属性信息, 以及不同类型的valuechange的类定义
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值