数字IC设计-15-DPI(延续)

简介


供SV,无论是构建测试激励,或模拟硬件的并行行为,DPI这是非常方便。上次我们介绍SV内通“import”导入和电话C性能。

在本节,通过一个简单的例子来说明C什么语言的函数调用SV的task和function。


1,SV部分


/*
* test.v  Rill create for dpi test at 2014-10-20
*/

`timescale 1ns/1ns

module tb;
   import "DPI-C" context function int c_func(input int num);// or import "DPI-C" context task c_display(input int num);
      
      reg tmp;
      
      initial begin
	 #10
	   tmp = c_func(1);
      end

   m1 M1();
   m2 M2();
   
endmodule // top

module m1;
   import "DPI-C" context function void c_get_m1_scope();
   export "DPI" function m1_add;

   reg tmp;
   reg [7:0] m1_value;
   
   function int m1_add(input [7:0] num);
      m1_add = num + m1_value; //or return (num + m1_value);
   endfunction // m1_add

   initial begin
      c_get_m1_scope();
      m1_value = 8'd100;
   end
   
endmodule // m1


module m2;
   import "DPI-C" context function void c_get_m2_scope();
   export "DPI-C" task m2_add;

   reg tmp;
   reg [31:0] m2_value;
   
   task m2_add(input int num,output int sum);
      sum = num + m2_value;
   endtask // m2_add

   initial begin
      c_get_m2_scope();
      m2_value = 32'd200;
   end

endmodule // m1



2,C部分


/*
* test.c  Rill create for dpi test at 2014-10-20
*/

#include <stdio.h>
#include <svdpi.h>

svScope tmp_scope;
svScope m1_scope;
svScope m2_scope;

//import task/funcs from sv
extern int m1_add();
extern int m2_add();

//==scope switch
void c_get_tmp_scope(void)
{
  tmp_scope = svGetScope();
}

void c_set_tmp_scope(void)
{
  svSetScope(tmp_scope);
}

void c_get_m1_scope(void)
{
  m1_scope = svGetScope();
}

void c_set_m1_scope(void)
{
  svSetScope(m1_scope);
}

void c_get_m2_scope(void)
{
  m2_scope = svGetScope();
}

void c_set_m2_scope(void)
{
  svSetScope(m2_scope);
}

//==export c funcs to sv
int c_func(int num)
{
  int m1 = 0;
  int m2 = 0;

  c_get_tmp_scope();
  c_set_m1_scope();
  m1 = m1_add(num);
  c_set_tmp_scope();
  printf("m1:%d
",m1);

  c_get_tmp_scope();
  c_set_m2_scope();
  m2_add(num,&m2);
  c_set_tmp_scope();
  printf("m2:%d
",m2);

  return 0; 
}




3,脚本


#! /bin/bash

#
# test.sh
# usage: ./test.sh c/w/r
# Rill create 2014-10-20
#


TOP_MODULE=tb

tcl_file=run.tcl

CDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20


if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi

if [ $1 == "c" ]; then
echo "compile rtl lib..."
ncvlog -f ./vflist -sv -update -LINEDEBUG;
ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE}

echo "compile dpi lib"
if [ -e libdpi.so ];then
rm libdpi.so -f
fi

gcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/include
exit 0
fi


if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}

if [ $1 == "w" ];then
echo "open wave..."
echo "database -open waves -into waves.shm -default;" >> ${tcl_file}
echo "probe -shm -variable -all -depth all;" >> ${tcl_file}
echo "run" >> ${tcl_file}
echo "exit" >> ${tcl_file}
fi

if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim  ${TOP_MODULE} -input ${tcl_file}
fi

echo "$(date) sim done!"


4,说明

细致体会我们上面构造的样例,有几个问题须要弄清楚。

a。scope的含义:

在SV端。m1是不能直接调用m2中的task/function的。所以m1里面调用的C函数也不能直接调用m2中export出来的task/function。假设想调用,必须进行scope切换。

b。SV端,有task和function的区分。可是在C端,并没有区分,一律是C函数。


5,关于用C模拟硬件的并行行为

方式a,将流水后面的模块写在前面。这样的方式我们之前介绍过(http://blog.csdn.net/rill_zhen/article/details/8464930),这里不再赘述。

方式b,将全部并行的信号写成例如以下形式:

用c,n两个变量模拟reg的值。

用init和update两个函数模拟reg的行为。

/*
* parallel.c  Rill create for simulater test at 2014-10-20
*/


struct signal;

struct sig_ops
{
	int (*init) (struct signal*);
	int (*update) (struct signal*);
};

struct signal
{
	unsigned int c; //current cycle value
	unsigned int n; //next cycle value
	
	char name[32];
	struct sig_ops* ops;
};

/* veritual functions
int sig_init(struct signal* signal)
{
	return signal->ops->init(signal);
}

int sig_update(struct signal* signal)
{
	return signal->ops->update(signal);
}
*/

//actual functions
int test_init(struct signal* signal)
{
	signal->c = 0;
	signal->n = 0;
	return 0;
}

int test_update(struct signal* signal)
{
	signal->c = signal->n;
	return 0;
}



int signal_create(struct signal* signal,char * name)
{
	signal->name = name;
}

//============main.c====================//
//example signal
struct signal test;
struct sig_ops test_ops =
{
	test_init,
	test_update,
};

int main()
{
	signal_create(&test,"test");
	//when reset
	test->ops->init(&test);
	//per cycle
	test->ops->update(&test);
	
	return 0;	
}





原文地址:https://www.cnblogs.com/zfyouxi/p/4823942.html