自定义网站模块,wordpress 询盘插件,石家庄高级seo经理,app开发有几种方式1. 前言
通过总线将各个IP通过总线连接起来的SoC芯片是未来的大趋势#xff0c;也是缩短芯片开发周期#xff0c;抢先进入市场的常用方法。如何确保各个IP是否正确连接到总线上#xff0c;而且各IP的地址空间分配是否正确#xff0c;是一件很棘手的事情。本文提出了一种新…1. 前言
通过总线将各个IP通过总线连接起来的SoC芯片是未来的大趋势也是缩短芯片开发周期抢先进入市场的常用方法。如何确保各个IP是否正确连接到总线上而且各IP的地址空间分配是否正确是一件很棘手的事情。本文提出了一种新方法可以解决SoC总线验证的诸多困难既简单又快速地完成SoC总线功能验证。 2. SoC总线功能验证难点
在SoC芯片开发过程中SoC总线功能验证是确保各IP能否顺畅互动的关键可以把每个IP比较一座座房子总线就是房子和房子之间的路路没修好或者修错了房子建得再稳固再漂亮都没有什么用。以往的SoC总线面临诸多困难导致TB代码又长又难以继承复用。主要的困难点有
总线的地址空间(memory map)频繁改动TB需要实时适配需要定义和维护大量的宏不方便遍历整个地址空间的全部各区间区间和区间之间的从属关系在TB中很难反应出来激励完备性难以保证只能挑选一些典型的场景和区间去测试 3. 解决方案
本文提出的一种SoC总线功能验证方法完美解决了上述问题非常使用而且在真实项目中也实践过了。它有以下优点
减少TB代码修改无需大量宏定义方便使用确保完备性可复用性强 第2节的困难点主要是因为总线的memory map区间划分数量繁多和变化频繁引起的因此解决方法的思路也是从memory map映射到TB的格式入手。好的TB memory map格式可以起到事半功倍的效果思路请看下文。 3.1 文件准备
假设有以下一个用Excel表示的简单总线memory map表格它有三级表1为全部的地址空间大小表2为表1中IO区间的更小粒度划分区间(Region)表3为表2中SYS区间的更小粒度划分区间。 图1 Memory map在Excel中呈现的形式
Memory map表格的呈现形式具体可以和Designer讨论确定一种形式就好了不一定要按上面的罗列的形式。
有了这个Excel表格的话我们就可以写个脚本把每个区间的信息提取处理包括区间的名字(Region name)起始地址(Start Address)和终止地址(End Address)以及区间和区间之间的所属关系等比如表2中的TPIU/UART/…/SYS是IO区间的子区间而表3的EWM/PLL/SDIO/BOOT是表2的子区间。
提取了这些信息有什么用呢我们可以把每个区间或子区间都看作是一个SystemVerilog中的类(class)。如下图所示这个类(Class: region)应包含了以下基本属性和方法。 图2 memory map转换成class表示的形式
Region class包含起止地址(start_addr, end_addr)和下一个子region(sub_region)的连接信息如果一个区间没有再细分子区间那么sub_region队列的大小为0。反之则不为0比如图1中表1的IO区间下有5个子区间那么IO类的sub_regions的大小将为5。然后IO区间下面的SYS子区间有更细分为4个子区间那么SYS类的sub_regions的大小将为4。以此类推层层嵌套。再比如表1的ROM区间没有被细分那么ROM类的sub_regions的大小将为0。很简单是吧。
每个紫色方框可以代表是图1中表1 Main region的一个区间这样的话会有5个紫色方框map[enum]中的enum是表示enum类型它的值是表1区间名的集合。
按以上方式形式的一个类似于金字塔的结果最上面的是主区间然后一层层往下细分为更新的区间上级的区间拥有下一级区间的class句柄链接。而且所有区间都是使用region class来实现的很方便TB通过嵌套方式来使用memory map。
另外既然memory map的每个区间都抽象为类了那么SystemVerilog的所有语法可以用于操控它了比如可以在start_addr和end_addr之间生成任意的地址访问。而且TB可以在class里实现诸多使用的方法(task, function)去处理数据大大减少了重复代码。
另外通过将Excel的内容全部抽取转换为TB格式的mem_map类TB可以逐级遍历去测试每个区间再也不用担心漏了哪些地址区间没测了也不怕RTL频繁改动。
当然有一个小难点就是需要将Excel转换为图2形式的mem_map这个我就不多讲了脚本大家可以自己写而且根据这个思路可以实现很多有意思的功能亲测实用。 3.2 效果展示
使用脚本把图1的Excel内容转成TB代码的参考代码如下
//
// Main region: ROM
//
main[ROM] region::type_id::create(ROM);
main[ROM].start_addr h8A0000000;
main[ROM].end_addr h99FFFFFFF;//
// Main region: DDR
//
main[DDR] region::type_id::create(DDR);
main[DDR].start_addr h120000000;
main[DDR].end_addr h89FFFFFFF;//
// Main region: RESERVED_A
//
main[RESERVED_A] region::type_id::create(RESERVED_A);
main[RESERVED_A].start_addr h41000000;
main[RESERVED_A].end_addr h11FFFFFFF;//
// Main region: USB
//
main[USB] region::type_id::create(USB);
main[USB].start_addr h40000000;
main[USB].end_addr h040FFFFFF;//
// Main region: IO
//
main[IO] region::type_id::create(IO);
main[IO].start_addr h0;
main[IO].end_addr h03FFFFFFF;
// Sub: TPIU (IO - TPIU)
sub_rgn region::type_id::create(TPIU);
sub_rgn.start_addr h3D000000;
sub_rgn.end_addr h3FFFFFFF;
main[IO].sub_rgn.push_back(sub_rgn);
// Sub: UART (IO - UART)
sub_rgn region::type_id::create(UART);
sub_rgn.start_addr h3C000000;
sub_rgn.end_addr h3CFFFFFF;
main[IO].sub_rgn.push_back(sub_rgn);
// Sub: GPU_REGISTER (IO - GPU_REGISTER)
sub_rgn region::type_id::create(GPU_REGISTER);
sub_rgn.start_addr h3B000000;
sub_rgn.end_addr h3BFFFFFF;
main[IO].sub_rgn.push_back(sub_rgn);
// Sub: DMC_REGISTER (IO - DMC_REGISTER)
sub_rgn region::type_id::create(DMC_REGISTER);
sub_rgn.start_addr h30000000;
sub_rgn.end_addr h3AFFFFFF;
main[IO].sub_rgn.push_back(sub_rgn);
// Sub: SYS (IO - SYS)
sub_rgn region::type_id::create(SYS);
sub_rgn.start_addr h0;
sub_rgn.end_addr h2FFFFFFF;
main[IO].sub_rgn.push_back(sub_rgn);
// SubSub: EWM (IO - SYS - EWM)
sub_rgn region::type_id::create(EWM);
sub_rgn.start_addr h25000000;
sub_rgn.end_addr h2FFFFFFF;
main[IO].sub_rgn[$].sub_rgn.push_back(sub_rgn);
// SubSub: PLL (IO - SYS - PLL)
sub_rgn region::type_id::create(PLL);
sub_rgn.start_addr h21000000;
sub_rgn.end_addr h24FFFFFF;
main[IO].sub_rgn[$].sub_rgn.push_back(sub_rgn);
// SubSub: SDIO (IO - SYS - SDIO)
sub_rgn region::type_id::create(SDIO);
sub_rgn.start_addr h200000;
sub_rgn.end_addr h20FFFFFF;
main[IO].sub_rgn[$].sub_rgn.push_back(sub_rgn);
// SubSub: BOOT (IO - SYS - BOOT)
sub_rgn region::type_id::create(BOOT);
sub_rgn.start_addr h0;
sub_rgn.end_addr h001FFFFF;
main[IO].sub_rgn[$].sub_rgn.push_back(sub_rgn);