单周期31条指令CPU设计---bug总结

单周期31条指令CPU设计bug—总结

  • vivado 2016.2
  • verilog
  • modelsim
  • Mars标准

-声明:该篇总结的bug是在编写代码,并进行测试过程中遇到问题,并及时记录。并不具有普适性,但可以提供相关的思路,帮助您去寻找出错的关键

文中使用的变量意义声明

变量名 含义
pc 32位,下一条指令在指令存储器中的地址,起始地址为32’h0040_0000
inst 32位,对应MIPS指令
RF_W 1位,寄存器堆regfile的写信号,高电平有效
wdata 32位,寄存器堆regfile的写数据
waddr 32位,寄存器堆regfile的写地址

1. 在顶层测试tb文件中使用$display系统函数无法读出pc以及对应的inst

$fdisplay(file_output,"pc: %h",uut.pc); //file_out指定输出结果的文件
$fdisplay(file_output,"instr: %h",uut.instruction);

建议:需要理清楚$fdisplay的层次关系。
解释:以上的代码是最后正确的代码,其中uut是在tb文件中实例化的cpu的名字,pc是cpu的接口之一。用C++中的概念来说,设cpu模块是一个类,那么$fdisplay中都是对象名,也就是实例化后的模块名。如,cpu uut(clk_in,reset,pc,inst)
不断向下挖,一直到最底层的接口为止。

2.一直循环读取第一条,第二条指令
在cpu中需要一个指令存储器instmem,接口如下:

接口类型 名称 含义
input[31:0] address 下一条指令在指令存储器中的位置
output[31:0] inst 读出来的指令

读出什么指令,取决于两方面

  • 指令寄存器中的数据是否正确
  • 传入的地址是否正确

通过观察modelsim看到,address一直在0,1之间徘徊,也没有报地址溢出的错误,所以问题关键,肯定在于address
对于address,也需要从两方面进行考虑

  • 外部传入时,是否出错
  • 在内部处理时,是否出错。

在debug过程中,在分析清楚出错可能的原因之后,一定是先从容易的方面入手
很幸运,在检查内部处理的部分中,找到了根源。在过程中使用了一个临时变量“接”address,实际应该是用一个32位的临时变量,但编写过程中,不小心使用了一个一位的变量,导致这个临时变量不是0就是1

3.regfile无法写入数据
思路:

  • 列出regfile相关的变量:RF_W,wdata,wdata
  • 将这些变量加入cpu的接口列表中
  • 注释掉cpu模块代码主体中对这些变量的声明
  • 修改对应的tb文件中对cpu的实例化
  • simulation,观察modelsim中这些变量的值,是否符合预想

以上这个思路是在debug我们的cpu的时候最常用的方法,可以帮助我们检查到出错的量。在此基础上,顺藤摸瓜,直到找到问题的根源
最终解决:出错根源是,由于regfile写入的wdata有多个来源,需要数据选择器进行选择。在cpu模块中实例化数据选择器时,选择信号M7手误写成了m7。由于我的代码是在sumlime中编写好后,再copy到vivado中,所以vivado并没有及时检查出拼写的错误

4.不能将测试文件中的指令读完
ps:纯经验
在tb文件中需要自行模拟时钟信号

always #50 clk=~clk

**解决:**将#50改成#4或者#2,总之改小
解释:#50说明,时钟周期为100个时间单位,频率为1M。也就是说,假设这时候在规定时间内,只能做x次取指操作,那么,改成#2之后,就能做25次取指操作。

5.sra测试错误
如何从测试结果找到这个问题根源请参照上述3,这边主要讲一个注意点:

  • 算术右移符>>>失效了

**解决办法:**手动通过拼接的方式写了算术右移功能

展开阅读全文

没有更多推荐了,返回首页