MIPS单周期CPU设计——lw和sw指令的设计

1.lw,sw指令格式及功能

指令 [31:26] [25:21] [20:16] [15:0] 意义
lw 100011 rs rt offset 从数存(数据存储器)中取数据写进寄存器
sw 101011 rs rt offset 将寄存器中的值写入数存

2.所需模块框图及指令执行过程

MIPS单周期CPU设计——lw和sw指令的设计_第1张图片
       lw指令和sw指令需要DataMem(数据存储器)来取数据或存数据。

       执行过程:
       lw:
       从数存中取数据写入寄存器,rega提供数存单元地址(源),regc提供寄存器地址(目的)。
       ①IF模块将指令地址pc和片选信号romCe送入指存InstMem,存InstMem中取出数据由data脚送入ID模块的inst脚。
       ②ID将送入的inst进行译码,对于lw指令,将指令中的rs为送入regaAddr,连同regaRd读信号送入寄存器堆RegFile,读出regaData,送入ID模块的regaData_i。regaData_i里的数据加上指令中(经符号位扩展的)offset位,即regaData_i+offset,regaData_i+offset表示的就是要取的数据(在数存中)的地址。将regaData_i+offset送入ID的regaData,将指令中的rt位送入regcAddr。将ID中的regaData,regcAddr和regcWr分别送入EX模块的regaData,regcAddr_i和regcWr_i。
       ③EX模块的regaData作为memAddr送入内存MEM,regcAddr_i和regcWr_i作为regcAddr和regcWr送入MEM。
       ④MEM将送入的memAddr给要送出的memAddr(这里纠正框图中的一个错误,送入的memAddr应改为memAddr_i,modelsim中不能有命名相同的参数或变量。所以在这里将memAddr_i和memAddr分别称为要送入的memAddr和要送出的memAddr,下文也是一样,不再说明),将要取的数据地址memAddr和片选信号memCe送入数存DataMem,读取数据,从rdData送入MEM。
       ⑤MEM将rdData作为regData,将regcAddr作为regAddr,将regcWr作为regWr,然后将regData,regAddr和regWr送入regFile,将数据regData写进地址为regAddr的寄存器中。lw指令执行完毕。

       sw:
       将寄存器中的数据写入数存,rega提供数存单元地址(目的),regb提供寄存器地址(源)。
       ①IF模块将指令地址pc和片选信号romCe送入指存InstMem,存InstMem中取出数据由data脚送入ID模块的inst脚。
       ②ID将送入的inst进行译码,对于sw指令,将指令中的rs位送入regaAddr。指令中的rt位送入regbAddr,将regbAddr、regaAddr、regaRd,regbRd送入RegFile,找到regbData和regaData送入ID的regbData_i和regaData_i。将regaData_i加上(经符号位扩展)的offset,并送入regaData。此时regaData中保存的就是要写入的数据在数存中的地址,regbData保存的就是要写入数存中的数据。将regaData和regbData分别送入EX的regaData和regbData。
       ③EX中,将regaData作为memAddr,regbData作为memData,分别送入MEM中的memAddr和memData。
       ④MEM将memData作为wtData,连通memAddr,memWr和memCe分别送入DataMem中的wtData、addr、we和ce,将数据写进DataMem,sw指令执行完毕。

3.代码

       ①define.v


`define RstEnable        1'b0
`define RstDisable       1'b1

`define RomDisable       1'b0
`define RomEnable        1'b1

`define RamWrite         1'b1
`define RamUnWrite       1'b0
`define RamEnable        1'b1
`define RamDisable       1'b0

`define Valid            1'b1
`define Invalid          1'b0

`define Zero             32'h00000000
`define nop              6'b001101

`define Inst_lw          6'b100011
`define Inst_sw          6'b101011

`define Lw              6'b001100
`define Sw              6'b001101

       ②IF.v


`include "define.v"

module IF(

    input wire clk,
    input wire rst,
    output reg [31:0] pc,
    output reg romCe,
    input wire [31:0] jAddr,
    input wire jCe
    

);

    always@(*)
        if(rst == `RstEnable)
           romCe = `RomDisable;
        else
            romCe = `RomEnable;

     always@(posedge clk)
        if(romCe == `RomDisable)
            pc = `Zero;
        else if(jCe == `Valid)
            pc = jAddr;
        else
            pc = pc+4;

endmodule

       ③InstMem.v


`include "define.v"

module InstMem(

    input wire ce,
    input wire [31:0] addr,
    output reg [31:0] data
);

    reg [31:0] instmem [1023:0];
    always@(*)
        if(ce == `RomDisable)
            data = `Zero;
        else
            data = instmem[addr[11:2]];
    initial
        begin
            instmem[0] = 32'h8E1F0001;  //lw
            instmem[1] = 32'hAC890000;  //sw
        end

endmodule

       ④ID.v


`include "define.v"

module ID(

    input wire rst,
    input wire [31:0] inst,
    input wire [31:0] regaData_i,
    input wire [31:0] regbData_i,
    input wire [31:0] pc_i,
    output reg [5:0] op,
    output reg [31:0] regaData,
    output reg [31:0] regbData,
    output reg regcWr,
    output reg [31:0] regcAddr,
    output reg regaRd,
    output reg [31:0] regaAddr,
    output reg regbRd,
    output reg [31:0] regbAddr,
    output reg [31:0] jAddr,
    output reg jCe,
    output wire [31:0] pc
);

    wire [31:0] npc = pc + 4;
    wire [5:0] Inst_op = inst[31:26];
    wire [5:0] func = inst[5:0];
    reg [31:0] imm;

//    assign pc = pc_i;


    always@(*)
        if(rst == `RstEnable)
            begin
                op = `nop;
                regaRd = `Invalid;
                regbRd = `Invalid;
                regcWr = `Invalid;
                regaAddr = `Zero;
                regbAddr = `Zero;
                regcAddr = `Zero;
                imm = `Zero;
                jCe = `Invalid;
                jAddr = `Zero;
            end
        else
            begin
                jCe = `Invalid;
                jAddr = `Zero;
            case(Inst_op)
                `Inst_lw:
                    begin
                        op = `Lw;
                        regaRd = `Valid;
                        regbRd = `Invalid;
                        regcWr = `Valid;
                        regaAddr = inst[25:21];
                        regbAddr = `Zero;
                        regcAddr = inst[20:16];
                        imm = {{16{inst[15]}},inst[15:0]};
                    end
                `Inst_sw:
                    begin
                        op = `Sw;
                        regaRd = `Valid;
                        regbRd = `Valid;
                        regcWr = `Invalid;
                        regaAddr = inst[25:21];
                        regbAddr = inst[20:16];
                        regcAddr = `Zero;
                        imm = {{16{inst[15]}},inst[15:0]};
                    end
            endcase
            end
    always@(*)
        if(rst == `RstEnable)
            regaData = `Zero;
        else if(op == `Lw || op == `Sw)
            regaData = regaData_i + imm;
        else if(regaRd == `Valid)
            regaData = regaData_i;
        else
            regaData = imm;

    always@(*)
        if(rst == `RstEnable)
            regbData = `Zero;
        else if(regbRd == `Valid)
            regbData = regbData_i;
        else
            regbData = imm;
endmodule

       ⑤EX.v

`include "define.v"

module EX(

    input rst,
    input wire [5:0] op_out,
    input wire [5:0] op_i,

//    input wire [31:0] pc_i,
    input wire [31:0] regaData,
    input wire [31:0] regbData,
    output reg [31:0] regcData,
    
    input wire regcWr_i,
    input wire [4:0] regcAddr_i,
    output wire regcWr,
    output wire [4:0] regcAddr,
    output wire [31:0] memAddr,
    output wire [31:0] memData,

//HiLo
    output reg [31:0] wHiData, //lw,sw
    output reg [31:0] wLoData,
    output wire [31:0] rHiData,
    output wire [31:0] rLoData,
    output reg whi,
    output reg wlo
    

);

    assign op_out = op_i;
    assign memAddr = regaData;
    assign memData = regbData;

    assign regcWr = regcWr_i;
    assign regcAddr = regcAddr_i;
endmodule

       ⑥MEM.v

`include "define.v"

module MEM(
    
    input wire rst,
    input wire [5:0] op,
    input wire [31:0] regcData,
    input wire [4:0] regcAddr,
    input wire regcWr,
    input wire [31:0] memAddr_i,
    input wire [31:0] memData,
    input wire [31:0] rdData,
    
    output wire [31:0] regData,
    output wire [4:0] regAddr,
    output wire regWr,
    output wire [31:0] memAddr,
    output reg [31:0] wtData,
    output reg memWr,
    output reg memCe
);

    assign regData = (op == `Lw) ? rdData : regcData;
    assign regAddr = regcAddr;
    assign regWr = regcWr;
    assign memAddr = memAddr_i;

    always@(*)
        if(rst == `RstEnable)
            begin
                wtData = `Zero;
                memWr = `RamUnWrite;
                memCe = `RamDisable;
            end
        else
            case(op)
                `Lw:
                    begin
                        wtData = `Zero;
                        memWr = `RamUnWrite;//read
                        memCe = `RamEnable;
                    end
                `Sw:
                    begin
                        wtData = memData;
                        memWr = `RamWrite;//write
                        memCe = `RamEnable;
                    end
                default:
                    begin
                        wtData = `Zero;
                        memWr = `RamUnWrite;
                        memCe = `RamDisable;
                    end
            endcase
endmodule

       ⑦DataMem.v


`include "define.v"
module DataMem(
    input wire clk,
    input wire ce,
    input wire we,
    input wire [31:0] wtData,
    input wire [31:0] memAddr,
    output reg [31:0] rdData
);
    reg [31:0] data [31:0];  
    always@(*)
        if(ce == `RamDisable)
            rdData = `Zero;
        else rdData = data[memAddr[11:2]];
    always@(posedge clk)
        if(ce == `RamEnable && we == `RamWrite)
            data[memAddr[11:2]] = wtData;
        else ;
    initial
        begin
            data [1] = 32'h0000001A; //lw
        end
endmodule

       ⑧RegFile.v


`include "define.v"

module RegFile(

    input wire clk,
    input wire rst,
    input wire we,
    input wire [4:0] wAddr,
    input wire [31:0] wData,
    input wire regaRd,
    input wire regbRd,
    input wire [4:0] regaAddr,
    input wire [4:0] regbAddr,
    output reg [31:0] regaData,
    output reg [31:0] regbData
);

    reg [31:0] reg32 [31 : 0];    
    always@(*)
        if(rst == `RstEnable)
            regaData = `Zero;
        else if(regaAddr == `Zero)
            regaData = `Zero;
        else
            regaData = reg32[regaAddr];
    always@(*)
        if(rst == `RstEnable)          
            regbData = `Zero;
        else if(regbAddr == `Zero)
            regbData = `Zero;
        else
            regbData = reg32[regbAddr];
    always@(posedge clk)
        if(rst != `RstEnable)
            if((we == `Valid) && (wAddr != `Zero))
                reg32[wAddr] = wData;
        else ;  
    initial
        begin
            reg32[4] = 32'h00000010; //sw
            reg32[9] = 32'h000000FF; //sw   
            reg32[16] = 32'h00000004; //lw
        end

   
endmodule 

       ⑨MIPS.v

`include "define.v"
module MIPS(
    input wire clk,
    input wire rst,
    input wire [31:0] instruction,
    output wire romCe,
    output wire [31:0] instAddr
);
    wire [31:0] regaData_regFile, regbData_regFile;
    wire [31:0] regaData_id, regbData_id; 
    wire [31:0] regcData_ex;
    wire [5:0] op;    
    wire regaRd, regbRd;
    wire [4:0] regaAddr, regbAddr;
    wire regcWr_id, regcWr_ex;
    wire [4:0] regcAddr_id, regcAddr_ex;
    wire [31:0] jAddr;
    wire jCe;

    wire [5:0] op_ex;
    wire [31:0] memAddr_ex,memData_ex;//lw and sw
    wire [31:0] rdData,wtData;
    wire [31:0] memAddr;
    wire [4:0] regAddr_mem;
    wire [31:0] regData_mem;
    wire memWr,memCe;
    wire regWr_mem;

    wire wlo,whi;//hilo
    wire [31:0] wLoData,wHiData;
    wire [31:0] rLoData,rHiData;

    IF if0(
        .clk(clk),
        .rst(rst),
        .jAddr(jAddr),
        .jCe(jCe),
        .romCe(romCe), 
        .pc(instAddr)
    );
    ID id0(
        .rst(rst),        
        .inst(instruction),
        .regaData_i(regaData_regFile),
        .regbData_i(regbData_regFile),
        .pc(instAddr),
        .op(op),
        .regaData(regaData_id),
        .regbData(regbData_id),
        .regaRd(regaRd),
        .regbRd(regbRd),
        .regaAddr(regaAddr),
        .regbAddr(regbAddr),
        .regcWr(regcWr_id),
        .regcAddr(regcAddr_id),
        .jAddr(jAddr),
        .jCe(jCe)
    );
    EX ex0(
        .rst(rst),
        .op_i(op),        
        .regaData(regaData_id),
        .regbData(regbData_id),
        .regcWr_i(regcWr_id),
        .regcAddr_i(regcAddr_id),
        .rHiData(rHiData),
        .rLoData(rLoData),
        .regcData(regcData_ex),//out
        .regcWr(regcWr_ex),
        .regcAddr(regcAddr_ex),
        .op_out(op_ex),//lw and sw
        .memAddr(memAddr_ex),
        .memData(memData_ex),
        .whi(whi),
        .wlo(wlo),
        .wHiData(wHiData),
        .wLoData(wLoData)
    );    
    MEM mem0(
        .rst(rst),
        .op(op_ex),
        .regcData(regcData_ex),
        .regcAddr(regcAddr_ex),
        .regcWr(regcWr_ex),
        .memAddr_i(memAddr_ex),
        .memData(memData_ex),
        .rdData(rdData),
        .regData(regData_mem),
        .regAddr(regAddr_mem),
        .regWr(regWr_mem),
        .memAddr(memAddr),
        .wtData(wtData),
        .memWr(memWr),
        .memCe(memCe)
    );
    DataMem datamem0(
        .clk(clk),
        .ce(memCe),
        .we(memWr),
        .wtData(wtData),
        .memAddr(memAddr),
        .rdData(rdData)
    );
    RegFile regfile0(
        .clk(clk),
        .rst(rst),
        .we(regWr_mem),
        .wAddr(regAddr_mem),
        .wData(regData_mem),
        .regaRd(regaRd),
        .regbRd(regbRd),
        .regaAddr(regaAddr),
        .regbAddr(regbAddr),
        .regaData(regaData_regFile),
        .regbData(regbData_regFile)
    );
endmodule

       ⑩SoC.v

module SoC(
    input wire clk,
    input wire rst
);
    wire [31:0] instAddr;
    wire [31:0] instruction;
    wire romCe;    
    MIPS mips0(
        .clk(clk),
        .rst(rst),
        .instruction(instruction),
        .instAddr(instAddr),
        .romCe(romCe)
    );    
    InstMem instrom0(
        .ce(romCe),
        .addr(instAddr),
        .data(instruction)
    );
endmodule


       11. soc_tb.v

`include "define.v"
module soc_tb;
    reg clk;
    reg rst;
    initial
      begin
        clk = 0;
        rst = `RstEnable;
        #100
        rst = `RstDisable;
        #10000 $stop;      //run to 10000,simulate stop(Zan ting)       
      end
    always #10 clk = ~ clk;
    SoC soc0(
        .clk(clk), 
        .rst(rst)
    );
endmodule


4.仿真图

       RegFile里的数据:

            reg32[4] = 32'h00000010; //sw
            reg32[9] = 32'h000000FF; //sw   
            reg32[16] = 32'h00000004; //lw

       DataMem里的数据:

            data [1] = 32'h0000001A; //lw

       我的lw指令和sw指令:
       lw:8E1F0001,其二进制为100011 10000 11111 0000 0000 0000 0001。
       sw:AC890000,其二进制为101011 00100 01001 0000000000000000。
       lw指令将数存地址为32’h00000004(reg32[16])中的数据32’h0000001A(data[1])写入到RegFile中地址为5’b11111的寄存器中(即r31寄存器)。

       sw指令将RegFile中的数据32’h000000FF(reg32[9])写到数存的data[4]中,之所以是data[4],是因为RegFile的reg32[4]中的数据是32’h00000010,即写入到数存的第16个字节中,而data是宽度为32位的寄存器,一个字节8位,data的每位都是4个字节,数存的第16个字节刚好是data的第4位,即data[4]。仿真图如下:
MIPS单周期CPU设计——lw和sw指令的设计_第2张图片
       因为读出是组合逻辑,任意时间都能看到数据,写入是时序逻辑只有时钟上升沿才能写入到寄存器,所以数存中的数据32’h0000001a在lw指令的下一周期才被写入RegFile的31号寄存器reg32[31]。和lw一样,需要在sw的下一个周期才能从RegFile读出写入的数据32’b000000FF,写入的地址就是data[4]。

你可能感兴趣的:(计算机组成原理)