SIMC软件规范.docx
- 文档编号:24558443
- 上传时间:2023-05-28
- 格式:DOCX
- 页数:28
- 大小:32.89KB
SIMC软件规范.docx
《SIMC软件规范.docx》由会员分享,可在线阅读,更多相关《SIMC软件规范.docx(28页珍藏版)》请在冰豆网上搜索。
SIMC软件规范
符合软件思路。
同时具有硬件模型的实质意义。
SystemC就是HDL的翻版。
思路和软件相差太大。
两种对象:
事件和信号
事件对象是顶层对象,其所包含的信号对象只受此事件驱动。
事件对象被统一调度。
事件对象的事件可以在运行过程中被设置。
事件对象构成事件域。
信号对象必然属于一个事件对象。
不给则属于默认的时钟事件对象。
模块必须是由单一事件驱动的。
这是事件驱动的实质精神。
符合思维解决问题的方式,是软件可读性的保证。
模块结构和事件驱动是一致的
事件和信号值分离。
事件的计算:
1)延迟设置,手动清除。
2)延迟设置,自动清除。
事件行为属性:
设置和清除都触发
只有设置触发
只有清除触发
设置和清除都不触发
事件既是硬件模型的驱动源,也是软件线程同步的对象。
事件同时也是1bit信号,接受受自身的驱动。
仿真时间问题:
软硬件终究要同步的。
因此时间终会互锁。
但是这个过程是怎么样的呢?
能否逼真?
时钟总在运行,如何限制时钟流逝?
硬件“空闲状态”的识别?
还是信号记录屏蔽?
目的是减少仿真记录数据量。
对象同步访问:
一个事件发生时,对象允许被同时读写。
读到上一个时刻值。
这称为时钟级别的运算行为。
对象异步访问:
需要同步保护。
保护读写不同时进行。
多驱动模块和组合逻辑模块等价,组合逻辑可以用“事件”模拟。
每个组合逻辑信号是一个“事件”,事件之间互相驱动。
VHDL评价:
事件驱动是最底层的运算平台,它藏而不见。
给用户用的最基本元素是“赋值语句”。
赋值语句a=b用事件驱动的语言可以表述为“只要b上有事件发生,就进行赋值”,显然这是事件语义的综合表达,是“综合语句”。
这种综合语句与硬件组合逻辑直接对应,在一个水平上。
这导致了VHDL的困惑。
因为本质是“事件驱动的运算平台”,但是操作的却是“赋值语句”这种“综合结构”。
这种二元性质是VHDL致命的缺点。
“变量”和“信号”的不同也是VHDL的一个问题。
归根结底,VHDL是面向硬件的语言,而不是一种纯粹的软件语言。
尴尬的局面在于:
对硬件设计人员,VHDL太软件化了,模块、函数、过程、包等概念太抽象;而没有硬件基础,心里不装着模块、端口、信号、时钟、触发器、复位线等硬件概念,是绝没有学会VHDL设计的可能,这是软件设计人员的灾难。
总的来说,就VHDL设计来说,让硬件人员学习软件比让软件人员学习硬件要容易。
设计一套让软件人员使用的语言是很有意义的。
变量、事件驱动概念。
关键问题:
1)硬件模式的综合
2)区分并行计算域和普通软件域。
这里的概念、设计模式、边界。
技术路线:
恢复VHDL底层运算平台:
事件驱动、信号和变量的统一。
制定可综合程序规范。
VHDL是先放后收,给出宽泛的设计自由,然后提取可综合模式;不恰当地说,VHDL的非综合因素其实质是模仿软件语言,对于现在从软件出发来说,这是不存在的。
需要的只有综合规则。
“变量”代表信号状态、寄存器、存储器都是可以的。
硬件模式类型有如下几种,如何综合出来?
组合逻辑运算
寄存器(赋值、异步复位/置位)
锁存器
RS触发器
事件代表变量值的变化:
事件驱动的定义:
所有的计算由事件驱动,这是运行模式、也是设计模式、也是程序结构。
硬件设计就是事件驱动的程序设计。
可综合规则关键是多驱动形式的识别和规范问题。
组合逻辑:
多驱动,每个驱动都不区分沿。
锁存器:
双驱动,?
?
?
寄存器:
双驱动,?
?
?
RS触发器:
双驱动,?
?
?
定义4种类,表示不同的电路模块。
程序只有细化到这个层次,才是可综合的。
一般电路模块是基本电路模块的组合。
采用程序自动翻译成VHDL语言。
把可综合问题交给VHDL。
维护C++语言向VHDL的可翻译特性。
简化电路形式:
1)支持寄存器,但不支持异步复位/置位。
2)不支持组合电路。
3)不支持锁存器
4)不支持RS触发器
不谋求可综合,仅支持波形产生,做研究用。
空闲态识别,识别硬件在等待,不记录波形
变量和信号的区别仅在响应同一个事件时体现出来,在统一个时刻上咱开运算,需要区分前一刻和后一刻的问题。
所有的赋值发生在事件发生时,用这样的方式描述的寄存器是什么样子的?
Register-clk:
clk’eventandclk=1anden=1andrst=0=>Q=D
Register-en:
Register-rst:
(sig’eventandrst=1)or(rst’eventandrst=1)=>Q=sig
其中sig可以是一个变量,也可以用0或1的常量代替。
推理为:
clk’eventandrst’eventandsig’event
Ifrst=1thenQ=sig
Elseifclk’eventandclk=1anden=1thenQ=D
Latch-en:
en’eventanden=1andrst=0=>Q=D
Latch-D:
D’eventanden=1andrst=0=>Q=D
Latch-rst:
(sig’eventandrst=1)or(rst’eventandrst=1)=>Q=sig
推理为:
en’eventorD’eventorsig’eventorrst’event=>
ifrst=1thenQ=sig
elseifen=1thenQ=D
elseQ=Q
组合电路:
A’event=>Q=f(A,B)
B’event=>Q=f(A,B)
推理为:
A’eventorB’event=>Q=f(A,B)
能否基于事件表达式,进行公式推演,最后归于一个固定的特征形式?
这是很有意思的命题。
而反过来说,这些表达式不是更简洁吗?
我们甚至可以不用考虑事件问题,表达式包含的所有信号都是其敏感的事件。
又回到VHDL定义的起点了!
最后证明事件驱动的概念是没有必要的!
这只说明综合和设计的不同。
综合是以预设的电路结构为前提的。
也恰恰说明事件驱动和VHDL在形式上的巨大不同。
VHDL的端口是形式端口,正是端口列表给出了敏感信号,而同时敏感进程中的语句中可以默认提取出敏感信号。
于是在VHDL中事件是没有必要强调的。
相反,我们这里要创造的东西,端口只是值能力的“信号”,没有事件能力。
事件是我们要强调的东西。
那么,敏感进程中如何指示信号呢?
1)从端口中提炼?
-从信号中产生事件,那样和VHDL无异。
2)创建单独的事件接口?
-只是新的“端口”,本质上也和VHDL无异。
3)向Windows程序那样,用预先定义的编号指示信号。
4)象异常一样,用有类型的对象表示事件。
鉴于实现复杂程度的考虑,采用事件编号是方便的方式。
VHDL把所有的信息局限在模块内部:
由语句结构可以判断综合结果。
这种事件和信号分离的方式则有问题,无法进行综合优化。
因为综合时,判别事件和信号是否等价是重要的。
事件和信号分离,则无法进行这种判断。
那么,限制只有时钟驱动是有意义的,也是比较实用的。
也不支持异步复位。
这样可以避免定义事件。
组合逻辑指对所有事件都计算,组合逻辑模块可以通过属性标识。
这样也可以避免定义事件。
如此,综合问题也可迎忍而解。
随机事件:
让当前时间步进一个随机值则可模拟随机事件。
这是CPU接口的问题。
一个模块可以不接受时钟驱动。
它仅仅是一个计算模块,受其它模块调用。
但是,这样的模块不方便综合。
具体的翻译问题:
很多,看来翻译为VHDL仍然不是一件容易的事情。
内外名字的区别问题。
因为不支持信号立即赋值,起内外两个名字就成会导致问题。
变量代替!
指针的使用:
如何翻译?
移位操作:
如何翻译?
控制语句:
取消信号赋值语句,就不能创建“等价信号”。
但总能通过变量解决问题,还没有发现变量不能处理的!
无非两种情况:
1)为输入端口创建别名:
可以用变量作为别名,则立即获得值而不必延迟一个时钟事件。
输入端口是不可写的,不存在变量/信号写效应的不一致问题。
2)为输出端口创建别名:
可以用变量代替。
输出端口是不可以读的,变量和信号不会造成差别。
3)双向端口:
这样的端口不需要创建别名。
鼓励采用变量进行运算。
变量正是传统软件计算的基石。
限制信号的使用,信号是并行计算架构的支点。
出于结构清晰的考虑,必须限制信号的使用;把信号的使用作为软件结构和可读性的一部分。
事件的限定:
限定为上升沿或下降沿,如何限定?
一个信号关联一个事件对象,这个事件可以设置条件。
条件就是一个信号值。
事件总是关联一个状态,此状态表示条件是否成立。
即信号是否等于设定值。
等于设定值和不等于设定值都产生事件。
事件发生且状态为1,说明信号值变化到设定值。
事件发生且状态为0,说明信号值变化为不等于设定值。
事件的限定条件为状态为1或0;
结论是:
软硬件接口。
虚函数
仿真delt–零延迟事件处理完成后再进行信号值更新。
错!
信号不更新,如何产生关联的零延迟事件?
必须定义更新级别,区分是delt更新还是最终更新。
只有最终更新时才记录信号值。
必然先是一个delt更新,这样才能检测是否会触发delta事件。
事件调度是个关键问题,要做到任何时候都可以调度它。
同时多线程安全。
限定模块只能具有信号接口,不能具有函数接口。
这样是不是束缚了C语言的手脚?
反过来,限定模块只能有函数接口也是个很好的主义。
使用函数接口让硬件模块和软件更接近,但是映射到硬件时不太直观。
一般来说,取消函数可能更好些。
CSSignal
解决方法:
方案一,不允许操作符。
必须通过Val()函数。
方案二,定义一堆独立的操作符函数。
操作符函数必须作为全局函数,以便能区分不同的数据类型。
自动设置SetParent():
方法:
CSModule构造函数中把this设置为“当前模块指针”
派生类成员的构造函数执行时就找到了当前模块指针。
缺陷:
1)全局对象的初始化,“当前模块指针”未知;2)多继承时,“当前模块指针”有多个,选那个?
对策:
取消全局对象,规定有且只能有一个对象。
不支持多继承。
面向软件的硬件设计方法。
有两个基石。
借鉴VHDL的信号概念,支持并行计算。
这是第一个基石。
借鉴软件事件驱动概念,这是第二个基石。
希望这两个概念能为软件人员给硬件建模,理解硬件问题提供足够的工具。
事件引发计算,建立软件模块。
模块结构和驱动结构一致。
借鉴VHDL结构化概念,用类和对象代表模块;把信号作为对象之间的接口。
(用虚函数作为接口也可以进一步考虑)
如果我们的最终目的能够达成:
软件的设计能力一旦被释放出来,成功应用于硬件设计,效果是惊人的!
这是我们追求的结果。
仿真驱动和纯软件的同步:
纯软件具有多线程性质,如何可靠保护?
必须界定软硬件边界,以便能识别软件进入和退出硬件边界;进入时进行多线程保护,退出时运行仿真器消化事件。
软硬件接口是独立的函数接口,提供地址空间(访问)和同步事件(中断)。
同时截获软件进入和退出硬件边界的动作,驱动仿真程序和软件协调运行。
软件设计和硬件设计还是两个独立的领域。
但是,统一的事件驱动还是让设计上没有了边界。
软硬件边界:
方案一:
1)统一的地址读写函数:
Read()/Write()
2)硬件部分通过注册,把地址和变量关联在一起。
方案二:
1)直接访问硬件信号变量。
CPU接口的访问就是直接变量访问。
2)访问前使用Lock()锁定;访问结束使用Unlock()解锁。
数据记录能力
1)允许自定义数据类型的记录。
比如:
数组、结构等
2)事件对象应该也能记录输出。
CPU接口访问
可以直接被CPU接口写的信号对象,其默认属于CPU接口事件(驱动)。
因为一个信号只能被一个事件驱动,因此不能再属于其它事件。
Unlock()时更新CPU接口事件。
CPU接口事件有两种实现方式:
1)默认全局信号都是由CPU接口事件驱动2)必须明确定义一个CPU访问接口事件。
全局信号代表芯片的全部外围接口,不能等同于CPU接口。
所以,第一种方式是不妥的。
应该采取第2种方式,单独定义CPU接口事件。
系统时钟
默认认为全局对象都由系统时钟驱动,是不对的。
全局信号代表芯片的全部外围接口,并不是全部接口都和系统时钟同步。
可综合约定
Initialize()可以看作全局复位。
寄存器不支持异步复位和置位。
证明:
异步时钟边界1)CPU接口:
可以写1然后再写0。
2)异步时钟边界自动握手:
可以代替的。
构造函数给出变量名和父模块强制派生类构造函数的初始化,不是好的策略。
事件的定义有点矛盾:
既然只有时钟事件驱动,为何事件却那么一般,任何信号都可以产生事件?
这里显然留下了模糊性,给设计风格带来了不确定性。
给可综合性带来了探讨的话题。
只有时钟信号的事件是可综合的,综合时默认事件值和信号值总是一致。
这样综合时就可以忽略复杂的事件产生条件。
硬件模块的仿真都可以通过事件同步。
软件和硬件界面的同步是单向的,软件直接写的硬件信号需要被一个事件驱动。
多CPU界面需要多个这样的信号。
这信号是预先定义的,软件直接使用。
软件可以直接读任何硬件信号值。
但是不同步会导致数据一致性问题。
这种不一致性显然只有用高层协议,专门的硬件机制,才能解决。
软件可以直接等待硬件事件,没有必要增加其它动作。
确保模块不被同一个事件驱动2次的方法:
如果挂接到事件则不接受默认驱动。
仿真事件:
有一个戏剧性的问题,对事件使能设置和清除标志的目的是限定时钟沿,可是如果限定了,则时钟产生模块就无法正常驱动,时钟信号自己产生不了了!
所以,事件的使能限定对时钟信号来说是画蛇添足。
对“一般事件”,则事件的逻辑含义是“发生时”,“清除时”是没意义的。
需要的是“自动清除”特性。
仿真事件的定义:
具有事件和事件状态两个属性。
依据信号值定义属性含意。
1)事件:
指信号值发生了限定状态(值)的改变或者任意(无限定)改变。
2)事件状态:
当信号状态(值)有限定:
信号值符合限定范围则为“真”,否则为“假”;
当信号状态(值)没有限定:
信号状态的每变化一次,事件状态翻转一次。
事件和软件的事件等价,事件状态和软件的事件状态不等价。
事件的自复位特性:
和信号无关联,纯粹的事件。
与其增加事件属性,不如派生新的类。
引入“纯粹事件”:
CSEventPulse/CSEventClock/CSEventList
1)在响应事件的时候设置事件,多次设置只取最近的一次。
此行为和信号值设置一样。
2)在事件发生之前,重新设置会导致原来事件的丢失。
事件允许“多驱动”,事件设置操作的顺序是随机的。
研究这里的规则没有什么实用价值。
列表事件:
1)设置列表时清除原来的所有列表事件和当前事件。
2)SetEvent()/ResetEvent()的事件时间如果在当前事件之前,则替换当前事件,当前事件添加到列表;如果在当前事件之后,则直接添加到列表。
3)在同一个事件时刻设置列表和SetEvent()/ResetEvent(),后者无效。
4)列表事件回绕时,事件发生是否平滑?
出现delta0宽度的振荡?
或出现两次事件?
DUMP输出控制逻辑:
模块禁止输出则其子对象禁止输出;
事件禁止输出则其驱动的对象禁止输出;
2008/2/1~3/8:
功能基本实现
如何让整体上更好用?
一、输出文件的格式:
要做到和具体输出格式无关。
所有的输出用CSDrive提供的函数隔离。
借用ModelSim波形显示能力观察仿真结果。
1、VCD格式的文件。
文本格式,数据量大。
不支持回绕。
不台适合软硬件联合仿真的需要。
2、wlf格式的文件。
ModelSim解决长时间仿真运行数据记录的技术就是wlf文件。
优点有三个1)Wlf支持压缩,可以比VCD文件小千倍。
2)wlf文件支持文件尺寸限定,确保长时间连续运行。
3)wlf文件直接被ModelSim支持,不需要格式转换。
这样就可以让仿真和ModelSim的波形显示同步运行。
记录文件的创建。
仿真库初始化:
装载时初始化一次(构造函数时刻)
硬件平台构造:
应用程序启动时初始化一次(构造函数时刻)
第一次run():
自动进行restart()。
(程序启动后)
硬件启动复位:
restart()。
每次初始化变量状态都复位到初始值,并重新创建记录文件。
如果切换记录文件,必须重新restart()才能有效。
二、简化使用接口:
初始化:
a)自动初始化。
软件开机时总认为硬件是准备好的,如何保证软件访问硬件之前构造好仿真系统?
在软件第一次调用read()/write()函数的时候就准备好硬件平台。
定义“初始化initialize”对象,利用构造函数实现自动初始化。
如此,可以避免程序调用单独的初始化函数。
“初始化对象”的构造函数。
用户在这里“构造”整个硬件系统,定义全局变量名、构造事件驱动关系、构造CPU接口驱动的信号;初始化仿真系统的参数。
“初始化对象”的“启动initiate”函数。
“初始化对象”具有特殊的低温,仿真内核保证在其它对象启动操作之后再调用“初始化对象”的“启动”函数。
如此,仿真平台的启动复位可以集中在此函数中进行;也可以重新定义对象的启动行为,比如修改内存仿真对象的初始化值。
c)仿真系统参数设置函数。
一个函数设置所有参数。
独立的灵活的设置让用户无所适从。
或者一组设置函数采用相同的命名规则。
运行:
要自动化。
让其它部分感觉不到其存在。
自动运行入口scheduling(),用户可以创建10ms定时器驱动之。
或者在主程序循环中调用。
其它的替代方案有两个:
1)驱动器创建默认窗口,创建定时器;2)驱动器创建线程。
这两个方案让软件“不透明”、“不受控”;
第一种方法限制了控制台程序使用仿真库。
第二种方法引入多线程,让程序调试困难。
1、定义运行速度比例:
比如驱动线程睡眠事件和仿真事件之间的比例系数。
采用“空闲”判断,可能软件仿真的速度比硬件实际运行的速度还快!
(从功能上看)。
适当调节驱动线程的优先级,可以分配软件和硬件的运行时间,让二者的比例和实际情况一致。
2、有效减小输出数据的数量是关键技术。
a)定义“空闲”状态。
空闲状态由核心的一个模块或几个模块决定,其它从模块总是处于“空闲”状态。
方法:
1)Trigger()函数的返回值决定空闲与否?
2)全局函数决定空闲否?
b)“条件捕获”技术。
定义有条件关闭/打开仿真记录的方式。
关闭期间显示‘X’状态。
c)“予触发捕获”技术-对关闭/打开操作的完善。
逻辑1:
“准备”-“确认”、“关闭”。
逻辑2:
内置固定N事件予触发缓冲区;用户只有“打开”“关闭”逻辑。
逻辑1更精确;逻辑2更自然。
3、记录文件技术。
记录文件大小限定。
自然丢失前面的数据,确保带长时间运行。
遗憾的是,ModelSim集成环境并不依赖libwlf.dll库,因此libwlf.dll中实现此功能的可能性极小。
1GB大小的磁盘文件,应该能支持1K个信号,1MHz/秒个事件,连续运行1小时。
CPU/软件访问接口:
一个足够了,这也是默认的访问接口。
也提供注册新接口的方式。
默认访问接口也需要创建而不是默认实现。
这样更清楚。
调试:
如何实现软件仿真和记录数据的显示同步?
1)再次打开WLF文件;波形窗口会自动更新波形显示,并能保持当前显示窗口的显示范围和光标位置。
编制DO文件,实现如下功能:
使用默认的WLF文件,simc.wlf。
Dumplog.exe文件向仿真窗口发送消息,锁定仿真器;
ModelSim重新打开WLF文件;
Dumlog.exe解锁仿真器。
2)能否做到不重新打开WLF文件,直接更新?
遗憾的是,ModelSim集成环境并不依赖libwlf.dll库,因此libwlf.dll中实现此功能的可能性极小
仿真控制台对话框:
进行记录文件刷新控制。
仿真停止运行控制。
对象结构浏览功能。
a)单个对象的输出使能控制;b)信号条件断点
调试断点时硬件运行应该停止。
则应该使用定时器驱动仿真;或者通过控制台手动停止仿真。
CSModule提供记录输出条件检测函数接口,在调试时可以频繁更改此函数。
全新的设计思路,一切都是新的,要有勇气。
又从已有的借鉴局部内容,这是“整合”过程,用全新的思路、面临全新的问题。
基本调试能力:
-借用ModelSim波形显示
-增强的记录选择能力。
提供基于模块、事件、单独对象的打开、关闭控制能力。
在DUMP之前增加条件检测阶段,若打开记录,则可以记录当前值。
提供注册回调函数,插入条件检测函数。
1)事件计数器。
事件对象内置计数器;全局条件检测函数支持计数器的复位;计数器作为时序周期的标记。
2)自定义条件检测函数。
条件检测不能在对象内实现,这样就把设计和调试混合在一起,不是好的方式。
“软硬件实时联合运行”是新的挑战!
-断点:
硬件状态断点–等价于记录选择技术。
软件访问断点–访问接口寄存器时的断点设置:
写断点和读断点。
断点的实现:
1)硬件状态断点的时刻是在DUMP更新之前增加条件检测阶段,提供注册回调函数,插入条件检测函数。
之后则不能检测信号值变化标记。
2)CPU访问断点的时刻,在Unlock()函数中,在设置CPU接口访问事件“之前”提供检测函数调用点。
信号在被读时也设置标记,以便断点检测函数检测。
因为信号也可能被内部读取,所以在Lock()时要清除读、写标记,Unlock()时就可以准确检测。
3)断点检测函数返回值为TRUE/FALSE,借用ASSERT()实现断点。
-可靠的硬件单步:
保证软件不乱。
-逼真的连续运行:
软件和硬件仿真之间的时间分配调整,要象真的一样。
1)基于事件的单步。
单个事件出现1次或N次。
2)基于时间的连续运行。
-运行停止
控制台根据名字选择事件。
提供事件列表,进行选择。
-空闲态的检测
空闲态应该在对象内部实现还是作为全局条件函数实现?
此特性为调试特性,应该和模块设计无关。
应该用单独的全局条件检测实现。
考虑到软硬件联合开发,硬件仿真平台一旦设计完成,配合软件调试时,再用改代码的方式实现断点和记录就有点不适合了。
应该能通过用户界面进行设置。
此设置局限于CPU接口访问,因为软件只理解这一层。
硬件内部的信号接口没有必要开放,因为软件不懂硬件内部结构。
内核实用化
1)解决应用接口2)解决软硬件接口3)解决记录技术4)留出高级调试接口5)做成DLL
内核:
用户初始化接口、仿真平台初始化接口、运行控制接口、校验接口、断点接口、CPU访问断点接口、记录文件访问接口。
扩展:
记录文件、软硬件接口
调试:
运行控制台、调试模块
1)满足硬件平台设计和软件设计仿真分开的需要。
硬件平台以独立的DLL提供给软件开发过程,提供调试能力。
2)加以扩展,也可以满足硬件仿真平台调试需要。
即可以扩展成一个通用的,同时满足硬件仿真平台调试和软件调试需要的调试平台。
仿真平台的调试不必再编写不同的断点条件代码,通过GUI界面可以自定义检测条件,并且这些检测条件可以保存下来,供下次仿真直接使用;软件调试能设置的硬件访问断点也不再局限于CPU接口访问,可以直接使用仿真平台调试过程中编制好的检测条件。
调试逻辑上是运行控制台的一部分。
仿真时间的表示
double:
64bits:
1forsign,11fortheexponent,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- SIMC 软件 规范