指令 | [31:26] | [25:21] | [20:16] | [15:0] | 意义 |
---|---|---|---|---|---|
lw | 100011 | rs | rt | offset | 从数存(数据存储器)中取数据写进寄存器 |
sw | 101011 | rs | rt | offset | 将寄存器中的值写入数存 |
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指令执行完毕。
①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
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]。仿真图如下:
因为读出是组合逻辑,任意时间都能看到数据,写入是时序逻辑只有时钟上升沿才能写入到寄存器,所以数存中的数据32’h0000001a在lw指令的下一周期才被写入RegFile的31号寄存器reg32[31]。和lw一样,需要在sw的下一个周期才能从RegFile读出写入的数据32’b000000FF,写入的地址就是data[4]。