Risc-V单周期CPU设计思考

本文介绍了Risc-V单周期CPU设计过程,包括基础指令集的实现、Control模块、ImmGen模块、ALU Control、Memory模块、RegFile和PC模块的设计。讨论了如何增加新指令,如Jal,并涉及中断异常的处理,尤其是CSR寄存器的作用。文章强调了在CPU设计中资源优化和异常处理的重要性。

Risc-V单周期CPU设计思考

今年学校课程改革,计算机组成课开始教学Risc-V,写单周期CPU的时候发现网上好像大多都是MIPS的CPU设计,所以就把自己关于设计Verilog的一些思路整理出来。看完同学的设计之后再一次确定了我非常非常菜,本文就仅供参考。(为防影响以后的教学作业,大多数源代码已经隐去、并未将宏等解释性语言加入博客)。

基础指令集的实现

基础指令集(包括ALU计算、数据存储载入、跳转)的实现可以按照Risc-V书本上的数据通路实现。在这里插入图片描述

Control模块

Control模块实质上是一个opcode的译码模块,即通过输入的7位opcode(实际上是5位,因为01位始终为1)的实现可以通过一个always段和多个case语句进行译码。但是这样的弊端是所综合出的电路比较消耗资源。我采用的方式利用之前机逻课上学的简化真值表,写出每一个译码信号与原信号的逻辑关系,大致如下:

wire is_branch, mem_ren, ALUop1, ALUop0, is_imm, reg_wen;
wire DMemWrite, MemToReg;
assign is_branch = inst[6] & ~inst[4];
assign MemToReg = ~inst[6] & ~inst[5] & ~inst[4];
assign ALUop1 = inst[4];
assign ALUop0 = inst[6] & ~inst[2];
assign DMemWrite = ~inst[6] & inst[5] & ~inst[4];
assign is_imm = ~(inst[5] & inst[4]);
assign reg_wen = ~inst[5] | inst[4] | inst[2];

由于Risc-V并没有将32种opcode情况分配给每一种指令类型,无关项使得每一条指令都不必完全利用5位opcode,使得译码阶段更加节省资源。但是弊端是当增加一条新指令时,会对之前的译码模块产生很大的改变,而且在处理illegal instruction的时候也会非常麻烦。

ImmGen模块

立即数生成模块即可依照Risc-V的的指令集生成。

always@(*)begin
        case( opcode )
            `OPCODE_LOAD: r = {
  
  {20{inst[31]}}, inst[31:20]};
            `OPCODE_STORE: r = {
  
  {20{inst[31]}}, inst[31:25], inst[11:7]};
            `OPCODE_BRANCH: r = {
  
  {19{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0};
            `OPCODE_OP_IMM: r = {
  
  {20{inst[31]}}, inst[31:20]};
            `OPCODE_JAL: r = {
  
  {11{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0};
            `OPCODE_LUI: r = {inst[31:12], 12'b0};
            `OPCODE_JALR: r = {
  
  {20{inst[31]}}, inst[31:20]};
            `OPCODE_AUIPC: r = {inst[31:12], 12'b0};
        endcase
end

ALU Control、ALU(与Comparator)模块

ALU Control元件存在的意义是,在加载存储、跳转指令中,有些时候无法像寄存器(与立即数)之间运算由Fun3一样确定运算符号,但是这些符号却是确定的:

  1. 寄存器(与立即数)运算:由Fun3决定
  2. 加载存储:加法
  3. 有条件跳转指令:减法
    因此需要一个2位的ALUOP信号,但是在CPU设计的时候完全可以将ALU与Comparator分离,所以可以将ALUOP简化为1位信号。而ALU与Comparator的设计则和ImmGen基本相同,故不再赘述。

Instruction Memory与Data Memory模块

Memory的设计依托于verilog中读取内存的函数语句,值得一提的是由于PC在自增是总是增加4的倍数,故如果将Instruction Mem的指令寄存器设置为32位的,则需要除以4读入:

(* ram_style = "block" *) reg [31:0] mem[0:4095];
initial $readmemh("imem_data.mem", mem);
assign imem_o_data = mem[imem_addr >> 2];
</
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值