CatapultSLSynthesis软件试用评估报告_第1页
CatapultSLSynthesis软件试用评估报告_第2页
CatapultSLSynthesis软件试用评估报告_第3页
CatapultSLSynthesis软件试用评估报告_第4页
CatapultSLSynthesis软件试用评估报告_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、catapult sl高层次综合算法c工具的开发技巧 pixelworks 司马苗 摘要 mentor 公司提供的catapult sl开发工具,不仅是快速算法验证,也是模块级结构设计和分析的有力工具,能有效地缩短产品的上市时间。本文首先回顾catapult 综合工具开发的基本流程,然后介绍catapult sl基于类的开发技巧以及视频算法中遇到的preload和teardown 控制的技巧,最后列举一些catapult sl开发过程中节约时间的技巧。 一、概述 随着系统级芯片( soc )设计复杂度的不断增加,电子系统级(esl )的设计和验证方法学得到越来越广泛的应用。esl 设计是能够让

2、soc设计工程师以紧耦合方式开发、优化和验证复杂系统架构和嵌入式软件的一套方法学,它还提供下游寄存器传输级(rtl)实现和验证基础。已有许多世界领先的系统和半导体公司采用esl设计,以便为他们创新的终端产品获得成功提供必需的先进功能性和高性能。gartner dataquest预测, esl 工具市场将在未来5 年达到 35.7%的年复合增长率,而目前 esl工具缺乏是 “使寄存器传输级 (rtl)工具销售保持增长的唯一因素” 。而 mentor graphics拥有 esl领域有全套的领先设计、仿真及实现解决方案( bridgepoint 、platform express、perspect

3、a 、catapult sl synthesis)可以帮助设计公司提高设计的抽象层次,缩短设计时间。 目前 catapult 综合工具是业内最成熟的能利用非定时的纯c+ 语言来产生高品质rtl描述的算法综合工具,速度最快可达到传统人工方式的20 倍,为缩短了产品的上市时间提供了可能。 它支持设计人员面向各种微结构和接口设计实施详细的what-if分析,进而得到比较优化的硬件设计,并可以复用算法开发时的c+ testbench 来验证生成的rtl代码,从而保证原算法与rtl代码功能的一致性,减少人工引入错误的可能性。 逐点半导体 (pixelworks)主要致力于图像和视频处理芯片的开发,是显示

4、器,电视机,投影仪等消费电子产品的芯片的重要供应商。我们通过使用catapult工具来加速算法到芯片的开发过程,提高设计的可靠性。二、设计流程 传统的 asic 设计流程比较复杂, 流程中的每一步都需要详细的文档工作和复杂的验证,以保证设计正确。算法工程师, 结构工程师和rtl工程师之间的反复比较多,而且如果算法工程师, 结构工程师和rtl工程师对结构或者算法的理解有误差的话,会造成 rtl设计上的缺陷或失误。 为了减少设计的反复,缩短产品的上市时间,可以采用mentor 的 catapult sl设计流程如图 1 所示,直接由定点的c+ 代码综合出可综合的rtl代码。该流程的好处是我们结构工

5、程师和算法工程师不必等rtl工程师写完rtl代码后再进行算法的验证和优化,并且可以节省大量算法工程师,结构工程师与rtl设计工程师之间反复沟通算法设计的时间。 使用 catapult sl 开发环境,可以方便的把基于c+ 的算法加入的项目之中,选择适当的芯片设置,定义不同微架构方案(流水、并行、串行),评估不同方案使用的资源情况,最后生成 rtl和验证环境,在modelsim 中进行仿真。开发环境支持对多个方案对比,以便开发人员选择最优的方案。对于验证成功的rtl代码环可以进一步调用mentor 的工具进行fpga综合或者采用magama /synopsys /cadence 综合工具进行as

6、ic 综合。 图 1. catapult sl 的 asic 设计流程三、常用的设计技巧 catapult sl开发工具最初作为基于c的算法向 rtl代码转换和验证的工具引入。对于算法工程师而言, catapult开发工具可以方便地用于通信算法,图像处理算法、音频算法和视频算法的开发。而对于系统工程师或者架构工程师而言,catapult工具也可以用于视频芯片中模块级结构的设计和开发。 这一节主要介绍catapult sl提供的开发技巧: 基于类和模板 (template)的编程方式,定义寄存器,分配存储空间,输入输出,隐藏preload和 teardown 控制,以及使用rtl风格的 c代码。

7、 3.1 基于类和模板的编程方式 基于类和模板的编程有许多优势。首先,从结构设计的角度基于类的编程可以使得硬件结构变得清晰, 比如可以把memory以及和 memory紧密结合的逻辑放在一起。其次, 使用类和模板使得代码可以模块化重复利用。 下面结合视频解码中运动补偿的例子来说明。在进行视频解码的运动补偿时我们需要前向参考块和后向参考块,每个参考块又有亮度和两个色度分量,一共六个模块, 只需通过定义一个模板就可以实现。 /example for class and template 01: template 02: class reference_block 03: 04: public: 0

8、5: int ref_blocksin_heightin_width; 06: int intermediate2out_width+1; 07: void input(.); 08: void do_mc(int outout_width) 9: 10: get_pixels(); 11: biliear(out); 12: 13: void get_pixels(.); 14: void biliear(int outout_width); 15: 16: void top_mc() 17: 18: static reference_block ref_y_forw; 19: static

9、 reference_block ref_y_back; 20: static reference_block ref_u_forw; 21: static reference_block ref_u_back; 22: static reference_block ref_v_forw; 23: static reference_block ref_v_back; 24: . 25: int y_forw8; 26: int y_back8; 27: int u_forw4; 28: int u_back4; 29: int v_forw4; 30: int v_back4; 31: . 3

10、2: for (.) 33: for(.) 34: . 35: ref_y_forw.do_mc(y_forw); 36: ref_y_back.do_mc(y_back); 37: ref_u_forw.do_mc(u_forw); 38: ref_u_back.do_mc(u_back); 39: ref_v_forw.do_mc(v_forw); 40: ref_v_back.do_mc(v_back); 41: . 42: 43: 图 2. 基于类和模板的编程方式 上面图 2 第 1行到第 15 行定义了一个叫做reference_block的模板,他的功能是输入4 个块,放入内部的s

11、ram 之中,然后根据半像素精度的运动适量从中2 行乘以一个块宽度加 1 个像素, 然后用这些像素作双线性插值得到1 乘以块宽度个像素进行输出。在这个模板中,形成运动补偿的参考块的双线性插值算法,和它所使用的数据:输入的4 个块,中间结果 out_width+1 封装在一起,完成所需的任务。 在 18 到 23 行生成了6 个对象, 分别是 yuv分量前向后向参考块,对象的定义是静态的保证每个对象成员变量也是静态的,catapult工具会把其中的数组映射成寄存器或者sram 。而 25 到 30 定义的数组最后映射成寄存器可用来保存结果。参考块可以用来和残差信号相加的到最终的解码结果。使用类似

12、的方法使用类把算法实现的结构搭建起来。 3.2 使用类的成员变量数组定义寄存器 在使用模板 和类定义一组算法或者模块的结构时,需要考虑问题是在那里存贮数据,数据的格式是什么样子的,和算法之间有何联系? 一般而言可以考虑下面4 个步骤: ?算法的所有输入首先保存在input buffer之中; ?在运算之前把当前要用的数据从input buffer 之中取出来放入寄存器,也就是intermediate buffer 之中; ?进行计算; ?计算结果直接输出。 一般输入缓冲区和中间结果缓冲区定义在类或者模板之中。而最终结果( 特别是数组 ) ,定义于在主函数之中,便于子函数之间交换数据。一般而言类

13、中的数组和主函数中的数组都可以映射成寄存器或者sram ,比如图2 中第 5,6,18 到 23 行定义的数组都可以映射为寄存器或者 sram 。 需要注意的是,中间变量数组最好不要象图2 的第 13 行那样定义在类的成员函数中。在类例化之后,各个对象的成员变量是相互独立的,可以生成不同的sram ,而成员函数定义的数组有可能被catapult工具认为是多个对象共用一个sram ,从而导致数据混乱。 3.3 接口综合以及 break 都需要明确的条件 catapult开发工具提供了丰富的接口资源,如连线型,带使能端的、带硬件握手的、spram,dpram 以及总线接口和streaming(数据

14、流) 接口。我们为了节省面积, 减少对 memory的需求,采用了catapult 提供的streaming 接口,如图3 所示。在对基于streaming 的输入和输出进行操作的时候,需要加上相应的约束条件以保证数据的正确性。 blockin out 1n01 n 0 blockout 1 n0in 例如下面图4的例子中第15 和 20 行分别为输入和输出增加了约束条件。这样才能反映输入时 preload和输出时teardown 的情况。避免出现输入输出streaming 溢出的情况。 / example for conditional read write and break 01: #d

15、efine max_out 20 02: #define max_inn 200 03: void top_level_function(int in_a1000, int in_b1000, int out_c1000) 04: 05: int loop_outer, loop_inner; 06: 07: for( loop_outer = 0; loop_outer =11) break; 10: for( loop_inner = 0; loop_inner =103) break; 13: if(loop_inner 100)&(loop_outer= 3 & loo

16、p_inner = 1 & loop_outer 11) 21: 22: *out_c+ = tmp_out; 23: 24: 25: 26: 3.3 break语法的支持 catapult支持 break 语句,并可利用break 来减少流水线中冗余周期,如图5 所示。 1 0 n 图 3. streaming 接口示意图 4. streaming 接口及 break 语句的支持/break to remove the redudancy cycle 1: void test(int16 anum, int16 bnum, int32 doutnum,uint10 ctrl) /se

17、t the constrains to the test function with pipeline initialization interval =1 2: 3: iloop:for(int i=0;i ctrl;i+) 4: 5: douti = ai * bi; 6: 7: 8:void test(int16 anum, int16 bnum, int32 doutnum,uint10 ctrl) 9: 10: iloop:for(int i=0; i= ctrl) 14: break; 15: 16: 冗余周期图 5. break消除冗余周期此外使用 break 语句控制两层循环的

18、次数时,需要注意的是break 语句执行的条件和输出条件必须是明确互斥的,不能有”交集” 。 例如图 4中不能因为在第12 行有 “if(loop_inner =103) break; ”就去掉第20 行中 loop_inner =11) break; ” 而省略第 20行中 “loop_outer 11” 。 这样才可避免catapult工具生成的rtl和原始的c+ 代码仿真的不匹配。 3.4 preload和 teardown隐藏在主程序之外 在图 4 的例子中13 行和 20 行分别控制了preload和 teardown 过程。但是下列情况下想利用 13 行和 20 行这样简单方式控制

19、preload 和 teardown 会十分困难: ?有复杂的信号控制preload 和 teardown , 比如在视频算法中行同步和场同步信号参与 preload和 teardown; ?在循环里有多个子函数需要执行,而他们preload和 teardown 的条件不同; ?希望把主函数中的循环次数变为形式上的循环次数,真正的循环次数由参数控制。 /example for hidden preload and teardown 01: #define max_out 20 02: #define max_inn 200 03: class timing_control 04: 05: pu

20、blic: 06: int inner_max; 07: int outer_max; 08: int load_enable; 09: int save_enable; 10: int fun1_enable; 11: int fun2_enable; 12: int inner_break; 13: int outer_break; 14: void init(int _inner_max, int _outer_max) 15: 16: inner_max = _inner_max; 17: outer_max = _outer_max; 18: load_enable = false;

21、 19: save_enable = false; 20: fun1_enable = false; 21: fun2_enable = false; 22: inner_break = false; 23: outer_break = false; 24: 25: void check(int cur_inner, int cur_outer, int vsync, int hsync) 26: 27: if(loop_inner 100)&(loop_outer= 1 & loop_inner = 0 & loop_outer = 2 & loop_inne

22、r = 1 & loop_outer = 3 & loop_inner = 1 & loop_outer =103 & hsync) 49: inner_break = true; 50: else 51: inner_break = false; 52: 53: if(loop_out=11 & vsync) break; 54: outer_break = true; 55: else 56: outer_break = false; 57: 58: 59: void fun1(.) 60: 61: . 62: 63: void fun2(.) 64

23、: 65: . 66: 67: 68: void top_level_function(int in_a1000, int in_b1000, int out_c1000, int hsync, int vsync) 69: 70: int loop_outer, loop_inner; 71: static timing_control timing_controller; 72: timing_controller.init(100, 10); 73: 74: for( loop_outer = 0; loop_outer max_out; loop_outer+) 75: 76: if(

24、timing_controller.outer_break) break; 77: for( loop_inner = 0; loop_inner max_inn; loop_inner+) 78: 79: timing_controller.check(loop_inner, loop_outer, vsync, hsync) ; 80: if(timing_controller.inner_break) break; 81: if(timing_controller.load_enable) 82: 83: tmp_a = *in_a+; 84: tmp_b = *in_b+; 85: .

25、 86: 87: if(timing_controller.fun1_enable) 88: 89: fun1(.); 90: 91: if(timing_controller.fun2_enable) 92: 93: fun2(.); 94: 95: if(timing_controller.save_enable) 96: 97: *out_c+ = tmp_out; 98: 99: 100: 101: 图 6. 隐藏 preload 和 teardown 在上面图 6 的例子里使用timing_controller这个 module 为主函数中所有的读写和函数调用产生enable 信号,

26、这样主函数的框架变得清晰明了,当某一函数的enable 信号的生成机制改变的时候也不需要对主函数进行修改。每一个函数是否执行仅仅和自己的enable有关而与其他信号无关,便于debug和对生成的rtl代码进行优化。在timing_controller可以使用非常复杂的enable 信号生成算法而不会把主函数变得非常复杂,难于调试。 此时,主函数的循环只是引入了clock 信号而已,其他都由timing_controller控制。 3.5 可综合的 c+ 代码 正如传统的编写rtl代码一样, 综合结果的优劣取决于rtl代码的编写风格, 同样为了使 catapult sl生成高质量的rtl代码。我

27、们采用以下几种方法来优化我们的c+ 代码。 ?避免使用双变量乘法 01: / 1/4 pixel linear weight 02: void fun1(int in_a, int in_b, int weight, int &out_c) 03: 04: out_c = (in_a * weight + ( 4 - weight) * in_b + 2)/4 ; 05: 06: void fun2(int in_a, int in_b, int weight, int &out_c) 07: 08: if (weight = 0) 09: out_c = in_b; 10:

28、if (weight = 1) 11: out_c = (in_a + 3 * in_b + 2)/4 ; 12: if (weight = 2) 13: out_c = (in_a + in_b + 1)/2 ; 14: if (weight = 3) 15: out_c = (in_b + 3 * in_a + 2)/4 ; 16: if (weight = 4) 17: out_c = in_a; 18: 19: void fun_top(.) 20: 21: int a8; 22: int b8; 23: int c8; 24: . 25: for( int outer = 0; ou

29、ter max_loop; outer+) 26: 27: . 28: for( int i = 0; i8; i+) 29: 30: / difficalt to pass rtl verification 31: /fun1(ai, bi, weight, ci); 32: 33: / easy to pass rtl verification 34: fun2(ai, bi, weight, ci); 35: 36: . 37: 38: 39: 图 7. 避免使用双变量乘法例如上面图7第 2 行的 fun1 和第 6 行的 fun2 实现一样的功能四分之一像素精度的运动补偿, fun1

30、中乘法器两侧都是变量而且一共有2x8 个乘法操作,生成rtl代码和验证的时间较长,而改为fun2 的写法之后可以很快地生成rtl代码,而且c+ 代码的功能和生成的rtl代码的功能能很快地通过验证。 ?减少嵌套的层次 在上面第 8 行到第 17 行的 if语句都是并行的如果改成下图8 面写法会降低rtl性能。08: if (weight = 0) 09: out_c = in_b; 10: else if (weight = 1) 11: out_c = (in_a + 3 * in_b + 2)/4 ; 12: else if (weight = 2) 13: out_c = (in_a +

31、in_b + 1)/2 ; 14: else if (weight = 3) 15: out_c = (in_b + 3 * in_a + 2)/4 ; 16: else if (weight = 4) 17: out_c = in_a; 图 8. 减少嵌套的层次尽量并行执行?增加中间变量,避免反馈 在下面图 9 例子里 4 行到 11 行形成了把sum和一个数相加在反馈给sum的逻辑,catapult sl 产生的 rtl代码会有同样的反馈回路,关于sum的电路迟延会加大。而使用19行到 21 行的实现方法生成的rtl性能更好。 01: void fun1(int a8, int &

32、sum) 02: 03: sum = 0; 04: sum += a0; 05: sum += a1; 06: sum += a2; 07: sum += a3; 08: sum += a4; 09: sum += a5; 10: sum += a6; 11: sum += a7; 12: 13: 14: 15: void fun2(int a8, int &sum) 16: 17: int tmp03, tmp47; 18: 19: tmp03 = a0 + a1 + a2 + a3; 20: tmp03 = a4 + a5 + a6 + a7; 21: sum = tmp03 +

33、tmp47; 22: 图 9. 增加中间变量,避免反馈四、节约时间的技巧 在综合比较大的算法或者结构设计时,综合时间成为一个重要的问题,无论算法工程师还是结构工程师都希望尽快得到综合结果。为了节约时间可以从以下三方面入手。 4.1 充分调试 c+ 代码 ?算法输出必须正确,满足设计要求; ?没有语法错误,符合catapult的格式要求; ?没有内存越界和泄露, streaming的大小或者说定义这个streaming的数组的大小必须大于等于对这个streaming访问时涉及到的范围; ?如果 c+代码是在 visual c+环境下编译执行的,要保证c+代码在 linux 编译工具下也可以正确的

34、编译执行并且产生正确的结果。 4.2 使用递增的实现方法 如果设计比较复杂,如果直接根据最终输出的错误进行调试会比较困难,可以在一些中间结果上设置 “probe”输出。例如原始的代码如图10 所示,第一步首先验证sub_fun_1 的输出是否正确, 然后验证第二步sub_fun_2 的输出是否正确, 在某一步出现错误时可以有针对性地进行debug 。 / original code and final code void sub_fun_1(int in_a, int in_b, int &out_c); void sub_fun_2(int in_a, int in_b, int &

35、amp;out_c); void sub_fun_3(int in_a, int in_b, int &out_c); void main_function(int a1000, int b1000, int c1000) int i; int t1, t2, t3, t4, t5; for(i = 0; i 1000; i+) t1 = ai; t2 = bi; sub_fun_1(t1, t2, t3); sub_fun_2(t3, t2, t4); sub_fun_3(t3, t4, t5); *c+ = t5; 图 10. 原始代码 / step 1 debug code void sub_fun_1(int in_a, int in_b, int &out_c); void s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论