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设计完成,后续将实现更多指令!