一、一些概念
1.单周期CPU
指令周期:CPU从内存取出一条指令并执行这条指令的时间总和。
CPU周期:又称机器周期,CPU访问一次内存所花的时间较长,因此用从内存读取一条指令字的最短时间来定义。
时钟周期:通常称为节拍脉冲或T周期。一个CPU周期包含若干个时钟周期。
指令周期>CPU周期>时钟周期。
单周期CPU:取出并执行一条指令在一个时钟周期内完成,即一条指令用一个周期。MIPS就是一个单周期CPU。
2.MIPS指令格式和通用寄存器定义
MIPS所有的指令均为32位,MIPS指令的三种格式如下(op是指令码):
R类型指令的op为0,具体操作由func指定。rs和rt是源寄存器号,rd是目的寄存器号。只有移位指令使用sa来指定移位位数。I型指令的低16位是立即数,计算时要把它扩展到32位。依指令的不同,有零扩展和符号扩展两种。零扩展是把32位的高16位置成0;符号位扩展是把高16位的每一位置成与立即数最高为相同的值,即保持立即数的正负符号不变。J型指令的指令格式最简单,右边的26位是字地址,用于产生跳转的目的地址。
MIPS指令中的寄存器号(rs、rt和rd)有5位,因此它能访问2^5=32个寄存器。下表列出了这32个寄存器的名称和用途。
寄存器名 | 寄存器号 | 用途 |
---|
zero | $0 | 常数0 |
at | $1 | 汇编器专用 |
v0~v1 | $2~$3 | 表达式计算或者函数调用的返回结果 |
a0~a3 | $4~$7 | 函数调用参数1~3 |
t0~t7 | $8~$15 | 临时变量,函数调用时不需要保存和恢复 |
s0~s7 | $16~$23 | 函数调用时需要保存和恢复的寄存器变量 |
t8~t9 | $24~$25 | 临时变量,函数调用时不需要保存和恢复 |
k0~k1 | $26~$27 | 操作系统专用 |
gp | $28 | 全局变量指针(Global Poiner) |
sp | $29 | 堆栈指针(Stack Pointer) |
fp | $30 | 帧指针(Frame Pointer) |
ra | $31 | 返回地址(Return Address) |
二、MIPS CPU
框图:
IF是取指模块(Instruction Fetch),ID是译码模块,InstMen是指存(指令存储器)模块,是一个Rom芯片,RagFile是寄存器堆,EX模块是执行指令,包括写指令(用来做运算,可以认为是ALU)。
I型指令的执行过程:
IF的pc将指令的地址送入InstMem(指存)中,读取相应指令,pc每过一个clk就会自加4(这个过程在IF里完成),指向下一个指令。取出的指令送到ID ,ID将源寄存器的地址给regaAddress,将目的寄存器的地址给regcAddress(在I型指令中是这样,其他指令里就不一定了),将ID中的regaAddress和regaRd(读信号)送给RegFile,然后读取数据RegFile中的regaData,将RegFile的regaData送给ID的regaData_i,regaData_i会作为ID的regData送给EX。指令中的立即数也是可以在ID中直接获得的,当regaRd无效时,就会将立即数的值进行扩展,然后送给regaData。
而运算的功能是EX模块来做的,所以ID读取数据完成后,将数据regaData,和目的寄存器地址送给EX,op是操作码,用来决定将进行何种操作,也送给EX。EX获得数据和操作码后就进行运算,运算后的结果存到regcData中,运算的结果也是要写进RegFile中的,所以EX将regcData,regcAddr(要写入的地址)和regcWr(写信号)送给RegFile,将数据写入寄存器堆保存起来,到这里这条I型指令就执行完了。
红色的线是IF要做的事,蓝色的是ID要做的事,绿色的是EX要做的事。
三、代码设计
IF、ID、EX和RegFile都是子模块,我们需要写一个MIPS模块调用这几个子模块,InstMem是一个单独的模块,是在MIPS外面,MIPS和InstMem相结合就组成了一个更高一级的模块,称作Soc,我们可以写一个Soc模块调用MIPS和InstMem。
I型指令很多,这里只举ori、addi、andi和xori指令的实现,每个模块可以参照模块图进行理解。
①define.v
`define RstEnable 1'b1
`define RstDisable 1'b0
`define RomEnable 1'b1
`define RomDisable 1'b0
`define RamWrEnable 1'b1
`define RamWrDisable 1'b0
`define Zero 32'b0
`define Valid 1'b1
`define Invalid 1'b0
`define Inst_addi 6'b001000
`define Inst_andi 6'b001100
`define Inst_ori 6'b001101
`define Inst_xori 6'b001110
`define Inst_lui 6'b001111
`define Or 6'b000001
`define Add 6'b000010
`define And 6'b000100
`define Xor 6'b000101
`define Nop 6'b000000
`define Or 6'b000001
②IF.v
`include "define.v"
module IF(
input wire clk,
input wire rst,
output reg romCe,
output reg [31:0] pc
);
always@(*)
if(rst == `RstEnable)
romCe = `RomDisable;
else
romCe = `RomEnable;
always@(posedge clk)
if(romCe == `RomDisable)
pc = `Zero;
else
pc = pc + 4;
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,
output reg [5:0] op,
output reg [4:0] regaAddr,
output reg [4:0] regbAddr,
output reg [4:0] regcAddr,
output reg [31:0] regaData,
output reg [31:0] regbData,
output reg regaRd,
output reg regbRd,
output reg regcWr
);
wire [5:0] inst_op = inst[31:26];
reg [31:0] imm;
always@(*)
if(rst == `RstEnable)
begin
op = `Nop;
regaRd = `Invalid;
regbRd = `Invalid;
regcWr = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
else
case(inst_op)
`Inst_ori:
begin
op = `Or;
regaRd = `Valid;
regbRd = `Invalid;
regcWr = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_addi:
begin
op = `Add;
regaRd = `Valid;
regbRd = `Invalid;
regcWr = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'b0,inst[15:0]};
end
`Inst_andi:
begin
op = `And;
regaRd = `Valid;
regbRd = `Invalid;
regcWr = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'b0,inst[15:0]};
end
`Inst_xori:
begin
op = `Xor;
regaRd = `Valid;
regbRd = `Invalid;
regcWr = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'b0,inst[15:0]};
end
default:
begin
op = `Nop;
regaRd = `Invalid;
regbRd = `Invalid;
regcWr = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
endcase
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
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 wire rst,
input wire [5:0] op,
input wire [31:0] regaData,
input wire [31:0] regbData,
input wire regcWr_i,
input wire [4:0]regcAddr_i,
output reg [31:0] regcData,
output wire regcWr,
output wire [4:0] regcAddr
);
always@(*)
if(rst == `RstEnable)
regcData = `Zero;
else
begin
case(op)
`Or:
regcData = regaData | regbData;
`Add:
regcData = regaData + regbData;
`And:
regcData = regaData & regbData;
`Xor:
regcData = regaData ^ regbData;
default:
regcData = `Zero;
endcase
end
assign regcWr = regcWr_i;
assign regcAddr = regcAddr_i;
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'h34011100;//ori:32'h00000000 or 32'h00001100 =32'h00001100
instmem [1] = 32'h20430000;//addi:32'h00000011 add 32'h00000000 = 32'h00000011
instmem [2] = 32'h30850001;//andi:32'h00000001 and 32'h00000101 = 32'h00000001
instmem [3] = 32'h38C70001;//xori:32'h00000001 xori 32'h00000011 = 32'h00000010
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@(*)
if(we == `RamWrEnable)
reg32[waddr] = wdata;
else
reg32[waddr] = `Zero;
initial
begin
reg32[0] = 32'h00000001;
reg32[2] = 32'h00000011;
reg32[4] = 32'h00000101;
reg32[6] = 32'h00000011;
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;
IF if0(
.clk(clk),
.rst(rst),
.romCe(romCe),
.pc(instAddr)
);
ID id0(
.rst(rst),
.inst(instruction),
.regaData_i(regaData_regFile),
.regbData_i(regbData_regFile),
.op(op),
.regaData(regaData_id),
.regbData(regbData_id),
.regaRd(regaRd),
.regbRd(regbRd),
.regaAddr(regaAddr),
.regbAddr(regbAddr),
.regcWr(regcWr_id),
.regcAddr(regcAddr_id)
);
EX ex0(
.rst(rst),
.op(op),
.regaData(regaData_id),
.regbData(regbData_id),
.regcWr_i(regcWr_id),
.regcAddr_i(regcAddr_id),
.regcData(regcData_ex),
.regcWr(regcWr_ex),
.regcAddr(regcAddr_ex)
);
RegFile regfile0(
.clk(clk),
.rst(rst),
.we(regcWr_ex),
.waddr(regcAddr_ex),
.wdata(regcData_ex),
.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
⑨soc_tb.v
`include "define.v"
module soc_tb;
reg clk;
reg rst;
initial
begin
clk = 0;
rst = `RstEnable;
#100
rst = `RstDisable;
#10000 $stop;
end
always #10 clk = ~ clk;
SoC soc0(
.clk(clk),
.rst(rst)
);
endmodule
仿真波形图:
由左到右指令1、2、3、4依次是ori指令、addi指令、andi指令、xori指令的测试数据以及结果。因为没有加MEM模块,所以在EX中计算好的值,直接通过RegcData、RegcAddr和RegcWr三条线送入到RegFile里的we、waddr和w的data。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)