单周期RISC-V架构CPU的设计---仿真调试篇

二、仿真调试

ADD指令测试文件

宏定义错误

错误,,,,在宏定义文件中需要定义位宽和进制,不然没法进入对应的case条件分支中,因为右图中的opcode是7位二进制,宏定义不定义位宽就会默认为十进制数!!!!!!

改正后rs1_addr_o不再为零,赋值为rs1。

同样的问题再一次在alu.v文件中出现,只把`ADD的加了位宽和进制,10处没有加,导致result输出为默认值0。

取指时序问题

由波形可以得出,当前pc值是时序电路,如果在取指时也按时序电路设计,就会导致读取晚一拍,pc值和指令对不齐,可以将取指改为组合逻辑,如下图,使之提前一拍读出。

这样改完更离谱了,直接在终端输出''ADD FAIL'',经过对比之前ADD指令的CPU波形发现,在pc=54处的lui指令得到的result有误,lui指令需要对imm左移12位,由于alu.v中的imm已经在前一模块中完成了imm扩展,其中的操作包含了左移12位的操作,这里不需要再重复操作了,下图是错误之处。

改为还不对终端输出''ADD FAIL'',,,,

ADD指令与SUB指令

继续解决上述问题,,R型指令存在ADD与SUB指令,需要分情况做加减法,

但是I型指令,只有ADDI指令,因为imm为带符号位的补码,直接相加即可表示减法,比如9-3,9的补码(01001),-3的补码(11101),相加得100110,溢出舍去最高位得00110,即+6。

修正前:

修正后:

终端显示ADD PASS。

波形图如下:不知为何指令进入最后一个之后还在pc还在变化,只是没有在取指。

估计错误是由于jump指令的错误,没有执行,因为在指令执行的文件中显示在进入4FC之后持续跳转4FC。

JUMP指令修正

在设计中没有处理好JUMP(汇编指令),该指令0000006f对应的pc为000004fc,

对应的RISC-V指令操作是JAL,opcode=1101111,rd=00000,imm=000000000000000.

出现上一标题的问题,根源就是没有搞好JAL相关操作模块,观察到指令pc的返回通路中的pcsrc只考虑了branch的情况,加入或的情况,把 JAL的pc操作加入,该操作改变在mem.v中,如下图加入或条件,但是由于opcode没在这一模块加进来,于是,可以在他的前一模块操作。

前一模块id.v,只在branch类型的指令中给branch信号赋值1,观察后发现,jal、jalr、auipc都改变了pc值,于是对这三类指令都加入branch信号赋值。

改完还是没解决上一标题问题。

后又发现因为pcsrc是与门逻辑,除了branch还有个branch_sign(zero),这里是由于我在alu.v中赋初始值0给branch_sign。所以jal等指令无法激活pcsrc,在该文件中将上述三条指令的branch_sign赋值1即可。

YES!!!!!!!!!!成功

ADDI指令测试文件

与ADDI同理,经验证通过。

AND & ADDI指令测试文件

与上述同理,经验证通过。

XOR & XORI指令测试文件

SLL & SLLI & SRL & SRLI指令测试

opcode=0110011是R型指令,funct=0001是SLL逻辑左移,对操作数src1逻辑左移src2位。

opcode=0010011是I型指令,funct=0001是SLLI立即数逻辑左移,对操作数src1立即数逻辑左移src2位(imm的[4:0]位)。在这里src2=imm。

opcode=0110011(Hex=33)是R型指令,funct=0101是SRL逻辑右移,对操作数src1逻辑右移移src2位。

opcode=0010011(Hex=13)是I型指令,funct=0101是SRLI立即数逻辑右移,对操作数src1立即数逻辑右移src2位(imm的[4:0]位)。在这里src2=imm。

SRA & SRAI指令测试

SRA指令测试出现问题。虽然terminal显示FAIL,但是波形图显示一点就停了。。。。

可以看到在红框处,pc跳转并不正确,在dump文件检查发现,在该组指令中存在SRA指令,pc值为28,SRA=4020DF33,将下图的src1=8000_0000,算术右移(补符号位)src2=1,结果应为c000_0000,但结果错误的输出为4000_0000(逻辑右移结果)。

下图检查并修改SRA指令的执行代码,结果还是一样不对,,,,,

怕编译工具不支持该语法,更换编译工具仍然不支持,,,,尝试更换实现思路。

一种是遍历所有可能的移位情况(方法太笨),另一种可以先逻辑右移,再通过mask掩码按位操作。

完美解决!!!!!

SLT & SLTI指令测试

opcode=0110011(Hex=33)是R型指令,funct=0010是SLT小于则置位(有符号),src1小于src2则置位。

opcode=0010011(Hex=13)是I型指令,funct=0010是SLTI小于imm则置位(有符号),src1小于imm则置位。这里注意有符号数8000_0000=-2147483648,FFFF_F800=-2048,

要注意在有符号数运算时,用的补码,实际的数值即原码是下方波形图中的补码取反+1,例如补码FFFF_F800,取反8000_07FF,+1后=8000_0800,正好为2048,符号位是1,即-2048。

SLTU & SLTIU指令测试

都通过了!!!!!

LB & LBU & AUIPC指令测试

出现错误,在pc=000008处,查看dump文件是auipc指令(前期lui指令多次被动使用没有错误)。auipc的操作是rd = PC + ( imm << 12 )。

发现在id.v中branch=1(错误),alu.v中branch_sign=1(错误),没有PC跳转,所以都错了,之前可能修改时候改错了。又因为在alu中默认了pc_o=pc_i,导致pc原地不动。

经过修正后,pc=000010处,没有读取到ram的值,排查后发现,应该在tb文件中,用类似给指令rom赋值的方式,给ram寄存器组也进行赋值。

调整data_mem(即ram)的深度对应合适的位置,因为读写冲突,导致文件read_data的数据始终为0,下图选中部分删掉后波形图如下图所示,可以读取read_data。

经过参考tiny_riscv的设计,将读取操作和写入操作分离,将写入语句注释掉在后边单独写一个写入的always块。如下

经过考虑,因为load指令需要从RAM里读取数据,没有合适的ram数据文本能够对应load的指令测试(其中有一条是通过判断两个值是否相等,来决定跳转,正常情况是相等不跳转继续执行,bne指令)。

故可以采用store指令测试文本进行测试,其中有包含load指令可以一并测试。

SB & SH & SW指令

指令包含:sb+lb、sh+lh、sw+lw

sb指令的测试文件是对一个地址先进行写入,再读出数据,与原数据作比较,判断store和load指令执行的正误。

此处做了下改进,把ram数据模块拿出来,单独例化进mem.v中,依然出现问题,下图为mem.v的波形图,因为先写入再读出,能够看到在wirte_data处压根没有数据。而这个是输入数据,说明在前一个阶段,alu就没有输出正确值。

发现错误,对于访存指令我在id阶段pcsrc都赋值1,在alu阶段却把imm传进来了,imm这时等于0,应该将write_data直接接rs2_data_i,这里有问题待解决

基本通过,但还是有点见红,如下图:,,继续整!!!!!!

mem阶段的ram_data_o一大片红色,

我发现是对ram_data_o没有赋值(在非访存阶段),于是我将在其他指令默认赋值0,得下图。结果就是因为赋值0,与寄存器数据对比不相等,指令执行错误退出(0000_00a0与ffff_efa0比较)。上图通过是因为没有赋值导致读出的数据是xxxx_xxxx,数据写入低8位,读出低15位,得到xxxx_xxa0,不定态跟1算是相同,x可以是1也可以是0,所以认定为数值相同。

该成下图代码,也可以通过因为该地址之前没有值,所以都是ram取出来都是xxx态。

不过我检查到通用寄存器t5和t4时发现,竟然load到t5的值都大部分不是x态了,只有下图一块,为啥呢,存疑

这一小块红色是因为只有在这里,用了lh,结果高位补位补的都是x态,其他的都是lb指令,高位补的是确定态(ram_data_o[7])。后边有一小溜溜红色也正常,看指令文件中间多了两个非访存指令,就有红色了。

总结一下:sb+lb、sh+lh略有红色不定态,sw+lw全绿。

lbu & lhu指令

lbu指令

上图在无符号读取数据时,变成了右侧放16位读取的数据,左侧补16位0。(这是lhu的操作,但测试的是lbu)。发现下图define定义错了。改后执行正确。

在这里我想给外部的数据存储器预先加入数据时出现了错误,报错并提前结束。他的读取地址前两次都是1000,是没错的,但是第二次中t4的对比数据是0,所以第二次读出数据对比出现错误。正常应该不会的。就按没有预先加数据时为准吧,测试可以通过。

B_type指令测试

yes全绿通过,就不放图了。√√√√√√√√√√√√√√√√√√√√

J_type 指令测试

 jal指令前边通过了(jump指令修正那栏),这次再此通过。

jalr指令失败。在pc=18的imm=30000发生错误,应为imm=0(该jalr就应该执行操作,pc= x20+0,rd=pc+4)。

检查发现是译码模块对`INSTR_TYPE_JR的imm输出写错了,改正如下

改完之后pass了。

yes!!!√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√

U_type指令测试

yes!!!√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√√

至此RV32I所有指令测试通过

不含最后两个指令ecall、ebreak。

三、更换仿真工具VCS & verdi

`include "defines.v"无法识别,需要在makefile文件中加入选项:

+incdir+../src/            ####声明宏定义文件的位置 

tb文件中波形生成命令更改。

// iverilog    更改前!!!!!!
initial begin
    $dumpfile("sim_out.vcd");
    $dumpvars;
end
//
// vcs     更改后!!!!!!
initial	begin
	    $fsdbDumpfile("tb.fsdb");//这个是产生名为tb.fsdb的文件
	    $fsdbDumpvars;
end

同时在iverilog编译时tb文件中的时钟停止命令是 $stop,VCS编译不能识别该命令无法停止时钟,使用$finish即可。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ICer_freshman

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值