关键词:计算机组成与结构;SystemC;总线仿真;系统级建模;硬件模拟
中图分类号:G642 文献标识码:A
文章编号:1009-3044(2025)03-0131-03 开放科学(资源服务) 标识码(OSID) :
0引言
计算机组成与结构作为计算机系统类课程的基础,是学生全面了解计算机各个部件工作原理和主要功能的课程,也是集成电路相关领域的直接相关核心课程。该课程中近1/2的内容围绕中央处理器CPU展开,包括运算方法、指令系统、CPU的组成与结构、控制系统、中断系统等章节,1/4的课程围绕存储器展开,包括存储器芯片的基本单元电路,存储器与CPU 的连接,存储器的校验等。由于这门课难度较大,理论性较强,且涉及大量硬件知识,学生感觉到抽象、难以理解,因此采用合适的实践方式,对于增强学生对课程的深入理解尤为关键。
传统硬件实验箱[1]的方式主要靠插拔电线完成,学生根据不同仿真部件的电路图,利用杜邦线连接各个电路接口,并通过可视化界面观察模型机的实验数据通路图。这种实验方式将计算机的主要模块封装成为黑匣子,学生难以看到模块内部的细节,不容易理解计算机各个模块的基本工作原理,逐渐被其他方式所取代。近些年,Logisim [2-3]仿真软件和FPGA硬件实验箱的方式[4-5]已成为该课程的主要实践平台,其中Logisim仿真软件是一个用于设计和模拟数字逻辑电路的仿真工具箱,该软件提供了各种逻辑门(AND、OR、NOT) 和多种复杂的组合逻辑电路,借助于各种逻辑门和组合逻辑电路,可以进行加减法器、CPU、存储器和总线等不同计算机模块的设计。但是Logisim仿真需要学生对数字逻辑电路基本知识和仿真组件有扎实的基础,能够灵活地利用各种组件搭建复杂电路。FPGA方式尽管能够较好地与实验原理相结合,但前提是必须要有较强的FPGA动手能力,通常电子专业的学生有较强的FPGA开发能力,但是对于计算机专业的学生而言,往往较为欠缺。
对于计算机相关专业的学生,由于系统地学习了C/C++语言,使得他们已具备该语言的扎实编程能力。为了充分利用计算机专业学生较强的C/C++专业基础和编程实践能力,采用C++类库的仿真方式不失为一种更好地调动学生积极性和能动性的方式。尽管SystemC仿真已应用到相关领域[6-7],文献[8-9]也提到了基于SystemC的一些总线仿真方案,但是将SystemC 引入到计算机组成相关课程的教学设计和教学实践中的相关研究较少。
在现有计算机语言中,不同语言所能够建模的计算机层次并不相同,图1给出了不同语言在计算机软件、硬件中的应用范围。从这幅图可以看出,不同的开发语言适合不同的开发层级,对于门电路层、RTL层、IP验证层和Soc[10]验证层而言,Verilog比较适合,VHDL 一般不用于Soc验证层的开发,而SystemC Verilog[11]能够用于从门电路层到行为层的所有层次开发。相比而言,SystemC适用于从RTL层一直到算法架构层的开发,对于偏顶层的需求层以及算法和架构层开发,高级语言如C/C++、Matlab、Python和Java则比较适合。
从图1可以看出,SystemC涵盖了从RTL层到算法和架构层的所有系统层级,因此在系统级建模和开发上具有较大的优势。
SystemC作为C++类库, 在C/C++语言基础上引入了时间概念和并发概念,时间概念的引入有助于事件先后次序的仿真,并发概念则契合了硬件内部的并发性特征。因此,基于SystemC的语言特点,SystemC可以完成以下几种硬件仿真:1) 软件算法的周期精确模型;2) 硬件架构探索;3) 片上系统的接口设计;4) 系统级设计;5) 执行过程验证。
为此,本课程采用了SystemC[12-13]的仿真手段辅助本课程的实践环节,通过SystemC的项目实践,一方面让学生深入体会如何利用软件语言搭建硬件组件,另一方面也能够进一步增强学生的代码编写能力。
1总线仿真分析
系统总线是计算机各个部件的传输介质,所有系统部件之间的数据传输和通信都需要系统总线实现。如何让学生直观地体会总线的传输特性对于学生理解并深刻认识总线的基本特性至关重要。
本课程在进行系统总线的理论讲解时,分别讲述了单总线结构、双总线结构、多总线结构以及PCI Ex⁃press总线结构。考虑到学生对总线的直观理解以及仿真的难度,开展实践设计时,侧重要求学生仿真单总线的结构,但是针对不同的学生层次,提供如下两种总线的设计方案:单总线-单主从设备仿真和单总线-多主从设备仿真。其中单总线-单主从设备仿真为必做项,单总线-多主从设备仿真为选做项。图2 和图3分别为单总线-单主从设备仿真示意图以及单总线-多主从设备仿真示意图。其中单总线-单主从设备仿真只需模拟总线与总从设备的数据通信,单总线-多设备仿真在考虑数据通信的前提下,还需要考虑设备之间相互竞争时的判优方式。在判优方式的选择上,建议学生使用先来先服务的轮转优先级判优方法,该方法比教材[14]中的链式查询更为有效,并且也比计时器定时方式和独立请求方式简单。该判优方式的基本思想是:根据不同主设备请求的先后次序,将其放入到一个先进先出的队列中,依次进行响应,每次请求入队前,要先进行判满,请求出队前先要进行判空。但是总线判优的这部分不作为必做项。因为判优的前提要保证所有的主从设备保持时钟和进程的同步,对于刚入门SystemC系统级建模的初学者而言,这部分的难度较大,因此只作为选做内容供学有余力的同学进行实践。
在总线仿真设计时,无论是采用上述图2和图3 中的哪一种仿真方案,都需要学生先考虑如下一些问题:1) 如何建模总线仿真模块?2) 主设备、从设备和总线模块之间的接口连接方式该如何设计?3) 每个模块的必要结构应该包含哪些?这些前置问题的深入思考,有助于仿真过程的顺利开展。
2基于SystemC的总线仿真实现
2.1 SystemC语言概述
SystemC作为一种系统级的仿真建模语言,既能够进行周期精确级(CABA) [15]建模,又可以进行事务级(TLM) [16]建模,周期精确级建模需要仿真出每个周期的状态,只能在全部的硬件设计完成之后才能进行软件的测试和系统的集成,无法进行早期的系统架构设计。而事务级建模能够在更高抽象层次上对芯片进行分析,从而让设计人员快速地构建原型平台。该方法不仅能够进行硬件系统的架构探索和嵌入式软件程序的开发,而且系统仿真速度很快。本课程着重向学生讲述计算机各大部件系统级的功能,因此选择事务级建模方法较为合适。
SystemC在对系统进行建模时,针对系统运行的要素,分别抽象出模块、接口、端口、通道、进程等组件。从硬件角度来看,模块是一个特定的功能单元,比如存储器、总线、CPU均可以作为模块,一个接口转换电路也可以作为模块。SystemC中的模块除了具有C++类中必备的构造函数和析构函数以外,还需要在构造函数里面指定敏感表,比如可以指定模块对clk 的上升沿敏感。在进行总线建模时,总线本身,以及与总线互连的主设备和从设备都可以抽象为一个SystemC的模块。
在SystemC 中,接口实际上是一个C++抽象类,所有的接口都直接或间接继承于sc-interface,接口用来定义模块之间的通信方法。比如在总线建模时,需要定义读接口和写接口。
端口是一个对象,它是模块的一个组成部分,它将模块内部的行为与外部环境相连接。端口绑定到一个接口上后,就可以使用该接口定义的方法来进行通信。在SystemC中,有3种基本的端口:sc-in 、sc-out与sc-inout ,它们都从基类sc-port继承而来,每一种端口都提供接口方法,如read()与 write() 等。比如总线建模时,需要将端口分别与读写接口绑定。
通道实现一个或多个接口,可视为一个通信容器,通道必须继承一个或多个接口,这些接口中定义的抽象方法必须在通道中实现。通过端口,模块中的进程可以连接到通道并使用通道提供的方法。在端口、接口与通道都定义完成后,模块能够使自己的端口与实现了相应接口的通道互连。在SystemC中,通道用于实现模块间的异步通信,模块通过通道将数据在发送方和接收方之间传递。
进程具有并发性,SystemC中的进程有如下特征:1) 一个进程不能包含或者调用0其他进程;2) 进程可以调用非进程的函数和方法;3) 进程通常会有一个敏感表,当敏感表中的信号上有事件发生时,进程就会被激活。在总线建模时,每个主从设备仿真模块都需要有相应的进程。
2.2总线仿真设计
根据SystemC的仿真思想,可将主设备建模为主模块,从设备建模为从模块,总线建模为总线模块,那么主要仿真要素如表1所示。需要定义主模块、从模块、总线模块和顶层模块。在主模块内定义一个写端口、从模块内定义一个写端口,并且要在主从模块中分别设置进程敏感表,并将时钟上升沿作为敏感表中的事件,而总线判优设定为选做模块。
下面对表1中的主模块、从模块、总线通道、顶层模块分别做简单介绍。
1) 主模块:主模块定义为一个SC_MODULE 的C++类,类中需定义输出端口,端口类型为写接口类型,用于向总线模块里写入数据。定义自己的时钟信号clk和构造函数,构造函数中除了实现一些初始化功能,还需指定进程和敏感表。进程采用SC_THREAD线性进程,敏感表使用sensitive指定,设置为对时钟上升沿敏感,主模块的main函数中使用rand函数模拟随机写入,使用wait函数实现模拟写入频率。
2) 从模块:与主模块类似,只需将端口类型改为读接口类型,用于读取数据。
3) 总线模块:总线模块也定义为一个SC_MODULE的C++类,该类中需定义传输的数据数组,读写事件、定义读写接口,用于主从模块对总线的读写操作;由于该模块主要用于数据传输,因此写入数据还需要判满,读取数据判空等。若总线需要连接多个主从模块,需要增加判优方法。
4) 顶层模块:用于主从模块和总线模块之间的绑定,需要实例化这三个类的对象,再将先前定义的端口绑定在一起即可。最后在main函数定义时钟信号,将主从模块的时钟与之绑定,并启动仿真。
表1中的总线判优为选做项,仿真难度较大。若考虑总线判优,那么学生在仿真中首先必须实例化多个主设备模块和从设备模块,并且每个主设备模块和从设备模块必须预留多个输入输出端口。然后在此基础上,需要实现不同的判优方法,每次总线在传输数据时,需要选出优先级最高的设备进行响应。
图4给出了总线仿真各个模块及其相互连接示意图。主设备(Master)、从设备(Slave)、总线(Bus)和顶层模块(Top)分别为4个SC_MODULE的类,在这4个类中,SC_MODULE(Master)和SC_MODULE(Slave)都需要定义一个SC_THREAD的进程。在主设备类中,需要定义写接口与总线模块进行端口绑定。在从设备类中,需要定义读接口与总线模块进行端口绑定。在总线类中,需要同时定义写接口和读接口,分别与主设备和从设备进行端口绑定。所有端口绑定的过程需要在顶层类中进行实现。当所有的模块包括顶层模块均已经定义完成,启动sc_start 便可以进行仿真启动。
3学生仿真中存在问题及原因分析
通过在仿真过程中对学生的引导,发现在建模方面,学生基本能够抽象出主模块、从模块和总线模块,但是存在如下突出问题:1) 仿真初期无法回归到总线信息传输这一根本任务,难以建构清晰的仿真框架,比如学生在缺乏引导时,较难想到将主从设备以及总线建模为一个SystemC模块;2) 顶层模块之间的互联机制理解不清,比如如何进行端口的绑定,如何进行时钟的设置;3) 仅能够实现单总线-单主从设备的仿真,总线判优方法难以实现。
以上问题的出现主要归结为以下一些原因:1) 用软件仿真硬件,需要对软件的仿真思想有比较深刻的认识,而这方面可查阅的中文资料较少,学生普遍感到难以入门;2) SystemC有一套严谨的仿真逻辑,尽管在课程中为学生梳理了相关知识要点,但学生还需要花一些时间深入思考;3) 多设备仿真时的判优逻辑较为复杂,既要考虑到多个端口之间的相互绑定,又要考虑到不同设备之间的进程统一,对初学者难度较大,因此这一部分作为选做内容也较为合适。
为了改善这一情况,课程计划采用如下解决方案:1) 建立一些优秀的案例库,以案例学习带动学生对理论的理解;2) 录制一些优秀视频,辅助学生对SystemC基础理论知识的理解。
4结论
由于计算机组成与结构课程现有实践方式不能充分培养学生的系统级建模和开发能力,结合计算机专业学生在C/C++程序设计方面的扎实基本功,引导学生利用系统级建模语言SystemC对总线传输过程进行仿真实践。详细阐述了总线仿真方案与思路,仿真实现的关键要素与相关细节,并对学生仿真中存在的问题进行了具体讨论,下一步将深入研究如何利用SystemC进行更复杂模块的建模,比如CPU和存储器,研究这些复杂模块的建模和设计方法,从而更好地指导课程教学。