简单32位,3级流水线,MIPS CPU设计

我是一个数字设计的新人,做得不对的地方烦请大佬指正。

基本信息

工具:vivado 2019.1

FPGA型号:xc7k480tlffv1156-2L (Xilinx,7系列)

设计包含的指令:ADD,ADDI,SUBU,ORI,OR,AND,SW,LW,BEQ,MULTU,DIVU,MFHI,MFLO,MTHI,MTLO,以上都是MIPS指令集里有的,我自己又弄了MOVE,HALT,INITIAL,RET这几条,一共19条指令。MIPS有的就不做解释,我自己弄的解释一下,MOVE rs,rd(将rs寄存器的值移动到rd寄存器中);HALT系统停机;INITIAL这个是系统刚开始运行执行的,后续无用;RET写过汇编的知道,从call(调用)中返回主程序。

有参考这位大佬的文章(更确切的说是从这篇改过来的,改着改着就从单周期改成了流水线…),我刚开始也是想设计成单周期CPU,后来想着给自己增加难度,即放弃使用寄存器来当ram和rom,改用vivado自带的ip core,使用block memory来作为存储单元。因为block memory的读写有延迟没办法在一个时钟周期完成,就被迫改成了流水线型。

包含的模块:top, instructionsaver, controlunit, registerflie, extend, alu, datasaver, cp, tlb, hireg, loreg, muldiv, lwsw, cp, dcu, beq;

top模块

顶层模块,嗯,同样,pc也在这个里面,没有单独成块。top的功能简单没必要多说。

module CPU_CPU_sch_tb();wire [5:0] operation;wire [4:0] rs;wire [4:0] rt;wire [4:0] rd;wire [15:0] immediate_16;reg clk;wire [31:0] result;wire  [31:0] write_data;wire PCWre;wire ALUSrcB;wire ALUM2Reg;wire RegWre;wire DataMemRW;wire ExtSel;wire PCSrc;wire RegOut;wire Hi_sel_in;wire Hi_sel_out;wire lo_sel_in;wire lo_sel_out;wire Mul;wire Div;wire [31:0] instruction;reg [31:0] PC;wire [31:0] immediate_32;wire [31:0] imm_pc;wire [31:0] readData1;wire [31:0] readData2;wire  [63:0] muldiv_out;wire lw;wire sw;wire  beq;wire move;wire [31:0] result_to_DataMem;wire addr_erro_exception;wire add_overflow_exception;wire rom_en;wire ram_en;wire [14:0] addra;wire [31:0] epc_to_pc;wire pc_sel;wire clean_exc;wire ALUM;wire RegW;wire Hi_in;wire lo_in;wire hi_out;wire lo_out;wire mul;wire div;wire [1:0] ALUOp;reg [31:0] move_to_write_data;reg [31:0] move_to_write_data1;        wire mthi;wire mtlo;wire PCS;wire save_pc;reg [31:0] PC_reg;wire jmp_bk;wire clr;initial beginPC = 32'b0;clk = 0;endalways #5clk = ~clk;InstructionSave instructionsave(PC[7:2],clk,rom_en, save_pc,instruction);assign operation[5:0] = instruction[31:26];
assign rs = instruction[25:21];
assign rt = instruction[20:16];
assign rd = instruction[15:11];
assign immediate_16 = instruction[15:0];hi_reg hireg(muldiv_out[63:32],  readData1,Hi_sel_in,Hi_sel_out,clk,mthi,clr,write_data);lo_reg loreg(muldiv_out[31:0], readData1 ,lo_sel_in,lo_sel_out,clk,mtlo,clr,write_data);muldiv Muldiv(readData1, readData2, Mul, Div,clk, clr, muldiv_out);lwsw Lwsw(readData1, immediate_32, lw, sw, clean_exc,clr, addr_erro_exception,  result_to_DataMem);ControlUnit controlunit (operation, clk,clr, ALUSrcB, ALUM, RegW,PCWre, DataMemRW,ExtSel, PCS , Hi_in, hi_out, lo_in, lo_out, mul, div,lw, sw,move,  RegOut,ram_en,rom_en,mthi,mtlo,jmp_bk,ALUOp);RegisterFile registerfile (rs, rt, rd, write_data, RegWre, RegOut,clk,clr, readData1,readData2);Extend extend(immediate_16, ExtSel, imm_pc,immediate_32);ALU alu(readData1, readData2, immediate_32, ALUSrcB,clean_exc, ALUOp,clk, clr,add_overflow_exception, result);DataSaver datasaver(result,addra, readData2, DataMemRW, addr_erro_exception,ALUM2Reg,clk, ram_en,clr,write_data);CP0_register cp(.clk(clk),.badvaddr(result_to_DataMem),.pc_to_epc(PC),.addr_erro_exception(addr_erro_exception),.add_overflow_exception(add_overflow_exception),.epc_to_pc(epc_to_pc),.pc_sel(pc_sel),.clean_exc(clean_exc));TLB tlb(.clk(clk),.clr(clr),.result_to_DataMem(result_to_DataMem),.addra(addra));dcu DCU(.clk(clk),.clr(clr),.ALUM(ALUM),. RegW(RegW),.Hi_in(Hi_in),. lo_in(lo_in),.hi_out(hi_out),.lo_out(lo_out),. mul(mul),.div(div),. ALUM2Reg(ALUM2Reg),. RegWre(RegWre),. Hi_sel_in(Hi_sel_in),.lo_sel_in(lo_sel_in),.Hi_sel_out(Hi_sel_out),.lo_sel_out(lo_sel_out),. Mul(Mul),.PCS(PCS),.PCSrc(PCSrc),.Div(Div)              );BEQ     beq1(.clk(clk),.jmp_bk(jmp_bk),.PCS(PCS),.readData1(readData1),.readData2(readData2),.beq(beq),.clr(clr));always@(posedge clk) begin if(move == 1'b1)            //用来执行move指令move_to_write_data <= readData1;else move_to_write_data <= 32'bZZZZ_ZZZZ; end            always@(negedge clk)begin               //这里是因为时许问题,所以延迟了数据传递move_to_write_data1 <= move_to_write_data;                     end                         assign     write_data = move_to_write_data1;  always@(posedge clk) 
beginif  ( PCWre == 1'b1)beginif(pc_sel == 1'b1)      PC <= epc_to_pc;    //处理例外的pc返回值else if(jmp_bk == 1'b1)PC <= PC_reg;       //ret将beq的下一条pc附值给pc,即返回主程序继续执行else if(beq == 1'b0)PC <= PC + 4;else PC <= PC + 4 + imm_pc; //beq跳转end           else PC <= PC;
endalways@(posedge clk)                //beq跳转指令后,将beq后一条pc保存,RET指令是读取beginif(save_pc == 1'b1)PC_reg <= PC;else PC_reg <= PC_reg;end  endmodule

instructionsaver

其实就是ROM,用来存储要执行的指令的。这里我用了vivado自带的IP core,生成了block memory(single port ROM,width 32,depth 64),怎么用IP core以及用.coe文件初始化ROM站内有很多文章,我就不重复了。

这是我测试用的coe文件,很简单的。

memory_initialization_radix=2;
memory_initialization_vector=
0_00000000000000000000000000000000
4_100111_00101_11111_0000000000000000
8_100111_00101_11110_0000000000000100
12_110011_01101_00010_11101_00000000000
16_000010_11111_11101_00110_00000000000
20_100000_00111_00000_00110_00000000000
24_100110_00101_00110_0000000000001000
28_100111_00101_01000_0000000000001100
32_010010_01000_11101_11101_00000000000
36_010001_11101_11111_11101_00000000000
40_100111_00101_01001_0000000000010000
44_110000_11111_11110_00000000000000011
48_100111_00101_01100_0000000000100100
52_100111_00101_01101_0000000000101000
56_110000_11111_11110_0000000000000100
60_11111100000000000000000000000000

64_001000_11101_01001_0000000000000000
68_111000_00000_00000_01010_00000000000
72_111100_00000_00000_01011_00000000000
76_001001_00000000000000000000000000

80_110111_01101_01100_0000000000000000
84_111000_00000_00000_01110_00000000000
88_111100_00000_00000_01111_00000000000
92_001001_00000000000000000000000000

第一个_前的0,4,8,12—92,表示该条指令的pc值,真正作为coe文件时要删掉,还有指令中的下划线“_”也要删掉。64—76和80—92算是两个子程序(虽然就是一个乘法,一个除法),乘法在44被调用,但此时48也被读到了流水线内执行,所以要清空流水线,换句话说就是48想被执行但被clr(beq模块产生,用来清空流水线)一巴掌拍回去了,即pc:40–>44–>48–>64–>68…;同样除法在56被调用,pc:52–>56–>60–>80–>84…
用RET指令返回主程序时,pc:72–>76–>80(clr:啪!给我滚回去)–>48–>52…
如图:
在这里插入图片描述

module InstructionSave(input [5:0] pc_addr,input clk,rom_en,output reg save_pc,output  [31:0] instruction);wire [31:0] ins;reg [5:0] inst;blk_mem_gen_1 ROM (.clka(clk),    // input wire clka.ena(rom_en),      // input wire ena.addra(pc_addr),  // input wire [4 : 0] addra.douta(ins)  // output wire [31 : 0] douta  输出端居然只能是wire型,不明白为啥
);assign instruction = ins;always@(ins)inst <= ins[31:26];always@(inst)beginif(inst == 6'b110000)       //监测到beq指令就给出保存下一条pc的信号save_pc <= 1'b1;else save_pc <= 1'b0;end                    endmodule

controlunit

根据不同的指令来产生不同控制信号的模块,具体每一条信号的含义,在代码中有注释。

module ControlUnit(input [5:0] operation,input clk,clr,output reg ALUSrcB,     //选择alu的一个输入数据是readata2(==0)还是immediate_32(==1)output reg ALUM,        //选择往registerfile输入的是来自alu(==0)还是datasaver(==1)的数据output reg RegW,        //registerfile(==1)的写使能信号output reg PCWre,       //pc(==1)自增的使能信号output reg  DataMemRW,      //SRAM(==1)的写使能信号output reg ExtSel,      //extend模块的控制信号 ,符号扩展(==1)和无符号扩展(==0)output reg PCS,         //beq(==1)指令的控制信号output reg Hi_in,       //hireg(==1)的写入控制信号output reg hi_out,      //hireg(==1)的输出控制信号output  reg lo_in,      //loreg(==1)的写入控制信号output  reg lo_out,     //loreg(==1)的输出控制信号output reg mul,         //muldiv模块的控制信号,mul==1 && div==0无符号乘法运算output reg div,         //                                      mul==0 && div==1无符号除法运算output reg lw,          //lwsw(==1)控制信号,output reg sw,          //lwsw(==1)控制信号,output reg move,        //move (==1)output reg  RegOut,     //registerfile模块中用来选择rt(==0)或者rd(==1)output reg ram_en,      //SRAM(==1)使能output reg rom_en,      //ROM(==1)使能output reg mthi,        //MTHI(==1)指令信号,将rs寄存器的值移动到hiregoutput reg mtlo,        //MTLO(==1)指令信号,将rs寄存器的值移动到loregoutput reg jmp_bk,      //RET(==1)指令,用来从调用返回会主程序output  reg [1:0] ALUOp     //alu计算控制信号);parameter ADD = 6'b110011, ADDI = 6'b000001, SUBU = 6'b000010, ORI = 6'b010000,AND = 6'b010001, OR = 6'b010010, MOVE = 6'b100000, SW = 6'b100110,LW = 6'b100111, BEQ = 6'b110000, HALT = 6'b111111,MFHI = 6'b111000,MFLO = 6'b111100,MTHI = 6'b101010,MTLO = 6'b010101, MULTU = 6'b001000,DIVU = 6'b110111,INITIAL = 6'b000000,RET = 6'b001001;always@( operation) begin         if(clr == 1'b1)beginALUOp <= 3'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1; rom_en <= 1'b1;mthi <= 1'bz; mtlo <= 1'bz;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b00zz;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z; {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;PCS <= 1'b0;     move <= 1'b0;     ram_en <= 1'b1;                              endelse     case(operation)ADD:    beginALUOp <= 3'b00; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b001z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z; {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;PCS <= 1'b0;     move <= 1'b0;     ram_en <= 1'b1;                              endADDI:      beginALUOp <= 2'b00; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'b101z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b010z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;          PCS <= 1'b0;          move <= 1'b0;       ram_en <= 1'b1;                                                      end SUBU:         beginALUOp <= 2'b01; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b001z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;        PCS <= 1'b0;         move <= 1'b0;         ram_en <= 1'b1;                                                          end ORI:         beginALUOp <= 2'b10; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b101z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b000z; {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;            PCS <= 1'b0;         move <= 1'b0;           ram_en <= 1'b1;                                                      end AND:         beginALUOp <= 2'b11; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b001z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;            PCS <= 1'b0;         move <= 1'b0;       ram_en <= 1'b1;                                                         end  OR:         beginALUOp <= 2'b10; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'b001z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;       PCS <= 1'b0;          move <= 1'b0;   ram_en <= 1'b1;                                                                  endMOVE:         beginALUOp <=2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bzz1z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;   PCS <= 1'b0;   move <= 1'b1;      ram_en <= 1'b1;                                                                    end SW:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'bzz0z;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b1101; {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;        PCS <= 1'b0;       move <= 1'b0;    ram_en <= 1'b1;                                                                        endLW:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bz111;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b010z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;       PCS <= 1'b0;         move <= 1'b0;     ram_en <= 1'b1;                                                                  endBEQ:         begin         ALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'b01zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;       PCS <= 1'b1;       move <= 1'b0;         ram_en <= 1'b1;                                                                 endRET:         beginALUOp <= 2'b00; jmp_bk <= 1'b1;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW,  lw} <= 4'bzzzz;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b00zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;       PCS <= 1'b0;          move <= 1'b0;   ram_en <= 1'b1;                                                                  end                                    HALT:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b0;rom_en <= 1'b0;mthi <= 1'b0; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'bz0zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;       PCS <= 1'b0;       move <= 1'b0;        ram_en <= 1'b1;                                                               endMFHI:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bzz1z;{DataMemRW, ExtSel, RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bz1zzzz;         PCS <= 1'b0;         move <= 1'b0;      ram_en <= 1'b1;                                                             end   MFLO:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'bzz1z;{DataMemRW, ExtSel, RegOut, sw} <= 4'b001z;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzz1zz;         PCS <= 1'b0;       move <= 1'b0;     ram_en <= 1'b1;                                                                 end   MTHI:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b1; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b00zz; {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;      PCS <= 1'b0;       move <= 1'b0;        ram_en <= 1'b1;                                                              end MTLO:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b1;{ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'b00zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzzz;      PCS <= 1'b0;        move <= 1'b0;    ram_en <= 1'b1;                                                                     end   MULTU:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel,  RegOut, sw} <= 4'b00zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'b1z1z10;       PCS <= 1'b0;        move <= 1'b0;     ram_en <= 1'b1;                                                                 endDIVU:         beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'b00zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'b1z1z01;    PCS <= 1'b0;     move <= 1'b0;     ram_en <= 1'b1;                                                                       end  INITIAL:       beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b1;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'bz0zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzz;   PCS <= 1'b0;        move <= 1'b0;     ram_en <= 1'b1;                                                                      end          default:       beginALUOp <= 2'bzz; jmp_bk <= 1'b0;PCWre <= 1'b0;rom_en <= 1'b1;mthi <= 1'b0; mtlo <= 1'b0;{ ALUSrcB, ALUM, RegW, lw} <= 4'bzzzz;{DataMemRW, ExtSel, RegOut, sw} <= 4'b00zz;  {Hi_in, hi_out, lo_in, lo_out, mul, div} <= 6'bzzzzz;   PCS <= 1'b0;        move <= 1'b0;     ram_en <= 1'b0;                                                                      end                                                                   endcase  end                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
endmodule

registerfile

实际就是定义了一堆寄存器,用来暂存数据。其中clr信号用来清空流水线,BEQ和RET指令会使clr=1,BEQ和RET之前的指令要执行完毕,但BEQ和RET指令后紧跟的一条指令不能执行,因为在执行跳转时整个cpu的存储单元的数值不能有任何变化。

 module RegisterFile(input    [4:0]   rs,rt,rd,input   [31:0] write_data,input       RegWre,RegOut, clk,clr,output [31:0] readData1,readData2);reg [4:0] save;reg [4:0] save_addr;always@(negedge clk)beginif(clr == 1'b1)         //clr信号用来清空流水线,begin save <= 5'bzzzzz;       //对reg写入高阻态,不知道实际应用有没有问题save_addr <= 5'bzzzzz;              end else begin   save <= (RegOut == 0) ? rt : rd;      //因为是3级流水,所以要对写回的地址进行2级缓存//save_addr <= save;                     //-------------------------------------------------------------------------//endend reg     [31:0]  register [31:0]; initial begin$readmemb("my_test_ram.txt", register);endassign readData1 =  register[rs]; //read dataassign readData2 =  register[rt]; always @(posedge clk)beginif (RegWre == 1'b1) begin register[save_addr] <= write_data;      //write dataend end
endmodule

extend

对16位立即数扩展而已,没啥好说的

module Extend(input [15:0] immediate_16,input ExtSel,output [31:0] imm_pc,output [31:0] immediate_32 );wire [15:0] imm;assign imm = immediate_16 << 2;assign imm_pc =  (ExtSel==1'b1) ? {{16{imm[15]}}, imm[15:0]} : {{16{1'b0}}, imm[15:0]};assign immediate_32 = (ExtSel==1'b1) ? {{16{immediate_16[15]}}, immediate_16[15:0]} : {{16{1'b0}}, immediate_16[15:0]};endmodule

alu

算术逻辑单元,这个不会看不懂吧。

module ALU( input [31:0] readData1,input [31:0] readData2,input [31:0] immediate_32,input ALUSrcB,clean_exc,input [1:0] ALUOp,input clk,clr,output  reg add_overflow_exception,output reg [31:0] result);wire [31:0] alu;assign alu = (ALUSrcB == 0) ? readData2 : immediate_32;always@(posedge clk) begin  if(clr == 1'b1)begin result <= 32'bZZZZ_ZZZZ;   add_overflow_exception <= 1'b0;end else if(clean_exc == 1'b1)add_overflow_exception <= 1'b0;else     case (ALUOp)3'b00: {add_overflow_exception,result} <= readData1 + alu;//ADD3'b01: begin result <= alu - readData1; add_overflow_exception <= 1'b0;end  //SUBU3'b10: begin result <= readData1 | alu; add_overflow_exception <= 1'b0;end  //OR3'b11: begin result <= readData1 & alu; add_overflow_exception <= 1'b0;end  //ANDdefault:begin  result <= 32'bZZZZ_ZZZZ;add_overflow_exception <= 1'b0;endendcase
end
endmodule

datasaver

就是SRAM(single port RAM,width 32,depth 1024),不知道为啥depth超过1024就读不出来,所以深度1024的话,addr就只有10位,而我的位宽是32位,所以32位地址得砍掉12位。。。。,看着网上虚拟地址转物理地址脑子懵懵的,所以就瞎写了一个tlb,真的是瞎写的,不然直接砍掉12位感觉有点亏。

module DataSaver(input [31:0] from_alu_result,   input [14:0] addra,input [31:0] readData2,input DataMemRW,input addr_erro_exception,input ALUM2Reg,input clk,ram_en,clr,output  reg [31:0] to_write_data);wire [31:0] dout;wire [9:0] addr;assign addr = addra[9:0];
blk_mem_gen_0 SRAM (.clka(clk),    // input wire clka.ena(ram_en),      // input wire ena.wea(DataMemRW),      // input wire [0 : 0] wea.addra(addr),  // input wire [9 : 0] addra.dina(readData2),    // input wire [31 : 0] dina.douta(dout)  // output wire [31 : 0] douta
);always@(negedge clk)begin       if(clr == 1'b1)to_write_data = 32'bZZZZ_ZZZZ;else  if(ALUM2Reg == 1'b0)to_write_data =from_alu_result;else if(ALUM2Reg == 1'b1)beginif(addr_erro_exception == 1'b1)to_write_data = 32'bZZZZ_ZZZZ;else   to_write_data = dout;end else to_write_data = 32'bZZZZ_ZZZZ;end       
endmodule

cp

CP0寄存器组,用来处理中断例外,以及存储cpu的一些基本信息,不过我没写那么多,处理中断?没有中断,所以不用处理(滑稽);例外包括两种:算术溢出例外和地址错例外。前一种出现后应该跳转到处理例外的程序入口的,但这只是一个裸奔的CPU,就没搞程序入口,直接是有算术溢出例外,直接跳转到零地址从新开始跑,所以看见转圈首先看看是不是add_overflow_exception = 1了;后一种地址错例外完全就是指令没写好,写指令时就应该避免的。

module CP0_register(input clk,input [31:0] badvaddr,input [31:0] pc_to_epc,input addr_erro_exception,input add_overflow_exception,output reg [31:0] epc_to_pc,output reg pc_sel,output reg clean_exc);reg [31:0] BadVaddr;reg [31:0] EPC;wire  exc;initial beginBadVaddr = 32'b0;EPC = 32'b0;end always@(posedge clk)           //BadVaddrbeginif(addr_erro_exception)BadVaddr <= badvaddr;else BadVaddr <= BadVaddr;end always@(posedge clk)                       //EPCbegin  EPC <= pc_to_epc;end assign exc = addr_erro_exception | add_overflow_exception;always@(negedge clk)beginif(exc == 1'b1)begin      epc_to_pc <= 32'b0;pc_sel <= 1'b1;clean_exc <= 1'b1;end else begin epc_to_pc <= 32'bZZZZ_ZZZZ;clean_exc <= 1'b0;   pc_sel <= 1'b0;                                                   end end endmodule

tlb

这个真的是瞎写的,不用看了。

module TLB(input [31:0] result_to_DataMem,input clk,clr,output  reg [14:0] addra);wire [4:0] num;assign num = result_to_DataMem[31] +result_to_DataMem[30] + result_to_DataMem[29] + result_to_DataMem[28]+ result_to_DataMem[27] +result_to_DataMem[26] + result_to_DataMem[25] + result_to_DataMem[24]+ result_to_DataMem[23] +result_to_DataMem[22] + result_to_DataMem[21] + result_to_DataMem[20]+ result_to_DataMem[19] +result_to_DataMem[18] + result_to_DataMem[17] + result_to_DataMem[16]+ result_to_DataMem[15] +result_to_DataMem[14] + result_to_DataMem[13] + result_to_DataMem[12];always@(negedge clk)begin       if(clr == 1'b1)addra <= 15'bZZZZZ;else     casex(num)5'b00000:    addra <= {3'b000,result_to_DataMem[11:0]};5'b00010:    addra <= {3'b001,result_to_DataMem[11:0]};5'b00001:    addra <= {3'b010,result_to_DataMem[11:0]};5'b00011:    addra <= {3'b011,result_to_DataMem[11:0]};5'b001x0:    addra <= {3'b100,result_to_DataMem[11:0]};5'b0100x:    addra <= {3'b101,result_to_DataMem[11:0]};5'b011x0:    addra <= {3'b110,result_to_DataMem[11:0]};default:        addra <= {3'b111,result_to_DataMem[11:0]};        endcase end 
endmodule

hireg

HI寄存器,用来存储乘法和除法的高32位结果。不明白为啥MIPS要专门定义这么一个寄存器。

module hi_reg(input [31:0] hi_in,input [31:0] readData1,input Hi_sel_in,Hi_sel_out,clk,mthi,clr,output  reg [31:0] hi_out);                reg [31:0] hi_mem;initial beginhi_mem = 32'b0;endalways@(negedge clk)begin   if(clr == 1'b1)hi_out <= 32'bZZZZ_ZZZZ;else if(Hi_sel_out == 1'b1)beginhi_out <= hi_mem;end else hi_out <= 32'bZZZZ_ZZZZ;end always@(posedge clk)begin        if(clr == 1'b0)begin if(Hi_sel_in == 1'b1)hi_mem <= hi_in;else    if(mthi == 1'b1)hi_mem <= readData1;else hi_mem <= hi_mem;end  end                                  
endmodule

loreg

LO寄存器,用来存储乘法和除法的低32位结果。

module lo_reg(input [31:0] lo_in,input [31:0] readData1,input lo_sel_in,lo_sel_out,clk,mtlo,clr,output reg  [31:0] lo_out);          reg [31:0] lo_mem;initial beginlo_mem = 32'b0;end            always@(negedge clk)begin       if(clr == 1'b1)lo_out <= 32'bZZZZ_ZZZZ;else     if(lo_sel_out == 1'b1)beginlo_out <= lo_mem;end else lo_out <= 32'bZZZZ_ZZZZ;end always@(posedge clk)begin       if(clr == 1'b0)begin  if(lo_sel_in == 1'b1)lo_mem <= lo_in;else if(mtlo == 1'b1)lo_mem <= readData1;else lo_mem <= lo_mem;end                     end                     
endmodule

muldiv

乘除法模块,没啥需要解释的。

module muldiv(input [31:0]  readData1,input [31:0] readData2,input Mul,Div,clk,clr,output reg [63:0] muldiv_out);always@(posedge clk)begin       if(clr == 1'b1)muldiv_out <= 64'bZZZZ_ZZZZ_ZZZZ_ZZZZ;else  if((Mul==1'b1) && (Div==1'b0))muldiv_out <= readData1 * readData2;else  if((Mul==1'b0) && (Div==1'b1))begin        if(readData2==32'b0)muldiv_out <= 64'bZZZZ_ZZZZ_ZZZZ_ZZZZ;else beginmuldiv_out[63:32] <= readData1/readData2;muldiv_out[31:0] <= readData1%readData2;endend else muldiv_out <= 64'bZZZZ_ZZZZ_ZZZZ_ZZZZ;end endmodule

lwsw

lw:从SRAM取数据到registerfile
sw:将registerfile数据存到SRAM
其实这里有一点我没想明白,lw和sw指令要求地址必须是4的倍数,换成二进制就是最低两位必须是00;32位是4字节,难道读写数据不是整个32位4字节,还能对4个字节中的某些字节读写???或许我太菜了搞不明白,或者理解错了。

module lwsw(input [31:0] readData1,input [31:0] immediate_32,input lw,sw,clean_exc,clr,output  reg addr_erro_exception,output reg   [31:0] result_to_DataMem);reg  [31:0] lw_in;reg    [31:0] sw_in;always@(lw, sw,clean_exc)begin   if(clr ==1'b1)  beginaddr_erro_exception = 1'b0;result_to_DataMem = 32'bZZZZ_ZZZZ;end       else      if(clean_exc == 1'b1)addr_erro_exception = 1'b0;else begin   if(lw ==1'b1)  begin  lw_in = readData1 + immediate_32;if((lw_in[1]==1'b0) && (lw_in[0]==1'b0))begin     addr_erro_exception = 1'b0; result_to_DataMem =  lw_in;endelse begin   addr_erro_exception = 1'b1; result_to_DataMem = 32'bZZZZ_ZZZZ;endend                                  else  if(sw == 1'b1)begin sw_in = readData1 + immediate_32;if((sw_in[1] == 1'b0) && (sw_in[0] == 1'b0))begin       addr_erro_exception = 1'b0;     result_to_DataMem = sw_in; end else begin addr_erro_exception = 1'b1; result_to_DataMem = 32'bZZZZ_ZZZZ; end   end                                                                                 else    begin addr_erro_exception = 1'bz;   result_to_DataMem = 32'bZZZZ_ZZZZ; endend end 
endmodule

dcu

其实是delay controlunit的简写啦,对某些控制信号进行缓存输出用。

module dcu(input clk,clr,input ALUM,input RegW,input Hi_in,  lo_in, hi_out,lo_out,input mul,div,PCS,output reg ALUM2Reg,output reg RegWre,output reg Hi_sel_in, lo_sel_in,Hi_sel_out,lo_sel_out,output reg Mul,Div,PCSrc);reg alum;reg regw1;reg HI_IN,LO_IN;reg HI_OUT,LO_OUT;reg MUL,DIV;reg pcs;always@(posedge clk)beginALUM2Reg <= ALUM;end always@(negedge clk)if(clr == 1'b1)begin regw1 <= 1'bz;RegWre <= 1'bz;Hi_sel_out <= 1'bz;lo_sel_out <= 1'bz;HI_IN <= 1'Bz;Hi_sel_in <= 1'b1;LO_IN <= 1'B1;lo_sel_in <= 1'b1;Mul <= 1'b1;Div <= 1'b1;end else beginregw1 <= RegW;RegWre <= regw1;Hi_sel_out <= hi_out;lo_sel_out <= lo_out;HI_IN <= Hi_in;Hi_sel_in <= HI_IN;LO_IN <= lo_in;lo_sel_in <= LO_IN;Mul <= mul;Div <= div;                            end 
endmodule

BEQ

用来执行跳跃的模块,clr信号就是这里产生的。

module BEQ(input clk,jmp_bk,input PCS,input [31:0] readData1,readData2,output reg beq,clr);always@(negedge clk)beginif(PCS == 1'b1)begin                if(readData1 == readData2) begin    beq <= 1'b1;clr <= 1'b1;endelse begin beq <= 1'b0;clr <= 1'b0;endend else if(jmp_bk == 1'b1) begin beq <= 1'b0;clr <= 1'b1;endelse begin  beq <= 1'b0;clr <= 1'b0;endend 
endmodule

讲真,刚开始写时就是懵懵比比的,没有看别人的就急着动手,结果就是这都是些啥啊,理不清关系一样,跑出来的结果全是xxx。后来看了那位大佬写的才慢慢明白了点,然后就自己改,前前后后改了好几个版本,虽然还有瑕疵,但也算是我比较满意的版本了。吸取的教训就是磨刀不误砍柴工,改成流水线时,一点一点你理清脉络,含快就写好了,几个小错改改就弄好了。加油!小菜鸟。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部