1.lw,sw指令格式及功能
指令 | [31:26] | [25:21] | [20:16] | [15:0] | 意义 |
---|---|---|---|---|---|
lw | 100011 | rs | rt | offset | 从数存(数据存储器)中取数据写进寄存器 |
sw | 101011 | rs | rt | offset | 将寄存器中的值写入数存 |
2.所需模块框图及指令执行过程
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | `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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | `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 |
③ID.v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | `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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | `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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | `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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | `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 [1023: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 ; endmodule |
⑦RegFile.v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | `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 ; endmodule |
⑧MIPS.v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | `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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
4.仿真图
上面的代码RegFile和DataMem里都没有写数据,我直接用我的FPGA课程设计里的代码,那里面写了数据。
RegFile里的数据:
1 2 3 | reg32[4] = 32'h00000010; //sw reg32[9] = 32'h000000FF; //sw reg32[16] = 32'h00000004; //lw |
DataMem里的数据:
1 | 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寄存器)。仿真图如下:
因为读出是组合逻辑,任意时间都能看到数据,写入是时序逻辑只有时钟上升沿才能写入到寄存器,所以数存中的数据32’h0000001a在lw指令的下一周期才被写入RegFile的31号寄存器reg32[31]。
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]。仿真图如下:
和lw一样,需要在sw的下一个周期才能从RegFile读出写入的数据32’b000000FF,写入的地址就是data[4]。