20 一文学会制作riscvCPU(第三弹)

一文学会制作riscvCPU(第三弹)

在上述两篇文章中,我们讲解了译码、取值、执行,在取指令的过程中,当遇到分支指令如何跳转也是很重要的,本文讲解实现指令跳转相关部分

PC

module pc (
    input                      clk,
    input                      rst,
    input      [`PCOP_LEN-1:0] pc_op,             // pc 操作码
    input      [    `XLEN-1:0] rs1_data,
    input      [    `XLEN-1:0] imm_data,
    input      [    `XLEN-1:0] execute_data,
    input      [    `XLEN-1:0] clint_pc_i,
    input                      clint_pc_valid_i,
    output reg [    `XLEN-1:0] pc_out
);

首先我们对输入输出进行解析:

Input位数output位数
clk1pc_out (输出的当前PC值)64
rst(复位)1
pc_op(执行pc的操作运算种类)4
rs1_data (rs1的数据的值 )64
imm_data (立即数的值 decode中解析)64
execute_data (alu算出来的值)64
clint_pc_i(PC的值)64
clint_pc_valid_i(PC的有效性)

对PC指令进行解析

  /* pc 操作码 */
  wire _pcop_branch = (pc_op == `PCOP_BRANCH);  // 分支指令: pc = pc + imm
  wire _pcop_jal = (pc_op == `PCOP_JAL);  // jal 指令: pc = pc + imm
  wire _pcop_jalr = (pc_op == `PCOP_JALR);  // jalr 指令: pc = rs1 + imm
  wire _pcop_inc4 = (pc_op == `PCOP_INC4);  // pc 自增: pc = pc +4
  
  wire _pcop_trap = (pc_op == `PCOP_TRAP);  // trap 指令: pc = clint_pc_i
  wire _pcop_none = (pc_op == `PCOP_NONE);  // 暂停: pc = pc

对PC+4进行处理

  wire _isready_branch = (execute_data == `XLEN'b1) & _pcop_branch;  //条件跳转指令
  wire _isready_inc4 = (_pcop_inc4) | ((~_isready_branch) & _pcop_branch);// 跳转指令退化成 +4

对跳转进行处理

  wire [`XLEN-1:0] _pc_a_in = ({`XLEN{_isready_branch | _pcop_jal | _isready_inc4|_pcop_none}} &  _pc_current) |
                              ({`XLEN{_pcop_jalr}} & rs1_data)|
                              ({`XLEN{_pcop_trap}} & clint_pc_i);

  wire [`XLEN-1:0] _pc_b_in = ({`XLEN{_isready_branch|_pcop_jal|_pcop_jalr}}&imm_data) |
                              ({`XLEN{_isready_inc4}} & `XLEN'd4)|
                              ({`XLEN{_pcop_none|_pcop_trap}} & `XLEN'd0);


  wire [`XLEN-1:0] _pc_next;
  reg [`XLEN-1:0] _pc_current;
  assign _pc_next = _pc_a_in + _pc_b_in;

上述代码通过pc指令的不同提取出两个操作数进行相加得到PC的下一次的值与PC的当前值

通过模板实现上升沿跳转

  regTemplate #(
      .WIDTH    (`XLEN),
      .RESET_VAL(`PC_RESET_ADDR)
  ) u_regpc (
      .clk (clk),
      .rst (rst),
      .din (_pc_next),
      .dout(_pc_current),
      .wen (1)
  );

模板的代码如下:

module regTemplate #(
    WIDTH = 1,
    RESET_VAL = 0
) (
    input                  clk,
    input                  rst,
    input      [WIDTH-1:0] din,
    output reg [WIDTH-1:0] dout,
    input                  wen
);
  always @(posedge clk) begin
    if (rst) dout <= RESET_VAL;
    else if (wen) dout <= din;
  end
endmodule

PC的初始值在调用模板函数的时候已经给了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值