System Design with SystemC 的学习笔记

无责任书评

写此书评的主要目的是为该书平反,System Design with SystemC这本书在亚马逊上仅仅被评为2.5分,且参与评论者对此书颇有非议。我也受其影响,一直没敢读这本书。

最近由于对SystemC实在有些问题不明白,而其他书上都讲得实在太浅,尽是一些对用法的简单描述,看过以后也许你的确会知道如何写 SystemC,但你却不知道何时应该使用SystemC,应该怎么写,TLM到底是什么,应该用在什么地方,何时应该用SystemC写RTL,有什么好和不好的地方。客观的说,本书的确不适合作为SystemC的入门教材,但你学过SystemC的基础知识后,回头在看这本书,就会发现本书写得的确很精彩,回答了很多你想知道的问题。

因此强力推荐!






Foreword

Foreword的作者是Wolfgang Rosenstiel,欧洲SystemC用户组(ESCUG)的组织者。这位老兄对本书的评价很高,认为它即可作为学习SystemC的教材,也可做完数字集成电路工作者(设计师、验证师)的极有价值的参考资料。

Wolfgang说,SystemC从出现到成为系统级设计语言中的老大只用了不到两年的时间。该Foreword写于2002年3 月,SystemC的现状(2008年)到底如何,我也不敢肯定,也许并没有像当初期望的那么顺利吧,比如我一直想找一个使用SystemC完成全部前端设计的实例,就一直没有找到(当然不排除我能力有限,毕竟我之前一直从事软件设计,开始关注软硬件协同设计的时间还很短);但UML-SoC08的征稿中也强调,希望能获得SystemC在产业中实际应用的案例;且本书写于2002年3月,但至今也没有新版,不知是否说明什么问题。
Foreword中说在SystemC出现之前,人们已经开始使用C++语言设计可执行系统规约,有了SystemC,这些可执行系统规约就可以非常自然的被精化为TLM。很遗憾没有实例,这句话给我一个理性认识。

Foreword说SystemC虽然是一个系统级建模语言,但本书仍然给出了在像RTL、行为级这样传统的抽象级别上SystemC是如何使用的。此外,本书对如何用SystemC进行基于数据流的功能模型也做了介绍。从我初读此书的感觉,书中的相关介绍的确很有价值,让我这样一个没有任何 VLSI设计经验的读者也对这些传统的抽象级别,以及SystemC如何用于这些抽象级别有了较为深入的认识。

书的第3~8章随着抽象层次的逐渐提高,逐层介绍了SystemC在各层的应用,而第九章又介绍了抽象层次从高到低的转化(或者说是精化)过程。Foreword对第九章“通信精化”的评价很高,认为其中给出的“软件——软件”通信精化和“软件——硬件”通信精化都是大家十分关注但一直没有得到正面回答(或者说示例)的问题。同样的问题还有SystemC下的IP重用,Foreword认为本书也给出了实用的答案。

总之,Foreword对此书是极力推崇的。


致谢

致谢中提到一些人值得一提:
Abhijit Ghosh:SystemC的技术领导;
Martin Janssen:定义了SystemC2.0,并创作了其参考模拟器实现,作者认为该模拟器品质很高;

Ric Hilderink:创作了simple-bus这个TLM示例应用,该应用在SystemC2.0的example中,且是本书非常重要的第八章(事物级建模)中引用的示例;相信这个例子的确写的不错,但文档对该TLM的如何在实际中应用发掘不够深入,批评一下;本书试图对其做一些挖掘(如第九章的“硬件——软件”通信精化),但我还是觉得隔靴搔痒,因为大多数细节都只是泛泛而谈,没有实例。





1. 介绍

所以选择C++而不选择 Java作为系统级建模语言的basis的原因在于Java缺乏相关的实验性的实现,在表达系统级规约方法使用的人不多,且性能可能也是一个问题。

没有一个标准的、被广泛接受的系统级建模语言,IP核在系统级的开发、交流、重用都存在很大的问题。RTL级别的IP核存在仿真速度慢、知识产权保护困难、高层体系结构探索受限等等许多问题。VSIA制定了IP核的系统级模型应该满足的一些特点,如接口实现分离等等,所有这些特点在SystemC中都有很好的对应 construct支持。

引文26有关于软硬件协调设计的信息。

SystemC2.0规范的开发时间为2000年中至2001年中。2.0版本改进了时间模型,包括了动态敏感表、通道、端口、基本通道和分层通道,另外,将SystemC之前与特点开发方法学相关的内容分离出来,形成与开发方法学无关的语言核和方法学相关的库。

Real design hardly ever start with a “clean sheet paper”,言下之意即是说没有任何设计是没有任何“负担”,从头开始的;或者说,任何设计都是基于一些现有的基础开始的。

一些需要同时使用不同层次的抽象模型的设计场景:
  • 手头待测设计是一个详细的、实现级的模型,而该待测设计的激励生成以及响应检测模块则是一个抽象模型;
  • 手头的设计的确是详细的、实现级的模型,但为了提高测试速度、保护知识产权,特意为其创建一个高层的抽象模型;
  • 系统由很多模块组成,一个模块已经完成从高层抽象模型逐渐精化为一个实现级模型的过程了,但其他模块还没有完成此精化过程。
  • 模型的所谓“精确”应该是有好几个维度的,分别为:
  • 结构精确:包括硬件和软件。硬件指各模块的管脚精确;软件则是指各模块之间的通信已经精化到由RTOS的原语表达。
  • 时序精确
  • 功能精确:高层抽象中为简化模型不排除对一些功能也做了简化的可能,比如在高层模型中使用了浮点数,那么在底层模型中肯定要被替换为定点数。
  • 数据组织精确:SystemC的软件模块中使用的数据结构与最终的软件实现是否一致。
  • 通信协议精确:高层模型中的通信协议可能是比较抽象的,如TLM就将所有的通信统一抽象成阻塞式和非阻塞式两种,模型精化过程中当然要代之以具体的通信协议。


此外,讨论精确性时我们还有区分所谓精确是仅仅在模块的边界上精确还是深入到模块内部所有的子模块了。


几个不同的抽象层次:
  • 可执行规约:有系统规约直接转换为SystemC得到,与任何可能的具体实现都没有关系,如果该模型中有时延,那么该实现是系统约束。可惜书中没有给出一个这样的与任何实现无关的、有系统规约直接转化来的SystemC可执行规约的例子,我很希望能看到一个这样的从系统规约开始直至RTL的系统的完整实现。
  • 无时序功能模型:书上说其与可执行规约非常相视,不同点仅在于无时序功能模型没有任何时间约束,不太明白什么意思。又说无时序功能模型中模块之间的通信都是点对点的,通过Fifo,没有为像总线这样的用于通信共享的模块建模,还是不太明白。
  • 时序功能模型:时序功能模型与无时序功能模型的相似之处就在于它们的模块的通信都是点对点的,无需为像总线这样的共享通信模块建模,并且模块的通信都是使用的fifo的阻塞式读写方法。不同之处在于,在时序功能模型中,需要为process添加时延以模拟处理需要的时延,需要修改fifo添加时延以模拟通信时延。此外,时序功能模型广泛应用于确定软硬件划分,通过将同一个process分别映射为软件实现和硬件实现来比较效果。如何应用于确定软硬件划分的啊,又是泛泛而谈。



注意以上的可执行规约、无时序功能模型、时序功能模型都无法对应最终实现的结构,因为它们根本就没有结构信息。书上说第五章会描述如何用SystemC建立以上三种模型。但似乎没有看到可执行规约啊。
  • 事务级模型:在TLM中,模块间的通信是通过方法调用来完成的,因此就功能来说,TLM的通信是功能精确的,甚至通过在方法调用中加入时延,还可以让TLM的通信达到时序精确。但 TLM的通信不是结构精确的。另外,所谓平台TLM,除了以上TLM的特点,就结构而言,还精确描述了系统的模块及模块间的关系。因此,平台TLM可精确模拟总线负载、总线竞争以及系统的整体性能,并且可以在系统开发的早期,就提供一个高性能、精确、高效的方式来模拟软硬件交互。
  • 行为模型:行为模型中的模块在模块边界上是结构精确和功能精确的,但不是时序精确的,且在模块内部也不是结构精确的。行为模型可以为工具直接综合。
  • 模块边界上是结构精确、时序精确、功能精确的,且在模块内部也是结构精确的。


本书的源码按照书中所说的方式根本下不到,书中描述的网站的Product & Solution都根本不存在。




3. MoC

计算模型的非形式化定义:
  • 使用的时间模型(实数时间、整数时间、无时间)和事件机制(全序还是偏序);
  • 事件的激活机制;
  • 对同步进程的通信机制的支持


像Verilog、 VHDL这样的硬件描述语言只支持一种计算模型,且该计算模型还不可定制,SystemC则不然,虽然它也有一个基本的计算模型,但该模型可非常容易的定制且它还支持其他计算模型。

SystemC可支持的计算模型包括:
  • 静态multirate数据流
  • 动态multirate数据流
  • Kahn process network
  • RTL硬件建模
  • 网络建模
  • 基于事务的SoC平台建模



以上这些模型分别是什么意义,SystemC是如何支持它们的,不太清楚。

为什么SystemC要支持那么多计算模型?因为很多系统本身就不是同构的,而是由很多模块组成,各个模块使用了不同的计算模型。且同一个模块在不同的抽象层次上用不同的计算模型表达可能更加合适,例如,一个模块在功能建模时可能用静态multirate数据流表示比较合适,而在硬件建模时则用RTL模型更为合适。

目前OSCI有很多工作组,正在致力于为不同的计算模型制定标准。

RTL计算模型其实是对通过时钟信号来同步数字硬件的建模风格的一种非正式称谓。

RTL风格的建模中,process之间通过signal进行通信,process可通过敏感于时钟信号来表达时序逻辑,也可通过敏感于所有输入来表达组合逻辑。RTL模块是管脚精确以及时钟周期精确的。SystemC中的signal与VHDL的signal相似,与verilog的时延赋值(<=)相似,但 SystemC的signal不能指定赋值时延,因为SystemC的开发者认为既然也无法指定组合逻辑的时延和门时延,那么指定赋值时延就没有什么意义了。评论都说verilog在RTL的表达能力最强,而SystemC最弱,不知是否就是因为这个原因,那么我孜孜以求的想找一个从系统级精化至RTL级的示例,这样的示例也许因为没有意义而根本就不存在。

Kahn Process Networks(KPN):在KPN计算模型中,所有模块都通过一些无限长的fifo通信,无限长fifo使得模块对fifo的写是非阻塞的、读仍然是阻塞(初始时fifo可能还无数据)的。如果系统完全使用KPN建模,那么系统一定是确定的,既是说进程不同的执行顺序不会影响系统的对外表现,但具体是如何保证的,我还是不太理解。KPN系统中没有时间的概念。无时序功能模型就可以认为是KPN了。

静态数据流(SDF):KPN的一种特殊情况,表现在:

进程执行被明显的分为读数据、处理数据和写数据三个明显的阶段;

进程执行时将读写的数据是确定的,在编译时就已知了。

用SystemC表达SDF的方式就是使用第五章中描述的数据流建模风格。注意数据流建模风格较之 SDF更加的一般化,何谓更一般化,没看懂。

TLM:TLM中模块之间的通信是通过方法调用完成的,进程之间通过共享数据完成数据交换,因此,如果没有一个同步机制,这种数据共享的方式很可能造成系统行为的不确定性。 SystemC往往通过所谓的两阶段同步机制来保证系统行为的确定性。




4. 使用SystemC建立经典的硬件模型

经典硬件模型是指RTL和行为级。

行为模型仅仅比RTL略高一级,行为模型中输入输出也是通过时钟同步,只不过其时。钟的精确时钟周期数不定。

在RTL这个抽象级别上,电路被描述为功能单元之间的同步传输。功能单元以及它们之间的连接被统称为数据通路,发生在数据通路上的传输受一个控制单元的控制,以时钟作为同步。控制电路的行为一部分决定于数据通路上的状态信号,一部分决定于电路的外部输入。RTL模型由数据通路和控制电路组成。RTL模型中,每个时钟周期上执行什么操作都是确定的。RTL的另一个特点就是对数据的传输时延以及计算时延的忽略,因为RTL假设数据的传输和计算用时都为0,如果此假设不成立,例如某些多时钟周期的计算,那么设计者只能在RTL模型中使用wait显式添加时延。

Signal支持 request-update/update方式的访问,所谓request-update/update,就是指对signal上数据的更新分为两个阶段,分别为请求更新阶段和实际更新阶段,两个阶段之间有一段不限小的时间,即所谓的delta-cycle。Signal的这种行为非常类似于寄存器,因此用signal来表示寄存器就非常的自然。另外,当用于连接两个组合逻辑电路时,signal则被用来表示连线了。虽然signal的行为类似寄存器,但建模时通常不会由signal来表示寄存器,而是由综合工具根据其内部规则将相应的代码自动生成寄存器。通常,RTL模型中的process用于计算输出、计算电路的下一个状态、指定寄存器之间的数据传输,process之间的通信则通过signal完成,那些只在一个process内有效的数据则通过 process内的局部变量存储。

就SystemC来说,RTL模型的特点就是端口只使用sc_in、sc_out、sc_inout,通信都是通过sc_signal,process只使用 SC_METHOD。

最好在RTL模型的 ctor中初始化所有的signal、member variable、port。

行为层:在这个层次,主要关注输入输出事件的相对顺序而不是精确的时钟周期。

行为层与RTL层最大的不同就在于在RTL层设计者需要确定电路有那些状态,这些状态之间如何变迁,在每个状态下要执行那些操作。此外,在RTL层,设计者还要事先知道系统有哪些资源(如功能部件和寄存器)可供使用以及如何共享它们。RTL层的这些特点大大限制了设计者在探索不同的设计方案时的灵活性,因为设计很难改动,电路的任何一处有一点修改就需要对其他部分做相应的调整。

一次相对,行为层允许设计者将他们的设计描述为一个执行流程。外部行为是通过输入输出事件来定义的,而不是通过时钟周期。内部行为与时钟周期的映射关系以及与功能部件的映射关系在此并不重要,因为这些都是所谓的“细节”,可以在今后手动或者通过行为综合工具自动生成。
行为层与RTL层一个共同的特点就是它们都是管脚精确的。

本章主要讨论同步行为建模,在这种建模方式下,输入输出事件是有序的,且通过一个时钟同步,signal这是主要的通信通道。需要说明的是,行为层中的时钟与 RTL层的时钟并不相同,行为层的时钟只是作为一种排序和同步机制,其一个周期在最终实现时可能会是RTL时钟的好几个周期。行为层通常使用 SC_THREAD类型的process,且process必须敏感于时钟的上升沿或下降沿,而不能敏感于其他任何事件。

SC_CTHREAD类型的process,与SC_THREAD类型的process非常相似,只不过它必须敏感于时钟信号的上升沿或下降沿,且它引入了两个新的构造元素 watching和wait_until。该类型的process的仿真的初始化阶段不会执行(与之相对,其他两种类型的process在仿真开始时就会执行,除非指定了dont_initialize)。

行为层的process通过使用wait和wait_until语句来划分它的I/O周期。所谓I/O周期,指的是一段时间,在这段时间内,process不会即与外部环境交换数据同时又在处理数据。wait_until语句允许设计者指定一个条件,只有但条件成真时,process才会继续执行。条件也是由时钟同步的,条件中涉及的信号的值只有在时钟边沿上采样,因此process对signal值的变化的反映并不是即刻的,而要推迟到下一个时钟周期。

Thread类型的 process允许状态保持,即是说,其执行可被wait这样的方法挂起,直到其敏感表上有事件发生才继续执行,因此,Thread类型的process 在描述待实现算法的流程时可以非常的自然。

wathcing(reset.delayed() == true),表示监控reset信号,但其为真时就跳出cthread process。delayed()使仿真器在每个时钟周期都采样reset信号,否则只在process开始时采样一次。另外,cthread process的跳出是发生在reset变为真的下一个时钟周期,这就是所谓的同步复位。
wait_until(reset.delayed() == true)与之完全类似。

行为模型只关注I/O事件的相对顺序。

在行为模型中,我们只关注整体的执行流程,我们不需要状态变量来显示指明当前我们处在计算流程中的哪个位置。例如,对于刚才的那个例子,其中的“>=”和“-”操作,我们的行为模型并没有指明这两个操作在最终实现中应该发生在哪个时钟周期。然而,在RTL层,我们则可能需要将焦点集中在电路状态上,电路是如何从一个状态进入另一个状态的,在此过程中应该产生哪些控制信号。例如,对于刚才那个机器人控制器的例子,如果该控制器有更多的算术运算,那么我们将看不到这个使用最自然的执行流程来描述的算法,而只能看到一堆预先设计好的数据通路以及由一个有限状态机产生的控制信号(用于控制电路中的操作和数据传输)。

行为层模型在每个时钟周期上行为的不确定性使得我们在验证其正确性时不能通过逐个逐个周期的检查电路在该周期上的值与预期是否匹配的方式来决定。因此,我们应该基于握手协议来编写 testbench,这样testbecnh即可适用于行为模型,也可适用于精化后的RTL模型。

就性能而言,SystemC中sc_int<W>、sc_uint<W>的性能是最好的,基本类型次之。

应该尽量避免使用未初始化的变量(特别是bool类型)。

and_reduce运算,将变量的所有位相与,得到一位结果。例如and_reduce(11000)的结果为1&1&0&0&0=0。



5.功能建模  

在设计流程的早期,特别是在软硬件功能划分都还没有确定的时候,我们关心的只是对系统各组件功能的描述。像时序、细粒度的结构、底层通信协议细节这样的细节在此时都一个避免涉及。

无时序功能模型通常被用来描述和分析信号处理单元,如滤波器、解码器、解调器等等。

当分析系统行为需要建模时序关系时,或者功能模块仅仅是作为其最终实现的一个placeholder时,可能需要时序信息。

建模无时序功能模型时,最常使用的是数据流模型。SystemC中的数据流建模与其他方式存在的最大不同就是fifo的大小是确定的。要为一个无时序功能模型添加时序其实非常简单,只要在process中加入wait语句以表示处理时延即可。

使用SystemC建模时,无时序功能模型和时序功能模型可以和平共处和交互。底层的事件驱动的仿真语义加上有限长的fifo使得将两种模型连接起来是完全可能的,且非常容易。

感觉功能建模与第四章的 RTL和行为建模的不同点就在于:

第四章的RTL建模和行为建模都是硬件建模,即为那些已经确定为使用硬件实现的模块建模;而功能建模的关注点仅仅在于对模块的功能的描述,最常用的功能描述方式即数据流描述,且建模是发生在软硬件划分之前的。

RTL建模和行为建模都是硬件建模,因此都是管脚精确的,模块间通过signal通信;而功能建模毫无管脚的概念,模块之间通过fifo通信。




2.10 仿真语义

SystemC的仿真是基于事件的仿真,虽然SystemC中存在时钟的概念,但此时钟只是一种事件触发机制,没有绝对时间的意义。例如在2秒触发一次,5秒触发一次,10秒再触发一次,如果2秒、5秒、10秒之间都没有其他时钟,那么完成2秒的触发就是5秒的触发,完成5秒的触发就是10秒的触发,根本没有分别间隔3秒、5秒的概念。

SystemC的仿真语言如下:

S1(initialize):将所有SC_METHOD类型的process执行一遍,将SC_THREAD类型的process执行到第一个wait,除非这些process指明了dont_initialize()。

S2(evaluate):找一个ready-to-run的process,继续其执行,执行过程可能引发immediate event,从而导致新的process ready-to-run。但注意应该尽量避免immediate event。

S3:如果还有ready-to-run的process,则转S2。

S4(update):遍历所有在之前的evaluate阶段注册了request_update的process,执行它们的update方法。update方法的执行可能导致一些event的触发,这些event可能部分或全部都是delta_cycle类型的。

S5:由于S4中delta_cycle类型event的触发,一部分process又可能ready-to-run了,因此仿真流程返回S2;注意此过程仿真时间并不推进。

S6:如果事件队列上没有任何定时事件(由带参数的notify函数调用参数,或clock产生)了,那么仿真结束。

S7:否则,将仿真时间推进到离当前时间最近的定时事件所在时间。

S8:找到那些由于S7中的定时事件而ready-to-run的process,返回S2。




为何TLM中只有blocking和non-blocking transfer就可以了?  

一直在想为何TLM中只有blocking和non-blocking transfer就可以了?

今天看了一篇文章突然有了灵感:一个软件系统就是由完成各个功能的类以及将一组类联系在一起构成一个整体的消息机制组成。与之类似,描述一个硬件系统,首先描述各个功能模块,然后通过总线将个模块联系起来形成系统.

总线的功能有点类似于软件的消息机制,但不同之处在于软件的消息机制在实际中既是函数调用,而函数调用的具体完成由于OS的存在,对软件开发者完全透明;而硬件系统则不同,模块之间的通信最终必须通过某种形式的总线 ,而总线必须由系统设计者自己设计。TLM最抽象的编码风格也用函数调用表示模块之间的通信,但随着抽象级别的降低,这些函数的最终实现仍是总线上transaction的收发。类比软 件,相当于OS帮我们完成了以上所有与总线相关的工作。

总线上transaction的收发,无非就是抽象为阻塞和非阻塞两种方式,因此TLM有blocking和non-blocking transfer,就足够描述系统的事务级模型了。


原文http://www.opengpu.org/forum.php?mod=viewthread&tid=2436

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值