事务级建模及验证的基本原理和应用剖析

来源:互联网 发布:app自动签到软件 编辑:程序博客网 时间:2024/05/08 09:56
系统级芯片(SoC)平台有各种不同类型的实体,它们通常包含至少一个处理单元(如微处理器或DSP)及外设、随机逻辑、嵌入式存储器、通信架构以及诸如传感器和执行机构等外部接口元件。这些不同的设计平台正在促使设计重点和折衷分析向通信方向发展。

因为SoC中的功能单元经常需要通过几种标准和专用总线协议进行通信,因此理解模块间的通信已经成为验证的关键要素。这种向通信架构设计重心的转移也加大了混合级建模和调试技术的普及程度。这些技术承诺能让设计师完全接受从RTL到更高事务处理级的转移,并且不会影响目前的功能验证方法。

基于现代协议的复杂性,在详细的信号层理解同步交互是非常困难的,需要耗费很多时间。而且在从规格要求到实现的不断调整过程中会有不同的团队和个人参与进来,因此需要在设计团队之间和团队之中定义共同的参考框架。

描述必须要灵活,以适应多种应用领域。在从顶到下的开发或从底到上的配置过程中,描述必须满足抽象和改进要求,与设计协调发展。提供这种服务的事务级建模(TLM)要求中间的建模抽象层提供顶层和底层的平滑衔接。


什么是事务处理,为什么采用事务处理

目前的SoC设计流程既有从规格要求到实现的从顶至下创建过程,又有对来自外部提供商或内部复用模块的设计和验证知识产权(IP)进行从底至上的集成过程。事务处理可以看作是确认改进规范,用以桥接不同的设计建模层。涉及范围从一般用高级语言完成的无时序纯功能建模,根据架构估计提供的带逼近时序的功能层,一直到实现层的循环精确RTL。

另外,TLM可以作为系统工程师和专用模拟开发人员之间的公共描述手段。它涵盖了适合任何特殊设计或验证活动的不同语言。此时事务处理变成了架构开发和折衷分析都可以执行的一种形式。通过分析系统功能有效性、诸如整体吞吐量和模块及存储器交互等待时间等性能标尺,TLM将成为自动化设计理解和调试过程的一种途径。

图1给出了从算法到实现层的各个抽象层。多种功能建模和验证语言(和标准)被经常用于设计,包括SystemC(IEEE P1666)、SystemVerilog(IEEE P1800)和e(IEEE P1647)。而且前沿方法最好用,比如OpenVera的参考验证方法(RVM)中和e的e复用方法(eRM)建议中精选出来的方法,它们为算法、架构和TLM提供了完善的结构。

TLM是一种非常自然的运作过程。它接收设计的每个功能线程,并进行描述。描述的重点是怎样做,特别是通信交互,而不是功能的内容。事务处理提供了对实现细节的临时抽象和空间封装,直接体现了通信架构而不是功能元件这个初始重点。执行这种抽象建模的优势表现为验证效率。事实上,事务处理的使用正变得越来越广泛,变化也越来越多,也越来越主流。

捕捉模块间同步传送的事务处理也将成为折衷分析的主力。因此,为了充分利用基于事务处理的高级验证和调试技术,提高开发效率和设计质量,建模和记录事务处理将变得至关重要。


如何建模和使用事务处理

高级语言或HLL(如SystemC)、许多其它硬件验证语言或HVL(如OpenVera,e)以及测试平台和设计语言(如SystemVerilog)都对事务处理提供了不同程度的支持。SystemC(www.systemc.org)对事务处理的支持最好,支持在建模语言中创建用户为主导的事务处理,并记录进与sc_trace()用SCV库写入的相同数据库。SCV收集了预先定义好的许多有用类,包括以下三种主要的记录工具类:

scv_tr_db:事务处理数据库对象,它允许用户对记录进行控制。该对象是通用的,独立于数据库格式。第三方记录API提供商可以将当前的服务映射到他们自己的数据库方案中去。

scv_tr_stream:事务处理流建模对象。流是一种抽象的通信媒体,上面可以进行包括重叠在内的事务处理,例如带读写事务处理的存储器流。因此流也可以看作是一种抽象信号,其中事务处理是可以被信号接受的抽象值,比如一条总线的一个地址或一个数据流。

scv_tr_generator:环绕特殊事务处理类型的对象,涉及属性的创建和累积,可以是从设计信号和消息到一般负载数据的任何对象。

从下面的一小段代码可以看到如何使用SCV以相对直接的方式创建事务处理。每段语句前的注释说明了后面语句的用途。事务处理可以被无缝地记录进数据库,不需要人工直接干预。为了实现这一功能,工具供应商可以通过前面所述的三种类中分别提供的注册机制注册回调来实现记录功能。用户只需要增加一些初始化调用。

// Inside sc_main() or some other context //在sc_main()或一些其它内容里面

// SCV startup //SCV启动
scv_startup();

// Initialization //初始化
API_vendor_initialization(); // set SCV callbacks here
scv_tr_db db("my_db");
scv_tr_db::set_default_db(&db);

// Define a stream and a generator //定义流和发生器
scv_tr_stream mem_stream("memory", "transactor");
scv_tr_generator read_gen("read", mem_stream, "mem");
scv_tr_handle tr_handle;

// Modeling code here //在这里建模代码?

// Transaction begin with a tr_data attribute //以tr_data属性开头的事务处理
tr_data.addr= addr_signal;
tr_data.data= data_signal;
tr_handle= write_gen.begin_transaction(tr_data);

// Transaction end //事务处理结束
tr_handle.end_transaction();

// Other modeling code here //这里开始其它建模代码

SCV还有许多其它的类,比如用来创建不同事务处理之间关系的scv_tr_relation。在分析和调试中关系类非常有用,特别是在确定前-后因果关系、父子层次关系以及分析组合成分的集合关系的时候。

由于OpenVera(www.open-vera.org)是一种面积对象的建模语言,因此很容易适应TLM的封装概念。OpenVera目前没有象SCV这样的内置事务处理类。当然也可以创建用于这一目的的类,例如以下的最小集:

trans_db:用于数据库
trans_stream:事务处理流建模对象
trans_type:(或发生器)用于创建事务处理和它们的属性
trans_handle:用于方便地管理句柄

以下是建模图2所示事务处理的一段简单代码。该类试图也把事务处理数据记录进下面所示的事务处理数据库,并存为trans_db instance dump_file。输出结果显示在图3所示屏幕的最右边。

// Inside program or some other OpenVera context //在程序或一些其它OpenVera文本里面
trans_db dump_file;
trans_stream stream1;
trans_type mem_read;
trans_handle h1;

// open a database file //打开一个数据库文件
dump_file=new("test");

// create the memory stream under the test.duv.bus scope //创建test.duv.bus范围内的存储器流
stream1=new(dump_file, "test.duv.bus", "memory");

// create the read transaction type in the memory stream //创建存储器流中的读取事务处理类型
mem_read=new(stream1, "Read");

// define 2 attributes in the read transaction type //定义读取事务处理类型中的2个属性
mem_read.create_attr("Addr", INTEGER_DT);
mem_read.create_attr("Data", INTEGER_DT);

delay(10);
// begin a memory read transaction at 10 //在10行开始存储器读取事务处理
h1=mem_read.begin_now();
h1.log_integer_attr("Addr", 170);
h1.log_integer_attr("Data", 123);

delay(20);// end h1 transaction at 20 //在20行结束h1事务处理h1.end_now();

// close the database file //关闭数据库文件
dump_file.close();

当然,就象前面提及SCV时所说的,另外一个有用的类是trans_relation,它可以解决不同事务处理之间的关系。下面一小段代码说明了trans_relation单向时如何运用类。分析和可视化工具也能预先定义关系,以便获得特殊描述用于分析和显示。

trans_relation r1;
trans_relation r2;
trans_handle h1;
trans_handle h2;


r1=new(f, "parent");
r2=new(f, "child");
...
h1.add_relation(r1, h2); // h2 is the parent of h1
h2.add_relation(r2, h1); // h1 is the child of h2

为了顺利实现记录,类必须整理事务处理轨迹,并记录隐藏数据库记录细节的API。API必须保持开放,以培育工程师和类似供应商之间公共的增殖文化。同时还必须能够使用多种语言创建、产生和记录事务处理,从而为设计师提供高价值的服务。另外,还必须简单、基本并且足够全面,以覆盖事务处理记录的主要单元。可以针对某种(特殊建模语言)环境实现API的进一步专业化。

作者开发了这样一个API,叫做开放事务处理接口(OTI)。这是在Novas的FSDB写入器接口之上建立的一个层。该API用C语言编写,因此具有很高的可移植性。事实上,前面所列的类是内部编写的OpenVera事务处理库类的一部分。它们形成了OTI周边的整理工具,并利用Direct C与OpenVera直接相接。用户可以使用Direct C从他们代码的任何位置调用OTI。但一般来说,最好在它周围提供一个外壳,用以屏蔽与建模语言的接口要求。这样用户就能重点关注建模,忽略数据库记录的细节。

希望利用任何可与C接口的语言开发和记录事务处理数据的设计师可以开发与OTI类似的API,包括其它流行的HVL,比如e(www.ieee1647.org)。事实上,API也能用于具有合适的系统整理任务和软件C/C++代码的HDL,实现直接从实现输入事务处理数据。图4给出了具有所有这些元件的系统。

SystemVerilog(3.1a版本)(www.systemverilog.org)是一种很有前途的设计建模和测试平台语言。目前就象SystemC中那样还没有内置的事务处理类,但已经有这样的概念,即抽取Verilog wire和reg数据并封装成更有意义的分组数据。这样就保证了我们如何能够建模然后记录事务处理数据的外形框架。事实上,SystemVerilog中有很多方法可以做到这一点。

a)等待标准化工作增加内置的类。这样做最终可能是可行的,但SystemVerilog现在已经有了。因此为何还要等待然后又要供应商提供支持呢?b)创建你自己的事务处理类和方法(任务和功能),然后将它们作为可共享的库回赠给大众。c)通过直接编程接口(DPI)或编程语言接口(PLI)实现与SystemC的集成。d)调用系统任务并在合适的建模代码中运行。

我们认为(d)对设计师来说是一个很好的起点。它覆盖了接口的许多要求,能够以简单、直接和相当灵活的方式完成这项工作。设计师可以通过PLI或最好通过DirectC这样的DPI调用SystemVerilog任务或C/C++例程。DPI是为了方便与用C或C++编写的外部无时序模块接口而设计的一种机制。

因此又出现了两个问题。什么是事务处理对象?设计师如何创建/产生/记录事务处理和开发API?我们的答案还是简单的API工具,例如图3所示的OTI。它可以隐藏实现细节,能为事务处理记录提供合理、完整的基础。


未来自动化程度将更高

到此为止讨论的事务处理记录非常有用,而且很有效率。但实际上还是人工的,即用户必须执行事务处理建模,并调用数据库记录。随着标准的成熟以及工具供应商的壮大,设计师肯定可以实现更加自动化的产生和记录工具。例如,用户可以而且已经在用VeraRVM(与e的顺序非常类似)中的事务处理类进行事务处理产生。

因此,快速自动化应该在这些指令中使用回调工具,以便用户无需担心分开来为事务处理建模。他们只需从提供的基类进行扩展,并自动获得所要求的记录例程。

另外,我们发现SoC一般由包含传统IP在内的许多模块组成。设计和验证所用的建模语言变化也相当大,如图3所示。因此,完整的SoC可以形成一个难以破解的数据。在这种情况下,如果工程师能设法从有效数据中提取事务处理以便更好地理解系统运作就更好了。有关这些内容我们放到今后再讨论。

建模、验证和调试要求使用统一的符号和框架,方便架构师和实现人员联合进行复杂SoC的设计和开发。TLM是适合这种教育式分析的理想模型。设计师应该更深入地了解事务处理建模细节,并利用它实现更有效地协同验证和创新的分析与调试。

作者:Bassam Tabbara

原创粉丝点击