LoongArch CPU设计实验_实践任务5:5条指令单周期CPU

实践任务5:5条指令单周期CPU

本实践任务要求:

阅读并理解实验环境中提供的代码,补充代码中缺失的部分,使设计可以通过仿真和上板验证。
请参照第2.3.1节中介绍的方式获取本次实践任务所需的实验开发环境。具体的实验环境位于 mini_env/ 目录下,其组织结构和使用方式已在本章4.1节介绍过,此处不再重复。

实验环境准备就绪后,请参考下列步骤完成本实践任务:

  1. 在 minicpu_env/soc_verify/run_vivado/ 目录下打开miniCPU工程。如需要,请参考附录D.4节进行工程和IP核升级。
  2. 对miniCPU工程中的inst_ram重新定制,选择对应func的coe文件(minicpu_env/func/inst_ram.coe)。
  3. 运行miniCPU工程的仿真(进入仿真界面后,直接点击run all),开始调试。可以修改 minicpu_env/soc_verify/testbench/ 目录下的minicpu_tb.v文件中的switch值观察led输出值是否符合预期(每次修改switch值之后都要重新仿真)。(因为本实验的测试程序为斐波那契数程序,斐波那契数列是:0,1,1,2,3,5,……从第三项开始,每一项都等于前两项之和。规定数列第三项为f(1),即f(1)=1,f(2)=2,f(3)=3,f(4)=5, …… 。修改拨码开关switch值相当于修改n,led输出值对应f(n)。
  4. myCPU仿真通过后,综合实现后生成bit流文件,进行上板验证。(如果无硬件实验平台,请跳过该步骤。)

指令格式

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

inst_ram

1c000000:       addi.w   $t0,$zero,0x0      //置第1项的0
1c000004:       addi.w   $t1,$zero,0x1      //置第2项的1
1c000008:       addi.w   $s0,$zero,0x0      //循环变量i初始化为0
1c00000c:       addi.w   $s1,$zero,0x1      //循环的步长置为1
1c000010:       ld.w     $a0,$zero,1024     //读取拨码开关输入的终止值
          loop:
1c000014:       add.w    $t2,$t0,$t1        //f(i) = f(i-2) + f(i-1) 
1c000018:       addi.w   $t0,$t1,0x0        //记录f(i-1)
1c00001c:       addi.w   $t1,$t2,0x0        //记录f(i) 
1c000020:       add.w    $s0,$s0,$s1        //i++
1c000024:       bne      $s0,$a0,loop       //if i!=n, goto loop
1c000028:       st.w     $t2,$zero,1028     //将f(n)的值输出到数码管上
          end:
1c00002c:       bne      $s1, $zero, end    //测试完毕,进入死循环

代码

module minicpu_top(
    input  wire        clk,
    input  wire        resetn,

    output wire        inst_sram_we,
    output wire [31:0] inst_sram_addr,
    output wire [31:0] inst_sram_wdata,
    input  wire [31:0] inst_sram_rdata,

    output wire        data_sram_we,
    output wire [31:0] data_sram_addr,
    output wire [31:0] data_sram_wdata,
    input  wire [31:0] data_sram_rdata
);

reg         reset;
always @(posedge clk) reset <= ~resetn;

reg         valid;
always @(posedge clk) begin
    if (reset) begin
        valid <= 1'b0;
    end
    else begin
        valid <= 1'b1;
    end
end

reg  [31:0] pc;
wire [31:0] nextpc;
   
wire [31:0] inst;

wire [ 5:0] op_31_26;
wire [ 3:0] op_25_22;
wire [ 1:0] op_21_20;
wire [ 4:0] op_19_15;
wire [63:0] op_31_26_d;
wire [15:0] op_25_22_d;
wire [ 3:0] op_21_20_d;
wire [31:0] op_19_15_d;
wire [ 4:0] rd;
wire [ 4:0] rj;
wire [ 4:0] rk;
wire [11:0] i12;
wire [15:0] i16;
wire [15:0] i16_2;

wire        inst_add_w;
wire        inst_addi_w;
wire        inst_ld_w;
wire        inst_st_w;
wire        inst_bne;

wire        src2_is_imm;
wire        res_from_mem;
wire        gr_we;
wire        mem_we;
wire        src_reg_is_rd;
wire [31:0] rj_value;
wire [31:0] rkd_value;

wire [ 4:0] rf_raddr1;
wire [ 4:0] rf_raddr2;
wire [ 4:0] rf_waddr;
wire [31:0] rf_wdata;

wire        br_taken;
wire        rj_eq_rd;
wire [31:0] br_offs;
wire [31:0] br_target;

wire [31:0] imm;
wire [31:0] alu_src1;
wire [31:0] alu_src2;
wire [31:0] alu_result;


always @(posedge clk) begin
    if (reset) begin
        pc <= 32'h1bfffffc;     //trick: to make nextpc be 0x1c000000 during reset 
    end
    else begin
        pc <= nextpc;
    end
end

assign inst_sram_we    = 1'b0;
assign inst_sram_addr  = pc;
assign inst_sram_wdata = 32'b0;
assign inst            = inst_sram_rdata;

assign op_31_26 = inst[31:26];
assign op_25_22 = inst[25:22];
assign op_21_20 = inst[21:20];
assign op_19_15 = inst[19:15];
assign rd       = inst[ 4: 0];
assign rj       = inst[ 9: 5];
assign rk       = inst[14:10];
assign i12      = inst[21:10];
assign i16      = inst[25:10];
assign i16_2    = i16 << 2;

decoder_6_64 u_dec0(.in(op_31_26 ), .co(op_31_26_d ));
decoder_4_16 u_dec1(.in(op_25_22 ), .co(op_25_22_d ));
decoder_2_4  u_dec2(.in(op_21_20 ), .co(op_21_20_d ));
decoder_5_32 u_dec3(.in(op_19_15 ), .co(op_19_15_d ));

assign inst_add_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h00];
assign inst_addi_w = op_31_26_d[6'h00] & op_25_22_d[4'ha];
assign inst_ld_w   = op_31_26_d[6'h0a] & op_25_22_d[4'h2];
assign inst_st_w   = op_31_26_d[6'h0a] & op_25_22_d[4'h6];
assign inst_bne    = op_31_26_d[6'h17];

assign src2_is_imm   = inst_addi_w | inst_ld_w | inst_st_w;//在这里实现立即数选择信号
assign res_from_mem  = inst_ld_w;
assign gr_we         = inst_add_w | inst_ld_w | inst_addi_w;
assign mem_we        = inst_st_w;
assign src_reg_is_rd = inst_bne | inst_st_w;

assign rf_raddr1 = rj;
assign rf_raddr2 = src_reg_is_rd ? rd : rk;
regfile u_regfile(
    .clk    (clk      ),
    .raddr1 (rf_raddr1),
    .rdata1 (rj_value ),
    .raddr2 (rf_raddr2),
    .rdata2 (rkd_value),
    .we     (gr_we    ),
    .waddr  (rf_waddr ),
    .wdata  (rf_wdata )
    );//在空出的括号里完成引脚匹配

assign br_offs   = {{14{i16[15]}}, i16, 2'b00};//在这里完成br_offs信号的生成
assign br_target = pc + br_offs;
assign rj_eq_rd  = (rj_value == rkd_value);
assign br_taken  = valid && inst_bne && !rj_eq_rd;
assign nextpc    = br_taken ? br_target : pc + 4;//在这里实现nextpc信号的生成

// se si12
assign imm      = {{20{i12[11]}},i12[11:0]};
assign alu_src1 = rj_value;
assign alu_src2 = src2_is_imm ? imm : rkd_value;//在这里实现alu_src2信号

assign alu_result = alu_src1 + alu_src2;

assign data_sram_we    = mem_we;
assign data_sram_addr  = alu_result;
assign data_sram_wdata = rkd_value;

assign rf_waddr = rd;
assign rf_wdata = res_from_mem ? data_sram_rdata : alu_result;//在这里完成写回寄存器值的选择

endmodule

仿真

led低电平
在这里插入图片描述

参考资料

[1] CPU设计实战(汪文祥)第四章
[2] LoongArch CPU设计实验_实践任务5
[3] CDP_EDE_local
[4] 龙芯架构32位精简版参考手册

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值