一、基于RV32I ISA理解CPU结构

写在前面

  本文参考书目:《计算机组成,软硬件接口,Risc-V版》
  CPU结构和指令集是分不开的,因此,我们在使用HDL语言实现CPU之前,首先了解其指令集。

1、从一个简单数据通路开始

  简单数据通路,即RV32I的一个子集,实现RV32I指令集中的部分简单指令。(主要是R型,B型,lw和sw指令),下面先介绍这些指令。
在这里插入图片描述

RV32I 的指令类型概览

  从图上可以得出,我们根据指令不同的格式将其分成了6种类型。

1.1 R型指令

  R型指令可以罗列为下图
在这里插入图片描述
  或者是下图的样子
在这里插入图片描述
  主要实现的功能是实现逻辑运算。R-type指令的opcode都是0110011,如前所示,R型指令的特殊之处在于其使用了rs1,rs2和rd,运算完毕rs1和rs2之后,把rs1,rs2运算完毕的结果写回(Write Back)RF中的rd. 值得一提的是,Risc-V有32个通用寄存器x0-x31,不妨将他们叫做寄存器堆(RF,Register File)。寄存器堆的首个寄存器,即x0是始终为0的,无法通过写入改变其值

1.2 lw指令

  lw指令是I型指令中的一种,lw指令详细描述如下
在这里插入图片描述
  我们可以学会使用这种公式来表示指令的功能
x [ r d ] = M [ x [ r s 1 ] + s e x t ( o f f s e t ) ] x[rd] = M[x[rs1]+sext(offset)] x[rd]=M[x[rs1]+sext(offset)]
  lw指令用到了rs1,rd和offset三类数据,需要读Data Memory并写回(Write Back)给RF。其中和R型指令的共同点是都用了rs和rd。
  值得一提的是,同样属于I型指令的addi这些,就不需要访存MEM这一步,而是直接将结果写回。而且这两类I型指令的opcode也不同,足见其特殊之处。因此I-Type指令可以细分为访存类立即数运算类

1.3 sw指令

  sw指令的详细叙述如下
在这里插入图片描述
  sw使用了rs1,rs2和offset三类数据,需要将rs2的数据写入到Data Memory.

1.4 B型指令

  B型指令是 branch,分支跳转指令的简称,其格式如下
在这里插入图片描述
  或者如下

在这里插入图片描述
  B型指令的opcode是1100011,其用到了rs1,rs2和offset,这一点和sw一样。只不过B指令做的不是计算rs1和offset的结果作为访存地址,而是将rs1,rs2作为ALU输入。而offset是和pc进行运算的(如果条件转移满足的话),可以参考beq指令。
在这里插入图片描述

1.5 简单数据通路

  通过下图我们可以看到该结构是如何将上述四种指令结合起来
在这里插入图片描述
  我们以R型指令为例(结合上图)。
  PC是时序电路,假设当下PC输入时pc+4,pc输出是pc,那当下一个posedge到来时,PC输出变成pc+4,完成了一次输入到输出的刷新。pc变成pc+4后,输入到Instruction Memory的read address就发生了变化。Instruction Memory是组合逻辑,当Read Address变化后,其输出的Instruction也发生变化。
  输出的Instruction经过简单的译码之后,给出register1和register2的地址。给到RF,RF的读取也是组合逻辑,因此随之Read data1和Read data2也会立即变化.
  rs1,rs2送到ALU中,计算完毕的结果在写回处,即RF的write data处等待下次时钟周期的到来.
  下一个posedge到来后写回的数据就会被写入RF。

  以上描述了指令运行的五个阶段,IF,ID,EX,MEM和WB,在R型指令中没有MEM阶段,EX的结果直接WB到RF。

  我们再看lw指令。
  lw指令选择计算rs1和offset,计算的结果作为Data Memory的读地址,Mem的读取也是组合逻辑,读取的结果WB到RF。因此该指令是完全包含五个阶段的。

  我们再看sw指令。
  同样计算rs1和offset的结果作为Data Memory的写地址,rs2作为Write data,由于写是时序,因此在下一个posedge到来时将值写入到Data memory中。这个指令是没有WB阶段的,因为是store word,把数据写入到Data Memory就标志着结束。

  最后我们再来看B指令。
  B型指令例如beq,将rs1和rs2进行对比,如果输出结果Zero指示为0的话,就将PC的输入值改为pc+offset(左移1位,按照16位对指令空间进行地址跳转),否则仍然是pc+4.

2、加入控制模块的数据通路

  控制模块将ALU的控制单独分离出来一个模块。这样做的好处是多级控制,简化逻辑。如下图所示。
  *需要注意的是我们写的是RV32I,所以图上的64位有关的叙述我们需要进行调整。
在这里插入图片描述
  我们可以观察到,除了ALU控制之外,Control的控制是基于7位的opcode的,这一定程度上也能解释I型指令中,为何访存指令立即数算数指令,它们的结构一样(因此都是I型指令),却要用不同的opcode.见下图
在这里插入图片描述
  因为立即数运算和访存的执行很像,都是rs1和offset相加,只不过立即数运算是直接将相加结果写回到RF,而访存指令是将结果作为访存的地址,得到的输出再写回RF,因此多了一步MEM。因此这些需要通过控制模块来实现,所以采用不同的opcode来保证不同的控制输出(例如多选器选择写回RF的数据源)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
rv32i是一种基于RISC-V指令集架构的32位指令集。rv32i指令集包含了9条基本指令,这些指令可以用于构建CPU结构。下面是这9条指令: 1. LUI(Load Upper Immediate)- 这条指令用于将一个20位的立即数左移12位,并将结果存储在目标寄存器的高20位中。 2. AUIPC(Add Upper Immediate to PC)- 这条指令用于将一个20位的立即数左移12位,然后与当前PC寄存器中的值相加,并将结果存储在目标寄存器中。 3. JAL(Jump And Link)- 这条指令用于设置PC寄存器的值为当前指令地址加上一个20位的立即数,并将当前指令地址加4保存到目标寄存器中。 4. JALR(Jump And Link Register)- 这条指令用于设置PC寄存器的值为目标寄存器和一个12位的立即数相加的结果,并将当前指令地址加4保存到目标寄存器中。 5. BEQ(Branch if Equal)- 这条指令用于比较两个寄存器的值是否相等,如果相等则将PC寄存器的值设置为当前指令地址加上一个12位的立即数。 6. BNE(Branch if Not Equal)- 这条指令用于比较两个寄存器的值是否不相等,如果不相等则将PC寄存器的值设置为当前指令地址加上一个12位的立即数。 7. BLT(Branch if Less Than)- 这条指令用于比较两个寄存器的值是否有小于的关系,如果满足条件则将PC寄存器的值设置为当前指令地址加上一个12位的立即数。 8. BGE(Branch if Greater Than or Equal)- 这条指令用于比较两个寄存器的值是否有大于等于的关系,如果满足条件则将PC寄存器的值设置为当前指令地址加上一个12位的立即数。 9. ADDI(Add Immediate)- 这条指令用于将目标寄存器和一个12位的立即数相加,并将结果保存在目标寄存器中。 通过使用这9条指令,我们可以构建出基于rv32i指令集的CPU结构。这些指令提供了基本的控制流和数据操作,能够实现简单的程序逻辑与数据处理。当然,可以通过添加其他指令来扩展CPU的功能,使其能够执行更复杂的任务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值