CV32E40P处理器源码剖析(二):ID_Stage

原文链接:CV32E40P处理器源码剖析(二):ID_Stage - 知乎 (zhihu.com)

cv32e40p_id_stage负责实现指令译码功能,内部由cv32e40p_hwloop_regs、cv32e40p_decoder、cv32e40p_register_file、cv32e40p_controller和cv32e40p_int_controller五个模块组成。其中cv32e40p_hwloop_regs模块负责将循环程序硬件展开;cv32e40p_decoder负责解析指令,输出各操作寄存器编号、操作码、立即数等;cv32e40p_register_file负责维护32个寄存器;cv32e40p_controller实现id_stage内部模块的反压暂停功能,以及与if、ex和wb阶段交互控制信息;cv32e40p_int_controller实现中断控制功能,将中断位向量转化为中断编号。

cv32e40p_id_stage内部组成

1. 译码阶段剖析

cv32e40p_id_stage除了包含五个模块外,还实现以下几部分功能。

1.1 立即数译码与寄存器名译码

立即数类型包括imm_i_type、imm_iz_type、imm_s_type等。立即数格式可参考CV32E40P用户手册相关指令定义 。

寄存器名译码包含解析寄存器编号,以及判断访问整形寄存器或浮点寄存器。由于CV32E40P定义了专用指令,还包含寄存器c的译码功能。此外,通过对比前一条指令的目的寄存器与当前指令的操作寄存器是否同名判断是否存在数据依赖。这里需要注意两点,1)虽然访问数据需要多个时钟周期,但CV32E40P仅允许同时存在一条访存指令,即使用regfile_waddr_wb_i表示当前正准备load的寄存器标识;2)存在两个目的寄存器,regfile_waddr_id表示访存指令所使用的目的寄存器,regfile_alu_waddr_id表示ALU操作使用的目的地址寄存器,可用于定制访存指令(post-increment load and store)将访存地址写回基地址寄存器。

1.2 跳转地址计算与操作数赋值

根据跳转指令分为三类:1)直接跳转(无状态跳转),即jal指令,跳转地址为当前pc加偏移;2)间接跳转(无状态跳转),即jalr指令,跳转地址为寄存器值加偏移;3)分支跳转(有状态跳转),即branch指令,跳转地址为操作寄存器a的值加偏移。

CV32E40P包含三个操作数,其值可以主要来自5个地方:1)来自第一个操作寄存器的值;2)来自第二个操作寄存器的值;3)来自第三个操作寄存器的值;4)当前PC值;5)来自立即数。这里,操作数a并不一定来自第一个操作寄存器,例如div指令来自第二个操作寄存器,而位操作定制指令还存在来自第三个寄存器的情况。

1.3 ID-EX流水级交互

1.3.1 数据交互

可以分为五种情况:

1)data_misaligned_i == 1,即待读取sram的数据非4B对齐(读取低位地址非2‘b00的4b数据,读取低位为2’b11的2B数据),需要将地址加4后继续读取一拍数据。其中,标准load/store指令是在基地址+偏移上加4,即第二次的操作数a是先前操作数a和b的和;而CV32额外扩展的基地址累加load/store指令,则是直接在基地址上加4。

值得注意的是,累计两次load/store操作,是执行覆盖操作,即写两次sram,或者写两次寄存器。此外,第二次load/store操作时不会判断。

 
 

if (data_misaligned_i) begin // misaligned data access case if (ex_ready_i) begin // misaligned access case, only unstall alu operands // if we are using post increments, then we have to use the // original value of the register for the second memory access // => keep it stalled if (prepost_useincr_ex_o == 1'b1) begin alu_operand_a_ex_o <= operand_a_fw_id; end alu_operand_b_ex_o <= 32'h4; regfile_alu_we_ex_o <= 1'b0; prepost_useincr_ex_o <= 1'b1; data_misaligned_ex_o <= 1'b1; end end

2)mult_multicycle_i == 1,即乘法操作需要执行多个时钟周期时:需要保持c操作数的值。

3)id_valid_o == 1,id可正常执行指令译码时:对操作数、操作类型、待写回寄存器名进行赋值。

4) id_ready== 0 && ex_ready_i == 1,id阶段未就绪,但ex阶段就绪时:不中断ex阶段,执行一条假命令(即sltu,不写回寄存器),等价于在流水线中插入空气泡。

5)csr_access_ex_o == 1,上一个时钟周期已经申请访问csr寄存器时:将写回寄存器使能关闭,避免多次更新csr。

1.3.2 控制交互

输出的控制信号主要包含以下三个:

1)Id_ready信号,其失效情况包括:

  • load/store地址未对齐;

  • 出现分支指令且条件判断存在数据相关;

  • load过程需要暂停,即load指令且存在数据依赖,(data_req_ex_i == 1'b1) && (regfile_we_ex_i == 1'b1),或者load未对齐,需要等数据更新完,(wb_ready_i == 1'b0) && (regfile_we_wb_i == 1'b1)。

  • 协处理器apu需要暂停

  • csr操作在apu操作之后

  • ex阶段未准备就绪

 
 

assign id_ready_o = ((~misaligned_stall) & (~jr_stall) & (~load_stall) & (~apu_stall) & (~csr_apu_stall) & ex_ready_i);

2)id_valid_o信号,其值无效的情况包括halt_id有效或id阶段未准备就绪;

 
 

assign id_valid_o = (~halt_id) & id_ready_o;

3)halt_if_o 信号,由控制模块输出,在存在分支跳转指令、中断等指令需要跳转的情况时,需要暂停if阶段;

 
 

assign halt_if_o = halt_if;

2. 模块内部设计

2.1 cv32e40p_register_file

cv32e40p_register_file模块维护了两组寄存器,即32个整形寄存器和32个浮点寄存器。支持读写两种操作,读操作直接将寄存器标识作为寄存器组索引。

 
 

assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]];

写操作则是将待写入寄存器标识转化为32b位宽位向量,然后根据位向量写回对应寄存器即可。

 
 

//* generate 32b bitmap; genvar gidx; generate for (gidx = 0; gidx < NUM_TOT_WORDS; gidx++) begin : gen_we_decoder assign we_a_dec[gidx] = (waddr_a == gidx) ? we_a_i : 1'b0; end endgenerate //* write registers; if (we_a_dec[i] == 1'b1) mem[i] <= wdata_a_i;

2.2 cv32e40p_decoder

cv32e40p_decoder模块用于解析指令,包括解析跳转指令、访存指令、ALU操作指令、浮点计算指令、向量处理扩展指令、系统特殊指令、CSR处理指令,输出操作码类型{alu_en_o,alu_operator_o,mult_operator_o,mult_int_en_o,mult_dot_en_o,apu_en_o,apu_op_o},输出操作数类型{alu_op_a_mux_sel_o,alu_op_b_mux_sel_o,alu_op_c_mux_sel_o,alu_vec_mode_o,imm_a_mux_sel_o,imm_b_mux_sel_o},以及是否更新寄存器使能信息{regfile_mem_we_o,regfile_alu_we_o},以及一些csr相关信息。

有两点值得注意:1)cv32e40p_decoder预留了原子操作指令的译码功能,但原子处理需要自己在top模块实现,包括读取memory数据,将memory数据与寄存器数据加、减、比较等操作,作为新结果返回load_store_unit,并将该新结果写入memory;2)prepost_useincr_o默认为1,使用基地址累加功能时,prepost_useincr_o置为0。

2.3 cv32e40p_controller

cv32e40p_controller负责控制if、id阶段的启停{halt_if_o,halt_id_o},pc重置和地址选择{pc_set_o,pc_mux_o,exc_pc_mux_o,trap_addr_mux_o},操作数相关的数据旁路选择功能。

cv32e40p_controller的主要功能由一个状态机实现:

  • RESET:复位状态,在芯片复位释放后,使能fetch_enable_i,状态跳转至BOOT_SET;

  • BOOT_SET:启动状态,开始加载指令。若此时需要进入debug模式则状态跳转至DBG_TAKEN_IF’否则状态跳转至FIRST_FETCH;

  • FIRST_FETCH:等待if_stage加载第一条指令,状态跳转至DECODE;

  • DECODE:译码状态,处理动作可以分为几类:1)若遇到分支指令且命中,则需要更新pc值,即将is_decoding_o置“0”以中断当前正在译码的指令,并将pc_set_o置“1”;2)遇到触发进入debug模式的条件,如debug_req有效,或者指令pc进入debug块(trigger_match_i有效),状态条装置DBG_FLUSH;3)检测到中断,需要保存中断类型和中断位置pc值,请求更新PC值以进入中断处理程序,状态仍保留在DECODE;3)遇到非法指令(illegal_insn_i有效),等待id_ready_i有效后状态跳转至FLUSH_EX;4)直接跳转指令,直接重置PC即可;5)ebreak指令,等待进入debug模式,状态跳转至DBG_FLUSH;6)wfi/ecall/fencei/mret/uret/dret指令,则是跳转至FLUSH_EX;

  • FLUSH_EX:在ex阶段插入气泡,同时记录异常类型,状态跳转至FLUSH_WB;

  • ELW_EXE:针对PULP_CLUSTER,用于使cpu进入休眠状态;

  • FLUSH_WB:在wb阶段插入气泡,根据指令类型,重新设置pc值,状态跳转回DECODE;其中,mret/uret/dret指令需要跳转至XRET_JUMP,并请求由csr寄存器赋值pc;

  • XRET_JUMP:retrun指令重置pc值,由crs寄存器赋值,状态跳转至DECODE;

该模块一些值得注意的点:

  • 输出信号instr_req_o用于启动取指功能;

  • 中断控制过程如下,需要记录中断类型、中断位置的pc值

 
 

pc_set_o = 1'b1; pc_mux_o = PC_EXCEPTION; exc_pc_mux_o = EXC_PC_IRQ; exc_cause_o = irq_id_ctrl_i; csr_irq_sec_o = irq_sec_ctrl_i;

  • cv32e40p_pmp应该时进行数据报文(地址匹配),cv32e40p目前时不支持的;

  • 调试模式相关控制信号debug_mode_n会被dret指令置“0”,以退出debug模式;在DBG_TAKEN_ID、DBG_TAKEN_IF状态被置为“1”,以进入debug模式。其中,进入DBG_TAKEN_ID的条件包括:1)ebreak指令;2)trigger_match_i有效,进入debug状态。进入DBG_TAKEN_IF的条件为debug_single_step_i有效。

2.4 cv32e40p_int_controller

cv32e40p_int_controller模块负责实现中断控制功能,即根据输入的32b中断向量(irq_i),以及csr寄存器配置的中断屏蔽向量(mie_bypass_i),计算待处理中断id(irq_id_ctrl_o)。此外,还输出irq_req_ctrl_o使能信号标识中断有效,irq_sec_ctrl_o用于切换m/u状态,以及输出irq_wu_ctrl_o使能信号用于唤醒操作。

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值