自己动手写CPU_step2_构建SOPC

ROM实现指令寄存器

        上一篇中实现的五级流水线需要一个输入,这个输入是指令数据,而指令数据是通过取指阶段的PC控制的,PC会一直循环的取指令。

指令寄存器实现

//指令寄存器
module inst_rom(
    input                       clk,
    input                       rden,
    input [`InstAddrBus]        addr,
    output reg [`InstDataBus]   inst
    );

reg [`InstDataBus]  inst_mem [0:3];
initial $readmemh ( "C:/C_extend/OpenMIPS_CPU_FPGA/inst_rom.data", inst_mem );

always @ (*) begin
    if (rden == 0) begin
        inst <= 32'd0;
    end else begin
        inst <= inst_mem[addr[3:2]];   //PC每加4对应指令寄存器的下一条指令  addr为0时表示第一条指令
    end
end

endmodule

        设计一个inst_rom.data的数据文件,其中存放4条16进制的32位指令,通过PC恰好可以循环遍历这些指令。addr低两位为0因为PC是4的倍数。


流水线顶层设计

//流水线的顶层模块
module openmips(
    input                   clk,
    input                   rst,
    input [`RegDataBus]     rom_data,
    output [`RegAddrBus]    rom_addr,
    output                  rom_rden
    );
    
    pc u_pc(
        .clk            (clk),
        .rst            (rst),
        .pc             (rom_addr),
        .pc_en          (rom_rden)
    );
    wire [`InstAddrBus]     id_pc;
    wire [`InstDataBus]     id_inst;
    if_id u_if_id(
        .clk            (clk),
        .rst            (rst),
        .if_pc          (rom_addr),
        .if_inst        (rom_data),
        .id_pc          (id_pc),
        .id_inst        (id_inst)
    );    
    wire [`RegDataBus]      reg1_data;
    wire [`RegDataBus]      reg2_data;
    wire [`RegAddrBus]      reg1_addr;
    wire [`RegAddrBus]      reg2_addr;
    wire                    reg1_rden;
    wire                    reg2_rden;
    wire [`RegDataBus]      reg1;
    wire [`RegDataBus]      reg2;
    wire                    reg_wb;
    wire [`RegAddrBus]      reg_wb_addr;
    wire [`AluOpBus]        aluop;
    id  u_id(
        .rst            (rst),
        .pc             (id_pc),
        .inst           (id_inst),
        .reg1_data      (reg1_data),
        .reg1_addr      (reg1_addr),
        .reg1_rden      (reg1_rden),
        .reg2_data      (reg2_data),
        .reg2_addr      (reg2_addr),
        .reg2_rden      (reg2_rden),
        .reg1           (reg1),
        .reg2           (reg2),
        .reg_wb         (reg_wb),
        .reg_wb_addr    (reg_wb_addr),
        .aluop          (aluop)
    );
    wire                wr_en;
    wire [`RegAddrBus]  wr_addr;
    wire [`RegDataBus]  wr_data;
    id_reg  u_id_reg(
        .clk            (clk),
        .rst            (rst),
        .reg1_data      (reg1_data),
        .reg1_addr      (reg1_addr),
        .reg1_rden      (reg1_rden),
        .reg2_data      (reg2_data),
        .reg2_addr      (reg2_addr),
        .reg2_rden      (reg2_rden),
        .wr_en          (wr_en),
        .wr_addr        (wr_addr),
        .wr_data        (wr_data)
    );
    wire [`RegDataBus]      ex_reg1;
    wire [`RegDataBus]      ex_reg2;
    wire                    ex_reg_wb;
    wire [`RegAddrBus]      ex_reg_wb_addr;
    wire [`AluOpBus]        ex_aluop;
    id_ex   u_id_ex(
        .clk            (clk),
        .rst            (rst),
        .id_reg1        (reg1),
        .id_reg2        (reg2),
        .id_aluop       (aluop),
        .id_reg_wb      (reg_wb),
        .id_reg_wb_addr (reg_wb_addr),
        .ex_reg1        (ex_reg1),
        .ex_reg2        (ex_reg2),
        .ex_aluop       (ex_aluop),
        .ex_reg_wb      (ex_reg_wb),
        .ex_reg_wb_addr (ex_reg_wb_addr)
    );
    wire                    ex_reg_wb_o;
    wire [`RegAddrBus]      ex_reg_wb_addr_o;
    wire [`RegDataBus]      ex_reg_wb_data_o;
    ex  u_ex(
        .rst            (rst),
        .reg1           (ex_reg1),
        .reg2           (ex_reg2),
        .aluop          (ex_aluop),
        .reg_wb_i       (ex_reg_wb),
        .reg_wb_addr_i  (ex_reg_wb_addr),
        .reg_wb_o       (ex_reg_wb_o),
        .reg_wb_addr_o  (ex_reg_wb_addr_o),
        .reg_wb_data    (ex_reg_wb_data_o)
    );
    wire                    mem_reg_wb;
    wire [`RegAddrBus]      mem_reg_wb_addr;
    wire [`RegDataBus]      mem_reg_wb_data;
    ex_mem u_ex_mem(
        .clk                (clk),
        .rst                (rst),
        .ex_reg_wb          (ex_reg_wb_o),
        .ex_reg_wb_addr     (ex_reg_wb_addr_o),
        .ex_reg_wb_data     (ex_reg_wb_data_o),
        .mem_reg_wb         (mem_reg_wb),
        .mem_reg_wb_addr    (mem_reg_wb_addr),
        .mem_reg_wb_data    (mem_reg_wb_data)
    );
    wire                    mem_reg_wb_o;
    wire [`RegAddrBus]      mem_reg_wb_addr_o;
    wire [`RegDataBus]      mem_reg_wb_data_o;
    mem u_mem(
        .rst                (rst),
        .reg_wb_i           (mem_reg_wb),
        .reg_wb_addr_i      (mem_reg_wb_addr),
        .reg_wb_data_i      (mem_reg_wb_data),
        .reg_wb_o           (mem_reg_wb_o),
        .reg_wb_addr_o      (mem_reg_wb_addr_o),
        .reg_wb_data_o      (mem_reg_wb_data_o)
    );
    mem_wb  u_mem_wb(
        .clk                (clk),
        .rst                (rst),
        .mem_reg_wb         (mem_reg_wb_o),
        .mem_reg_wb_addr    (mem_reg_wb_addr_o),
        .mem_reg_wb_data    (mem_reg_wb_data_o),
        .wb_reg             (wr_en),
        .wb_reg_addr        (wr_addr),
        .wb_reg_data        (wr_data)
    );
endmodule

最小SOPC实现

//基于MIPS五级流水线的最小sopc实现
module openmips_sopc(
    input                   clk,
    input                   rst
    );
    wire            rom_rden;
    wire [4:0]      rom_addr;
    wire [31:0]     rom_data;
    inst_rom inst_rom(
        .clk            (clk),
        .rden           (rom_rden),
        .addr           (rom_addr),
        .inst           (rom_data)  
    );
    openmips openmips(
        .clk            (clk),
        .rst            (rst),
        .rom_data       (rom_data),
        .rom_addr       (rom_addr),
        .rom_rden       (rom_rden)
    );
endmodule

最小SOPC实现之后,就可以开始仿真测试了。

仿真测试

`timescale 1ns / 1ps

module openmips_sopc_tb;

reg     clk;
reg     rst;

initial begin
    clk = 0;
    forever #10 clk = ~clk;     //时钟周期20ns 50MHz
end

initial begin
    rst = 1;
    #200
    rst = 0;
    #1000
    $finish(2);
end

openmips_sopc   u_openmips_sopc(
    .clk        (clk),
    .rst        (rst)
);

endmodule

仿真结果

由图可知,在210ns时,开始了第一次取指令操作pc=0,230ns时开始了第二次的取指令pc=4,同时进行指令1的译码操作,以此类推;在290ns时是指令1的写回阶段,此时的结果是reg1(来源初始寄存器全0)和reg2(来源指令中的立即数)的或运算结果,结果写回指定的地址寄存器;在310ns时,地址为1的寄存器被正确写入了指令1的计算结果。


        至此,CPU中第一条指令ORI设计完成,后续将实现更多指令!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值