类MIPS单周期微处理器设计(单周期CPU)

类MIPS单周期微处理器设计(单周期CPU)

文章目录

  • 类MIPS单周期微处理器设计(单周期CPU)
    • 一、实验目的
    • 二、实验任务与要求
    • 二、实验内容和步骤
      • 1、设计思路
        • 1.1 整体设计
        • 1.2 子模块的设计
        • 1.3 顶层模块的设计
      • 2、设计源代码及注释
        • 2.1 顶层模块mips
        • 2.2 算术逻辑单元ALU
        • 2.3 寄存器文件RegFile
        • 2.4 主控制译码MainCtr
        • 2.5 ALU控制信号译码ALUCtr
      • 3、 部分模块仿真及波形
        • 3.1 算术逻辑单元ALU的仿真
        • 3.2 寄存器文件RegFile的仿真
        • 3.3 顶层模块mips的仿真

一、实验目的

  • 熟悉Verilog语言的编写;
  • 掌握单周期CPU的功能实现逻辑并理解过程;
  • 熟练掌握ise和vivado等软件并进行开发并实现逻辑功能。

二、实验任务与要求

基本要求:利用Verilog HDL语言,基于Xilinx FPGA nexys4实验平台,设计一个能够执行以下MIPS指令集的单周期类MIPS处理器,要求完成所有支持指令的功能仿真,验证指令执行的正确性;

  • 支持基本的算术逻辑运算如add,sub,and,or,slt, a n d i \textcolor{red}{andi} andi指令;

  • 支持基本的内存操作如lw,sw指令;

  • 支持基本的程序控制如beq,j指令。

二、实验内容和步骤

1、设计思路

1.1 整体设计

类MIPS单周期微处理器设计(单周期CPU)_第1张图片

​ 根据单周期mipsCPU的结构分析知,可以将子模块分为数据存储器dram、指令存储器irom、寄存器文件RegFile、主控制译码MainCtr、ALU控制信号译码ALUCtr以及算术逻辑单元ALU,分别实现各个模块的功能;

​ 再将控制信号等在mips的顶层模块中使用assign语句进行赋值,同时在顶层模块中进行其余子模块的实例化,使之与控制信号以及32位Instr等进行关联,对于不同的指令都有对应于各自的控制信号;

1.2 子模块的设计

  • 指令存储器irom

​ 使用vivado的IPcore实现指令存储器irom的逻辑功能。在时钟上升沿到来时,读入PC信号的高五位,作为地址,输出相应的32位Instr指令,此处我们在vivado中导入text.coe到irom_IP中,其本质为16进制的32位机器码,机器码对照表如下:
类MIPS单周期微处理器设计(单周期CPU)_第2张图片
ps:此处的起始地址应该为0x00000000,j指令也应该相应地跳回0x00000000.

  • 数据存储器dram

​ 使用vivado的IPcore实现数据存储器dram的逻辑功能。在时钟下降沿到来时,根据写数据的使能信号MenWr决定是否在输入的地址addr处写入输入的数据DataIn,除此之外还会输出存储在输入的地址addr处的数据到DataOut;

  • 寄存器文件RegFile

​ 使用Verilog语言编写实现寄存器文件RegFile的逻辑功能。在时钟下降沿到来时,倘若写使能信号RegWr为高电平且复位信号reset为低电平,则将输入的数据DataIn写到地址为输入写地址WrAddr处的寄存器regs[WrAddr];倘若复位信号reset为高电平,则我们将regs的值设定为初始默认值regs[i]=i(按照要求也可将其写为学号的ASCII码)。模块中同时使用assign语句决定RsData和RtData的值是0或者地址为RsAddr或RtAddr的寄存器的值。

  • 主控制译码MainCtr

​ 使用Verilog语言编写实现主控制译码MainCtr的逻辑功能。输入Instr的高六位,输出控制信号和ALUOp,根据每个指令调用的模块得到各个控制信号的状态,再将ALUOp输入到ALU控制信号译码ALUCtr中去。

类MIPS单周期微处理器设计(单周期CPU)_第3张图片

  • ALU控制信号译码ALUCtr

​ 使用Verilog语言编写实现ALU控制信号译码ALUCtr的逻辑功能。输入ALUOp和Instr的低六位Funct,输出各个指令相应的ALUCtr信号,并且输入到算术逻辑单元ALU中去,其中andi和and的ALUOp和Funct虽然不同,但ALUCtr是一致的。类MIPS单周期微处理器设计(单周期CPU)_第4张图片

  • 算术逻辑单元ALU

​ 使用Verilog语言编写算术逻辑单元ALU。输入符号数字In1和符号数In2,由输入的ALUCtr信号觉得要做的运算,事实上我们采用的编码让sw和lw在算术逻辑单元ALU中所做的运算为add,andi所做的为and,beq所做的为sub。并且Zero信号默认为0,只有在执行sub运算时有机会为1,当其为1时,BranchZ = B & Zero才有机会为1,让PC跳转到BranchPC = ImmL2 + SquencePC,即左移两位的立即数与PC加4后的和。

1.3 顶层模块的设计

​ 顶层模块的输入信号仅有时钟信号clk和复位信号reset,声明一系列中间信号,使用assign语句和子模块实例化实现指令功能的完成以及控制信号的传递,数据的读写运算等。除此之外,使用always语句实现PC信号的选择和PC的复位。

2、设计源代码及注释

​ 由于不同的指令需求,对于ALUCtr和MainCtr的编码不同,笔者在此处给出部分源码:

2.1 顶层模块mips

`timescale 1ns / 1ps

module mips (
    input clk, 
    input reset 
);

    wire [31:0] TempPC, JumpPC, MuxPC, SquencePC, BranchPC, Imm32, ImmL2, regWriteData, RsData, RtData, ALUin2, ALUres, memReadData, Instr;
    wire [4:0] regWriteAddr;
    wire [27:0] PsudeoPC;
    wire [1:0] ALUop;
    wire [3:0] ALUctr;
    wire BranchZ, regDst, ALUsrc, M2R, regWriteEn, zero, memWriteEn, B, J;
    reg [31:0] PC;

    assign PsudeoPC = {Instr[25:0], 2'b00};
    assign JumpPC = {SquencePC[31:28], PsudeoPC};
    assign TempPC = J ? JumpPC : MuxPC;
    assign MuxPC = BranchZ ? BranchPC : SquencePC;
    assign BranchPC = ImmL2 + SquencePC;
    assign ImmL2 = {Imm32[29:0], 2'b00};
    assign Imm32 = {Instr[15] ? 16'hffff : 16'h0000, Instr[15:0]};
    assign BranchZ = B & zero;
    assign regWriteAddr = regDst ? Instr[15:11] : Instr[20:16];
    assign ALUin2 = ALUsrc ? Imm32 : RtData;
    assign regWriteData = M2R ? memReadData : ALUres;
    assign SquencePC = PC + 4;
       
    always @(negedge clk) begin
        if(reset)
            PC <= 32'h0;
        else 
            PC <= TempPC;
    end

    ALU U0(RsData,ALUin2,ALUctr,ALUres,zero);
    //dram U1(memWriteEn,ALUres[6:2],memReadData,RtData);
    //irom U2(PC[6:2],Instr);
    dram_IP U1(~clk,memWriteEn,ALUres[6:2],RtData,memReadData);
    irom_IP U2(clk,PC[6:2],Instr);

    RegFile U3(~clk,reset,regWriteEn,Instr[25:21],Instr[20:16],regWriteAddr,regWriteData,RsData,RtData);
    MainCtr U4(Instr[31:26],regDst,ALUsrc,M2R,regWriteEn,memWriteEn,B,J,ALUop);
    ALUCtr U5(ALUop,Instr[5:0],ALUctr);
    
endmodule

2.2 算术逻辑单元ALU

`timescale 1ns / 1ps

module ALU (
    input signed [31:0] In1,
    input signed [31:0] In2,  
    input [3:0] ALUCtr,
    output reg [31:0] Res,
    output reg Zero
);

always @(In1 or In2 or ALUCtr) begin
    case (ALUCtr)
        4'b0110://sub
        begin
        Res = In1 - In2; 
        Zero = (Res == 0) ? 1 : 0;
        // only sub needs Zero be 1
        end

        4'b0010://add
        begin
        Res = In1 + In2; 
        Zero = 0;
        end

        4'b0000://and
        begin
        Res = In1 & In2; 
        Zero = 0;
        end

        4'b0001://or
        begin
        Res = In1 | In2; 
        Zero = 0;
        end

        4'b0111://slt
        begin
        Res = (In1 < In2) ? 1 : 0; 
        Zero = 0;
        end

        default: 
        begin
        Res = 0;
        Zero = 0;
        end
    endcase
end  
endmodule

2.3 寄存器文件RegFile

`timescale 1ns / 1ps

module RegFile (
    input         clk,
    input         reset,
    input         RegWr,//regWriteEn
    input  [4:0]  RsAddr,
    input  [4:0]  RtAddr,
    input  [4:0]  WrAddr,//regWriteAddr
    input  [31:0] DataIn,//regWriteData
    output [31:0] RsData,
    output [31:0] RtData
);
// 32 regs, for each one is 32
reg [31:0] regs[0:31];

assign RsData = (RsAddr == 5'b0) ? 32'b0 : regs[RsAddr]; 
assign RtData = (RtAddr == 5'b0) ? 32'b0 : regs[RtAddr]; 

integer i;
always @(posedge clk) begin
    if(!reset & RegWr) begin
        regs[WrAddr] = DataIn;
    end

    else if(reset) begin
        for (i = 0; i < 32; i = i + 1) begin
            regs[i] = i;
        end
    end
end
endmodule

2.4 主控制译码MainCtr

`timescale 1ns / 1ps

module MainCtr (
    input [5:0] OpCode,// Instr[31:26]
    output RegDst,
    output ALUSrc,
    output Mem2Reg,
    output RegWr,
    output MemWr,
    output B,
    output J, 
    output [1:0] ALUOp
);
    reg [8:0] outputtemp;

    assign RegDst = outputtemp[8];
    assign ALUSrc = outputtemp[7];  
    assign Mem2Reg = outputtemp[6];  
    assign RegWr = outputtemp[5];  
    assign MemWr = outputtemp[4];  
    assign B = outputtemp[3];  
    assign J = outputtemp[2];  
    assign ALUOp = outputtemp[1:0];

    always @(OpCode) begin
        case (OpCode)
            6'b000010: outputtemp = 9'bxxx0001xx;// j
            6'b000000: outputtemp = 9'b100100010;// R
            6'b100011: outputtemp = 9'b011100000;// lw
            6'b101011: outputtemp = 9'bx1x010000;// sw
            6'b000100: outputtemp = 9'bx0x001001;// beq
            6'b001100: outputtemp = 9'b010100011;// andi
            default:   outputtemp = 9'b000000000;// default
        endcase
    end
endmodule

2.5 ALU控制信号译码ALUCtr

`timescale 1ns / 1ps

module ALUCtr (
    input [1:0] ALUOp,
    input [5:0] Funct,
    output reg [3:0] ALUCtr
);
    always @(ALUOp or Funct) begin
        casex ({ALUOp, Funct})
            8'b00xxxxxx: ALUCtr[3:0] = 4'b0010;// lw, sw
            8'b01xxxxxx: ALUCtr[3:0] = 4'b0110;// beq
            8'b10xx0000: ALUCtr[3:0] = 4'b0010;// add
            8'b10xx0010: ALUCtr[3:0] = 4'b0110;// sub
            8'b10xx0100: ALUCtr[3:0] = 4'b0000;// and 
            8'b10xx0101: ALUCtr[3:0] = 4'b0001;// or
            8'b10xx1010: ALUCtr[3:0] = 4'b0111;// slt
            8'b11xxxxxx: ALUCtr[3:0] = 4'b0000;// andi->and
            default:     ALUCtr[3:0] = 4'b0000;// initial
        endcase
    end
endmodule

3、 部分模块仿真及波形

3.1 算术逻辑单元ALU的仿真

  • 仿真sim文件
`timescale 1ns / 1ps

module ALU_sim(
    output [31:0] Res,
    output Zero
    );
    reg [31:0] In1,In2;
    reg [3:0] ALUCtr;
    
    ALU S1(In1,In2,ALUCtr,Res, Zero);

    initial begin
    In1 = 32'hffff0000;
    In2 = 32'h00ffff00;
    ALUCtr=4'h2;
    #10
    ALUCtr=4'h6;
    #10
    ALUCtr=4'h0;
    #10
    ALUCtr=4'h1;
    #10
    ALUCtr=4'h7;
    end 
endmodule
  • 仿真波形类MIPS单周期微处理器设计(单周期CPU)_第5张图片

3.2 寄存器文件RegFile的仿真

  • 仿真sim文件
`timescale 1ns/1ps

module RegFile_sim (
    output [31:0] RsData,
    output [31:0] RtData
);
    reg clk;
    reg reset;
    reg regWriteEn;
    reg [4:0] RsAddr;
    reg [4:0] RtAddr;
    reg [4:0] regWriteAddr;
    reg [31:0] regWriteData;

    parameter PERIOD = 10;

    always begin
        clk = 1'b0;
        #(PERIOD/2) clk = 1'b1;
        #(PERIOD/2) ;  
    end

    initial begin
    reset = 1;
    RsAddr = 5'h0;
    RtAddr = 5'h0;
    #15

    reset = 0;
    #30

    regWriteEn = 1;
    regWriteAddr = 5'h03;
    regWriteData = 32'h5aa5;
    #20

    RsAddr = 5'h03;
    RtAddr = 5'h03;
    end

    RegFile S2(clk,reset,regWriteEn,RsAddr,RtAddr,regWriteAddr,regWriteData,RsData,RtData);
 
endmodule
  • 仿真波形
    类MIPS单周期微处理器设计(单周期CPU)_第6张图片

3.3 顶层模块mips的仿真

  • 仿真sim文件
module mips_sim (

);
    reg clk;
    reg reset;
    mips U0(clk, reset);

    parameter PERIOD = 10;

    always begin
        clk = 1'b0;
        # (PERIOD/2) clk = ~clk;
        # (PERIOD/2)    
    end

    initial begin
    reset = 1;
    #20 

    reset = 0;
    end
endmodule
  • 仿真波形
    类MIPS单周期微处理器设计(单周期CPU)_第7张图片

你可能感兴趣的:(verilog,verilog,嵌入式,mips,fpga,编程语言)