要了解PyMTL就要从三个方面介绍:领域方法学、软件抽象层次、写一个hello world。
计算机体系结构和计算机系统软件的协同设计方法
研究计算机体系结构需要模拟器,而模拟器可以说是对芯片的系统级建模。比如模拟x86、arm等架构的qemu就是一种模拟器,通常用来验证用于特定体系结构的系统软件和系统算法的正确性。传统的模拟器一般使用C++写,而系统级的建模经常使用systemc语言完成,然后再映射到verilog HDL上,进而布局布线,最后流片。PyMTL可以说是systemc的替代品,在语法上极大地简化了systemc,虽然在工业界没有大规模使用,但是确实在提高生产力上表现优秀。
可以说有了模拟器以后,体系结构的设计不需要再先设计芯片,然后等到流片后测试运行在它之上的系统软件。可以按照以下顺序设计计算机系统,是软件工程中敏捷开发的一种具体形式。需求分析:获取客户对于专用计算机系统
系统建模:使用系统建模语言对系统进行建模,实现仿真器,并进行系统级正确性验证
系统软件设计/硬件设计:利用仿真器开发系统软件/利用verilog根据系统建模的结果做RTL级设计
系统软件测试/芯片验证:编写测试用例测试软件是否符合需求/用UVM芯片验证方法学验证
流片
软硬件联合测试:把开发好的系统软件在实际的芯片上验证。
systemc语言是一个系统级建模语言(基于C++),比较适合体系结构的研究,尤其是需要获取特定架构的延迟时。但是做reram这种模拟器件时,需要加入模拟特性的建模与描述,就有人扩展systemc到systemc-ams让它可以描述模拟器件。但是C++语言写起来有些麻烦,chisel又需要了解scala这种函数式编程语言。康奈尔大学的Derek Lockhart等人开发了类似于systemc,使用python对体系结构建模的PyMTL框架,简化了体系结构的建模流程。他们的工作是2014年发表在体系结构顶会MICRO上Quick Startpymtl.github.ioComputer Architecturewww.csl.cornell.edu
PyMTL中设计的不同抽象层次
和verilog中把设计分为门级、行为级等相似,PyMTL也把设计分为FL(Functional-Level 功能级)、CL(Cycle-Level 时钟级)、RTL(Register-Transfer-Level 寄存器传输级),只有RTL级的代码可以被综合成为verilog(PyMTL将python语言转换为verilog)。FL级模型用于算法仿真,CL级模型用于构造模拟器为系统软件测试提供基础,
FL级模型
FL模型实现功能,但不实现目标的时序约束。 FL模型对于探索算法,执行硬件目标的快速仿真以及创建用于验证CL和RTL模型很有用。 FL方法通常具有数据结构和算法为中心的视图层次,并利用MATLAB或Python等生产力级别的语言来实现快速实现和验证。 FL模型通常使用开源算法包或工具箱来帮助构建具有正确性的黄金模型。当仿真时间很重要时(例如指令集仿真器),面向性能的FL模型可以使用高性能的语言,例如C或C ++。
CL级模型
CL模型捕获硬件目标时钟近似的行为。CL模型在探索硬件时序行为的同时,在准确性,性能和灵活性之间取得平衡。CL方法论利用诸如C ++之类的高性能语言来强调仿真的速度和灵活性。封装和重用通常是通过经典的面向对象的软件工程来实现的,而时序通常是使用事件的概念来建模的。建立的计算机体系结构仿真框架(这个是系统软件开发的基础)通常用于提高生产率。
RTL级模型
RTL模型是硬件精确到周期、资源与位级别的表示。构建RTL模型是为了验证和综合特定的硬件。 RTL方法使用诸如SystemVerilog和VHDL之类的专用硬件描述语言(HDL)来创建精确到位,可综合的硬件规范。HDL提供的原语是专门为描述硬件而设计的:使用基于端口(port)的接口提供封装,通过结构之间的连接合成,并使用组合逻辑和同步时序逻辑块描述。这些HDL规范将传递给仿真器,以进行评估/验证,并提供EDA工具流,以收集面积,能量,时序估计以及物理FPGA / ASIC原型的构建。这里的时序估计和上述两个级别的时序估计相比更为精确,而且由于RTL级加入了器件库,因此科研人员可以收集到芯片面积,功耗等信息进行优化。PyMTL的工作流程
上图中VCD文件是波形文件,可以用gtkwave来查看仿真结果。
写一个“Hello World”
环境配置
我用的是ubuntu 20.04 for wsl,可以在windows 10下用linux系统。
pip3 install pymtk3 # 安装pymtk3库
sudo apt install verilator gtkwave # 不是必须的,后续可能用到仿真器
用PyMTL的FL级模型写一个8位加一器
8位加一器是指芯片对输入的8位数据做加一操作输出到输出端口上。
新建一个hello.py文件。
from pymtl3 import *
class Incre(Component):
def construct(s, nbits):
# 声明输入输出端口
s.in_ = InPort(nbits)
s.out = OutPort(nbits)
# 内部的线网变量
s.reg_out = Wire(nbits)
# 时序逻辑 用于寄存
@update_ff
def block1():
# reset是Component的默认内置信号
if s.reset:
# 表示非阻塞赋值
s.reg_out <<= 0
else:
s.reg_out <<= s.in_
# 组合逻辑 用于加1
@update
def block2():
s.out @= s.reg_out + 1
输入输出端口和内部变量合称信号(signal)。然后新建一个testbench文件sim.py用于仿真。
from pymtl3 import *
from hello import *
# 创建模型
regi = Incre(8)
# 应用仿真器
regi.apply(DefaultPassGroup())
# 时钟清零
regi.sim_reset()
# @=表示信号赋值操作符,组合逻辑
regi.in_ @= 42
# 仿真器走一个时钟周期
regi.sim_tick()
# 测试验证
assert regi.out == 43
值得注意的是,PyMTL还不甚完善,当你把s改成self时,就不行了,并且in_和out这些输入和输出的变量名也都是确定的标识符,目前还不能随便改。
正确的输出是空,因为输出等于43。假设输出错误,测试结果如下。
Traceback (most recent call last):
File "sim.py", line 20, in
assert regi.out == 42
AssertionError
参考^PyMTL: A Unified Framework for Vertically Integrated Computer Architecture Research https://ieeexplore.ieee.org/document/7011395