一、实验目的
-
理解MIPS处理器指令格式及功能。
-
掌握ori指令格式与功能。
-
掌握ModelSim和ISE\Vivado工具软件。
-
掌握基本的测试代码编写和FPGA开发板使用方法。
二、实验环境
-
装有ModelSim和ISE\Vivado的计算机。
-
Sword\Basys3\EGo1实验系统。
三、实验原理
MIPS是一款作为上世纪80年代的推出处理器,在美国与我国许多著名高校都作为教学研究的处理器。本次实验以32位MIPS为例,通过设计基本的MIPS指令集,从而掌握现代处理器的设计原理与方法。
MIPS处理器的指令格式分为R型、I型和J型。R型为寄存器型,即两个源操作数和目的操作数都是寄存器性。I型为操作数含有立即数。而J型特指转移类型指令,如图1所示。
如图2所示,本次实验及其后续实验挑选部分MIPS处理器指令进行实现。以ori指令为例说明,其中rs为源操作数寄存器,imm为立即数型源操作数,由于是逻辑运算,所以imm按无符号数(零)扩展为32位数,运算结果存入rt目的操作数寄存器。
如图3所示为按照单指令周期设计MIPS处理器内部结构。所有控制信号及字段均标注出来。另外,每条指令周期都包含2个clk,即PC模块用1个clk,Regfile和DataMem模块用1个clk,也可以说是由2个时钟构成的指令流水线。
为了便于今后的扩展,将MIPS处理器在图3的基础上进行了分阶段设计,这样结构更清晰,也有利于流水线的设计。随着后续指令的不断添加,处理器内部结构设计也会进行相应的调整。
用Verilog HDL设计32位MIPS处理器ORI指令实现,参照图4的MIPS内部结构示意图,将设计的MIPS处理器改造为分阶段实现方案,注意每条指令周期平均只包含1个时钟周期。先编写基本实现代码,即能实现ORI指令的取指令和执行指令。
`include "define.v"
module IF(
input wire clk,
input wire rst,
output reg ce,
output reg [31:0] pc
);
always@(*)
if(rst == `RstEnable)
ce = `RomDisable;
else
ce = `RomEnable;
always@(posedge clk)
if(ce == `RomDisable)
pc = `Zero;
else
pc = pc + 4;
endmodule
`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 regaRead,
output reg regbRead,
output reg regcWrite
);
wire [5:0] inst_op = inst[31:26];
reg [31:0] imm;
always@(*)
if(rst == `RstEnable)
begin
op = `Nop;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
else
case(inst_op)
`Inst_ori:
begin
op = `Or;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_addi:
begin
op = `Add;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {{16{inst[15]}}, inst[15:0]};
end
`Inst_andi:
begin
op = `And;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_xori:
begin
op = `Xor;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_subi:
begin
op = `Sub;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {{16{inst[15]}}, inst[15:0]};
end
`Inst_lui:
begin
op = `Lui;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {inst[15:0],16'h0};
end
/*`Inst_lui:
begin
op = `Lui;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {inst[15:0],16'h0};
end
*/
default:
begin
op = `Nop;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
endcase
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
always@(*)
if(rst == `RstEnable)
regbData = `Zero;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
endmodule
`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 regcWrite_i,
input wire [4:0]regcAddr_i,
output reg [31:0] regcData,
output wire regcWrite,
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;
`Lui:
regcData = regaData;
/*`Lui:
regcData = regaData | regbData;
*/
`Sub:
regcData = regaData - regbData;
default:
regcData = `Zero;
endcase
end
assign regcWrite = regcWrite_i;
assign regcAddr = regcAddr_i;
endmodule
`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 regaRead,
input wire regbRead,
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
`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 regaRead, regbRead;
wire [4:0] regaAddr, regbAddr;
wire regcWrite_id, regcWrite_ex;
wire [4:0] regcAddr_id, regcAddr_ex;
IF if0(
.clk(clk),
.rst(rst),
.ce(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),
.regaRead(regaRead),
.regbRead(regbRead),
.regaAddr(regaAddr),
.regbAddr(regbAddr),
.regcWrite(regcWrite_id),
.regcAddr(regcAddr_id)
);
EX ex0(
.rst(rst),
.op(op),
.regaData(regaData_id),
.regbData(regbData_id),
.regcWrite_i(regcWrite_id),
.regcAddr_i(regcAddr_id),
.regcData(regcData_ex),
.regcWrite(regcWrite_ex),
.regcAddr(regcAddr_ex)
);
RegFile regfile0(
.clk(clk),
.rst(rst),
.we(regcWrite_ex),
.waddr(regcAddr_ex),
.wdata(regcData_ex),
.regaRead(regaRead),
.regbRead(regbRead),
.regaAddr(regaAddr),
.regbAddr(regbAddr),
.regaData(regaData_regFile),
.regbData(regbData_regFile)
);
endmodule
`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 r1,r0,1100h r1--32'h0000 1100
instmem [1] = 32'h34020020; //ori r2,r0,0020h r2--32'h0000 0020
instmem [2] = 32'h3403ff00; //ori r3,r0,ff00h r3--32'h0000 ff00
instmem [3] = 32'h3404ffff; //ori r4,r0,ffffh r4--32'h0000 ffff
instmem [4] = 32'h3005ffff; //andi r5,r0,ffff r5--32'h0000 0000
instmem [5] = 32'h3806ffff; //xori r6,r0,ffff r6--32'h0000 ffff
instmem [6] = 32'h2007ffff; //addi r7,r0,ffff r7--32'hffff ffff
instmem [7] = 32'h3c081234; //lui r8,1234 r8--32'h1234 0000
instmem [8] = 32'h35095679; //ori r9,r8,5678 r9--32'h1234 5679
instmem [9] = 32'h212aa011; //addi r10,r9,a011 r10--32'h1233 f68a
instmem [10] = 32'h306b1111; //andi r11,r3,1111 r10--32'h0000 1100
instmem [11] = 32'h254C1111; //subi r12,r10,1111 r12--32'h1234 e579
end
endmodule
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
`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
在完成基本实验的基础上,如图4所示,将ANDI, XOI, ADDI,SUBI和LUI等指令添加进去,然后进行设计实现和验证结果。