如何使用Python模拟硬件?

3

标题有点混乱,但我的任务是用高级语言(我认为Python最好)编写一个4级MIPS处理器(IF,ID,EX,WB)。除了缓存和停顿的困难之外,如何将代码从并行变为串行?考虑以下代码片段。

pc = 0x0
IFinput, IDinput, EXinput, WBinput = None, None, None, None
while True:
    IFinput = self.memory.getInstruction(pc)
    if not IFinput: #No more instructions
        break

    self.IF.giveInput(IFinput)
    self.ID.giveInput(IDinput)
    self.EX.giveInput(EXinput)
    self.WB.giveInput(WBinput)

    instruction += 0x4
    clock += 1

    IDinput = self.IF.getOutput(clock)
    EXinput = self.ID.getOutput(clock)
    WBinput = self.EX.getOutput(clock)
    result  = self.WB.getOutput(clock)
result.printToFile()

我试图将输入和输出分为两个不同的阶段,以便在“clock += 1”命令执行之前不会通过获取输出来“欺骗”硬件。这是实现此目的的正确方法吗?是否有适合此任务的Python库?谢谢。


2
考虑使用特定于目的的编程语言,如VHDL或Verilog;可能结合/扩展使用PyHVL - user2864740
@user2864740 尽管我很想使用硬件语言,但我正在使用的服务器(我没有root权限)不包含任何这些内容 :( - SetSlapShot
真可惜。那为什么不试试在本地运行一个虚拟机/环境,来完成任务所需的工具呢? - user2864740
1
无论如何 - 如果我从零开始,并尝试用“通用”的高级语言模拟硬件线路,我可能会围绕“反应式”时钟节拍设计系统。由于这是一个原始的模拟器,除此之外我不会考虑任何形式的并发或并行性。请确保不要过多地阅读任务。 - user2864740
3个回答

1
在评论中建议使用一些特殊的语言,比如VHDL之类的,但我想对于一些简单的练习来说,速度可能并不重要,使用Python完全可以。您的代码看起来几乎没问题,我只是不明白为什么您的getOutput函数需要时钟作为输入,因为一个块的功能应该是时间不变的,并且只取决于它的输入。我认为你需要做的唯一的技巧是为处理器中存在的每个寄存器制作两个版本,一个表示它们当前的状态,另一个表示一个时钟周期后的状态。然后,模拟您硬件的所有功能应该只使用“当前”寄存器作为输入,并将其输出保存到“下一个”寄存器中。然后,在循环结束时,将所有下一个寄存器复制到当前寄存器中,然后重新开始。就像这样:
pc = 0
IF2ID_cur, ID2EX_cur, EX2WB_cur = 0 # values of registers after a reset

while True:
    instruction = memory[pc]
    IF2ID_nxt = simulate_IF(instruction)
    ID2EX_nxt = simulate_ID(IF2ID_cur)
    EX2WB_nxt = simulate_EX(ID2EX_cur)
    result =    simulate_WB(EX2WB_cur)

    pc += 1
    IF2ID_cur, ID2EX_cur, EX2WB_cur = IF2ID_nxt, ID2EX_nxt, EX2WB_nxt

请注意,通过这种方式,所有“模拟”函数仅使用当前寄存器值,而不使用下一个时钟周期的任何值。因此,您可以更改它们执行的顺序,而不会更改结果,就好像它们都在并行运行一样。

“将时钟传递给“获取结果”的原因是,是否已产生结果取决于经过了多少个周期。例如,如果指令在5时进入EX阶段,则需要2-20个周期,具体取决于它是ALU操作、FP操作等。此外,我无法确定何时完成任务,因为即使ex操作“完成”,它也可能会被阻塞,等待WB端口空闲。” - SetSlapShot
1
啊,你之前没说啊,我以为所有阶段都是单周期的。但如果是这样的话,你可以给每个项目添加一个适当长度的队列,不需要传递绝对时钟数。 - Bas Swinckels
@SetSlapShot 我会真的建议你考虑一下响应式设置 - 即仅在特定条件下执行回调(例如时钟上的行状态或x个滴答后)。 - user2864740

1
你已经接近成功了。函数名称有点令人困惑 - 我更喜欢使用capture()update()memory.getIstruction()应该绝对隐藏在IF.capture()中(IF的工作是获取指令,对吧?)。PC更新似乎也属于IF阶段。
“没有更多指令”的情况在现实生活中不会发生,应该放弃。打破循环的正确方法是EX阶段引发异常(例如,在非法范围内使用保留指令;请记住,其他异常可能会合法地引发)。
否则,作为起点看起来不错。

1
考虑使用针对特定目的的语言,如VHDL或Verilog; 可能结合/扩展使用PyHVLCocotb等工具。
然而,如果必须从头开始创建和/或使用纯Python实现,请考虑使用高级硬件语言中的相同概念。特别是要考虑反应式设计。Verilog和VHDL都支持这种概念-其中输入(例如时钟)的更改驱动行为和新的输出状态。
然后,每个“反应回调”仅接收输入状态并在与其他组件隔离的情况下发出特定的输出状态。依赖关系仅通过状态更改和围绕更改的反应触发器建立。
可能在触发器/保护中使用以下内容:
- 行或数据更改状态 - 信号事件 - 周期计数(例如最小值、之后、随机)

1
有一个名为CocotbPyHVL后代正在积极维护,并提供各种优点和改进-例如,它可以与VHDL和Verilog一起使用。对于新设计而言值得考虑。 - Chiggs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接