赞
踩
指令周期:CPU从内存取出一条指令并执行这条指令的时间总和。
CPU周期:又称机器周期,CPU访问一次内存所花的时间较长,因此用从内存读取一条指令字的最短时间来定义。
时钟周期:通常称为节拍脉冲或T周期。一个CPU周期包含若干个时钟周期。
指令周期>CPU周期>时钟周期。
单周期CPU:取出并执行一条指令在一个时钟周期内完成,即一条指令用一个周期。MIPS就是一个单周期CPU。
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) |
框图:
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; //ori reg32[2] = 32'h00000011; //addi reg32[4] = 32'h00000101; //andi reg32[6] = 32'h00000011; //xori 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。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。