Iverilog源码分析 -- VPI scope的实现

本文深入探讨了Verilog语言中scope的概念及其在IVerilog编译器中的实现方式,包括module、task、function等不同类型的scope,并详细介绍了这些scope在代码中的作用及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Verilog里面采用module/endmodule 来组成整个design的hierarchy结构, 比如, 如下的代码:
在这里插入图片描述
会产生如下的hierarchy结构:
在这里插入图片描述
目前在Verilog的LRM, 有如下几种scope类型:

  • Module
  • Task
  • Funcion
  • Named block

在IVerilog 里面, 定义了如下6中scope以及相关的定义如下:

  • vpiModule

  • vpiTask

  • vpiFunction
    上述3中, 比较常见, 忽略例子;

  • vpiNamedBegin
    begin … end之间的语句是串行执行的;

         begin:  scope_name
              declaration;
              state1
              state2
              ...
              stateN
         end
    
  • vpiNamedFork
    fork … join之间的语句是并行执行的;

         fork:  scope_name
              declaration;
              state1
              state2
              ...
              stateN
         join
    
  • vpiGenScope

    1 、generate-for语句必需用genvar关键字定义for的索引变量;
    2、 for的内容必须用begin…end块包起来,哪怕只有一句;
    3、 begin…end块必须起个名字;

    module gray2bin1 (bin, gray);
    parameter SIZE = 8; // this module is parameterizable
    output [SIZE-1:0] bin;
    input [SIZE-1:0] gray;
    genvar i;generate
    for(i=0; i<SIZE; i=i+1)
         begin:bit
                assign bin[i] = ^gray[SIZE-1:i];
         end
    endgenerate
    endmodule
    

在vvp/vpi_scope.cc里面, 对于上述6中类型的scope, 每一种定义了一个class, 继承自__vpiScope积累。

在Iverilog的整个流程里面, IVerilog负责产生一个xx.vvp 文件, 这是一个网表结构的文件, vvp程序会读取该文件, 产生vvp内存的信号;

从*.v scope的产生

在verilog .v文件里面,每次碰到一个scope, 在parser.y文件定义了每一种label对应的处理函数:

void
compile_scope_decl(char*label, char*type, char*name, char*tname,
                   char*parent, long file_idx, long lineno,
                   long def_file_idx, long def_lineno, long is_cell)
{
      count_vpi_scopes += 1;
      char vec_type;
      char sign_flag;
      unsigned wid;

      __vpiScope*scope;
      if (strcmp(type,"module") == 0) {
	    scope = new vpiScopeModule(name, tname);
      } else if ( sscanf(type, "function.vec%c.%c%u", &vec_type, &sign_flag, &wid) == 3 ) {
	    int type_code;
	    if (sign_flag=='s') {
		  type_code = vpiSizedSignedFunc;
	    } else if (sign_flag=='u') {
		  type_code = vpiSizedFunc;
	    } else if (sign_flag=='i') {
		  type_code = vpiIntFunc;
	    } else {
		  assert(0);
		  type_code = vpiSizedFunc;
	    }
	    vvp_bit4_t init_val = vec_type == '4' ? BIT4_X : BIT4_0;
	    scope = new vpiScopeFunction(name, tname, false, type_code, wid, init_val);

      } else if ( sscanf(type, "autofunction.vec%c.%c%u", &vec_type, &sign_flag, &wid) == 3 ) {
	    int type_code;
	    switch (sign_flag) {
		case 's':
		  type_code = vpiSizedSignedFunc;
		  break;
		case 'u':
		  type_code = vpiSizedFunc;
		  break;
		default:
		  assert(0);
		  type_code = vpiSizedFunc;
		  break;
	    }
	    vvp_bit4_t init_val = vec_type == '4' ? BIT4_X : BIT4_0;
	    scope = new vpiScopeFunction(name, tname, true, type_code, wid, init_val);

      } else if (strcmp(type,"function.obj") == 0) {
	    scope = new vpiScopeFunction(name, tname, false, vpiSizedFunc, 0, BIT4_0);
      } else if (strcmp(type,"autofunction.obj") == 0) {
	    scope = new vpiScopeFunction(name, tname, true, vpiSizedFunc, 0, BIT4_0);
      } else if (strcmp(type,"function.real") == 0) {
	    scope = new vpiScopeFunction(name, tname, false, vpiRealFunc, 0, BIT4_0);
      } else if (strcmp(type,"autofunction.real") == 0) {
	    scope = new vpiScopeFunction(name, tname, true, vpiRealFunc, 0, BIT4_0);
      } else if (strcmp(type,"function.str") == 0) {
	    scope = new vpiScopeFunction(name, tname, false, vpiOtherFunc, 0, BIT4_0);
      } else if (strcmp(type,"autofunction.str") == 0) {
	    scope = new vpiScopeFunction(name, tname, true, vpiOtherFunc, 0, BIT4_0);
      } else if (strcmp(type,"function.void") == 0) {
	    scope = new vpiScopeFunction(name, tname, false, vpiOtherFunc, 0, BIT4_0);
      } else if (strcmp(type,"autofunction.void") == 0) {
	    scope = new vpiScopeFunction(name, tname, true, vpiOtherFunc, 0, BIT4_0);
      } else if (strcmp(type,"task") == 0) {
	    scope = new vpiScopeTask(name, tname);
      } else if (strcmp(type,"autotask") == 0) {
	    scope = new vpiScopeTaskAuto(name, tname);
      } else if (strcmp(type,"fork") == 0) {
	    scope = new vpiScopeFork(name, tname);
      } else if (strcmp(type,"autofork") == 0) {
	    scope = new vpiScopeForkAuto(name, tname);
      } else if (strcmp(type,"begin") == 0) {
	    scope = new vpiScopeBegin(name, tname);
      } else if (strcmp(type,"autobegin") == 0) {
	    scope = new vpiScopeBeginAuto(name, tname);
      } else if (strcmp(type,"generate") == 0) {
	    scope = new vpiScopeGenerate(name, tname);
      } else if (strcmp(type,"package") == 0) {
	    scope = new vpiScopePackage(name, tname);
      } else if (strcmp(type,"class") == 0) {
	    scope = new vpiScopeClass(name, tname);
      } else {
	    scope = new vpiScopeModule(name, tname);
	    assert(0);
      }

      scope->file_idx = (unsigned) file_idx;
      scope->lineno  = (unsigned) lineno;
      scope->def_file_idx = (unsigned) def_file_idx;
      scope->def_lineno  = (unsigned) def_lineno;
      scope->item = 0;
      scope->nitem = 0;
      scope->live_contexts = 0;
      scope->free_contexts = 0;

      if (is_cell) scope->is_cell = true;
      else scope->is_cell = false;

      current_scope = scope;

      compile_vpi_symbol(label, scope);

      free(label);
      free(type);
      delete[] name;
      delete[] tname;

      if (parent) {
	    static vpiHandle obj;
	    compile_vpi_lookup(&obj, parent);
	    assert(obj);
	    __vpiScope*sp = dynamic_cast<__vpiScope*>(obj);
	    vpip_attach_to_scope(sp, scope);
	    scope->scope = dynamic_cast<__vpiScope*>(obj);

	      /* Inherit time units and precision from the parent scope. */
	    scope->time_units = sp->time_units;
	    scope->time_precision = sp->time_precision;

      } else {
	    scope->scope = 0x0;

	    vpip_root_table.push_back(scope);

	      /* Root scopes inherit time_units and precision from the
	         system precision. */
	    scope->time_units = vpip_get_time_precision();
	    scope->time_precision = vpip_get_time_precision();
      }
}

添加scope的自对象

current_scope是一个全局变量, 指到当前正在处理的scope:

__vpiScope* vpip_peek_current_scope(void)
{
      return current_scope;
}
void vpip_attach_to_scope(__vpiScope*scope, vpiHandle obj)
{
      assert(scope);
      scope->intern.push_back(obj);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值