实验4-1 32位MIPS CPU基本部件设计
1. 实验目的
Ø 了解MIPS-C基本组成部件的工作原理;
Ø 掌握MIPS-C基本组成部件的设计方法。
2. 实验原理
CPU顶层设计是由下层基本部件例会而成的。本节将介绍图4-2中的各个基本部件的接口定义要求、功能及实现示例。
2.1 程序计数器Pc
模块接口
表4-1 PC接口信号定义
信号名 |
方向 |
描述 |
Clk |
I |
MIPS-C处理器时钟 |
Reset |
I |
复位信号 |
PCSource[2:0] |
I |
下一个PC值的来源编码 |
BrPC[31:2] |
I |
分支指令的目标地址 |
JPC[31:2] |
I |
跳转指令的目标地址 |
EPC[31:0] |
I |
EPC(当发生异常时,当前指令值存储在EPC中) |
PCWrite |
I |
PC写使能 |
PC[31:0] |
O |
PC输出 |
功能定义
PC模块的核心是一个计数器-PC(计数器名称为:PC。除非特殊需求,将不区分这两个PC)。
表4-2 PC功能需求定义
编号 |
功能名称 |
功能描述 |
1 |
初始化 |
当Reset信号有效后,PC=0xBFC00000。 |
2 |
PC更新时机 |
当时钟上升沿到来时,检测PCSource,同时更新PC。 |
3 |
确定NPC |
根据来自控制器的PCSource,决定PC取值。 1) PCSource = 001h:PC = PC + 4 2) PCSource = 010h:PC = BrPC 3) PCSource = 011h:PC = JPC 4) PCSource = 100h:PC = 0x80000180 5) PCSource = 101h:PC = 0x80000200 6) PCSource = 110h:PC = EPC |
核心代码
module PC(Clk,reset,PCSource,PC4,BrPC,JPC,EPC,PCWrite,PC_out);
input Clk,reset,PCWrite;
input[2:0] PCSource;
input[31:0] PC4;
input[31:2] BrPC,JPC;
input[31:0] EPC;
output[31:0] PC_out;
reg[31:0] PC_out;
`define EXCEPTION 32'h80000180 //define a constant
`define INT 32'h80000200
always @(posedge Clk,posedge reset)
begin
if(reset)
PC_out <= 32'hBFC00000;
else
begin
case(PCSource)
3'b001:if(PCWrite) PC_out <= PC4; //PC = PC + 4
3'b010:if(PCWrite) PC_out <= {BrPC,2'b00}; //PC Branch instruction
3'b011:if(PCWrite) PC_out <= {JPC,2'b00}; //PC Jump instruction
3'b100:if(PCWrite) PC_out <= `EXCEPTION; //Abnormal values
3'b101:if(PCWrite) PC_out <= `INT; //Abnormal return
3'b110:if(PCWrite) PC_out <= EPC; //when abnormal move PC to EPC
default: ;
endcase
end
end
endmodule
仿真结果
图4-5 程序计数器仿真结果
Clk系统时钟信号,Reset复位信号,PCSource[3:0]代表PC写入来源的输入信号,BrPC[31:2]32位的分支地址,EPC异常回复的PC写入,JPC32位跳转地址,PCIn来自ALU计算出的下一条地址,PCWritePC写入使能信号,高电平有效PC程序计数器根据PCSource[2:0]来判断PC的写入类型,仿真过程中一次仿真的是,复位、PC+4指向下一个地址、PC写入分支地址、PC写入跳转地址、异常地址。
2.2 指令寄存器IR
接口说明
表4-3指令寄存器接口信号定义
信号名 |
方向 |
描述 |
Clk |
I |
MIPS-C处理器时钟 |
Reset |
I |
复位信号 |
MemData[31:0] |
I |
来自存储器的指令 |
IRWrite |
I |
IR写使能 |
IR[31:0] |
O |
指令寄存器输出 |
功能定义
IR内部只包括一个32位寄存器—IR
表4-4 指令寄存器功能需求定义
编号 |
功能名称 |
功能描述 |
1. |
初始化 |
当Reset信号有效后,IR=0x00000000。 |
2. |
IR更新时机 |
当时钟上升沿到来时,并且IRWrite有效,则IR=MemData。 |
核心代码
module IR(Clk,Reset,MemData,IRWrite,IR);
input Clk,Reset,IRWrite;
input[31:0] MemData;
output[31:0]IR;
reg[31:0] IR;
always@(posedge Clk)
begin
if(Reset) //initialize the IR
IR = 8'h00000000;
else if(IRWrite) //When IRWrite is valid
IR = MemData; //move the data from MemData to IR
end
endmodule
仿真结果
图4-6 指令寄存器仿真结果
指令寄存器,仿真其指令写入,Clk是CPU时钟信号,IR的写入由IRWrite信号控制,在IRWrite高电平时有效,将来自于存储器的指令写入,IR[31:0]是IR寄存器的输出,即控制器的指令来源,CPU工作时,控制器的在第一个周期令IRWrite写使能有效,IR寄存器写入来自于存储器的指令。
2.3 寄存器堆Regfile
接口说明
表4-5 寄存器堆接口信号定义
信号名 |
方向 |
描述 |
Clk |
I |
MIPS-C处理器时钟 |
Reset |
I |
复位信号 |
RS1[4:0] |
I |
读寄存器文件时的第1个寄存器下标 |
RS2[4:0] |
I |
读寄存器文件时的第2个寄存器下标 |
RD[4:0] |
I |
写寄存器文件时的寄存器下标 |
RegWrite |
I |
寄存器文件写使能 |
RData1[31:0] |
O |
读寄存器文件时的第1个寄存器的输出 |
RData2[31:0] |
O |
读寄存器文件时的第2个寄存器的输出 |
WData[31:0] |
I |
寄存器文件写入数据 |
功能定义
4-6 寄存器堆功能需求定义
编号 |
功能名称 |
功能描述 |
1 |
读寄存器 |
RData1输出RS1[4:0]所寻址的寄存器; RData2输出RS2[4:0]所寻址的寄存器。 |
2 |
写寄存器 |
当当时钟上升沿到来时,并且RegWrite有效时,WData被写入RD[4:0]所寻址的寄存器 |
核心代码
module Regfile (Read1,Read2,WriteReg,WriteData,RegWrite,Data1,Data2,clock);
input [4:0] Read1,Read2,WriteReg; // the registers numbers to read or write
input [31:0] WriteData; // data to write
input RegWrite, // The write control
clock; // the clock to trigger write
output [31:0] Data1, Data2; // the register values read
reg [31:0] RF [31:0]; // 32 registers each 32 bits long
assign Data1 = RF[Read1];
assign Data2 = RF[Read2];
always begin
// write the register with new value if Regwrite is high
@(posedge clock) begin
if (RegWrite) RF[WriteReg] <= WriteReg ? WriteData : 0;
end
end
endmodule
仿真结果
图4-7 寄存器堆仿真结果
Clk是CPU时钟信号,RS1,来自指令的第[25:21]位,作为寄存器的标号,RS2来自20:16位,代表第二个寄存器标号,RD是要写入的寄存器标号,WData来自于外部的32位数据,因为读取数据是任意时候可以的,所以只仿真了写入和读出,Reset信号后,将WData的876A4321H写入RD选中的寄存器06H,将RS1置06H,将写入的数据读出。
2.4 符号扩展单元
接口说明
表4-7 符号扩展单元接口信号定义
信号名 |
方向 |
描述 |
Imm16[15:0] |
I |
来自指令寄存器的16位立即数 |
ExtImm32[31:0] |
O |
符号扩展后的32位立即数 |
功能定义
表4-8 符号扩展单元功能需求定义
编号 |
功能名称 |
功能描述 |
1 |
符号扩展 |
将16位二进制数经符号扩展后转换成32位二进制数。 1) 如果16位二进制数的最高位为0,则32位二进制的高16位全为0; 2) 如果16位二进制数的最高位为1,则32位二进制的高16位全为1。 |
核心代码
module SymbolExpasion(Imm16,ExtImm32);
input[15:0] Imm16;
output[31:0] ExtImm32;
reg[31:0] ExtImm32;
always
begin
if(Imm16[15]==0)
begin
ExtImm32[31:16] <= 16'b0;
ExtImm32[15:0] <= Imm16[15:0];
end
else if(Imm16[15]==1)
begin
ExtImm32[31:16] <= 16'b1111111111111111;
ExtImm32[15:0] <= Imm16[15:0];
end
end
endmodule
仿真结果
图4-8 符号扩展单元仿真结果
Imm16是来自指令低16位的立即数,作为符号扩展单元的输入,ExImm32是扩展后的数据首先输入一个高位为0的立即数,扩展后,高16为填零,第二次输入一个最高位为1的立即数,扩展后高16位全部为1。
2.5 算术运算器Alu
接口说明
表4-9 算术运算器接口信号定义
信号名 |
方向 |
描述 |
ALU_DA[31:0] |
I |
ALU第1个输入(ALU的上部输入) |
ALU_DB[31:0] |
I |
ALU第2个输入(ALU的下部输入) |
ALU_Func[3:0] |
I |
ALU运算功能编码 |
ALU_Zero |
O |
运算结果0标志 |
ALU_DC[31:0] |
O |
ALU运算结果 |
功能定义
表4-10 算术运算器功能需求定义
功能名称 |
功能描述 |
ALU_Func编码 |
运算功能 |
无操作 |
0000 |
ALU_DC = ALU_DB |
‘无符号加’运算 |
0001 |
ALU_DC = ALU_DA + ALU_DB |
‘有符号加’运算 |
0010 |
ALU_DC = ALU_DA + ALU_DB |
‘减’运算 |
0011 |
ALU_DC = ALU_DA - ALU_DB |
‘有符号减’运算 |
0100 |
ALU_DC = ALU_DA - ALU_DB |
‘与’运算 |
0101 |
ALU_DC = ALU_DA & ALU_DB |
‘或’运算 |
0110 |
ALU_DC = ALU_DA | ALU_DB |
‘或非’运算 |
0111 |
ALU_DC = ~(ALU_DA | ALU_DB) |
‘异或’运算 |
1000 |
ALU_DC = ALU_DA ^ ALU_DB |
‘小于置位’运算 |
1001 |
ALU_DC = (ALU_DA < ALU_DB) ? 1 : 0 |
‘有符号小于置位’运算 |
1010 |
ALU_DC = (ALU_DA < ALU_DB) ? 1 : 0 |
溢出判断:当有符号加减的时候会产生溢出,所以必须做个溢出判断。 |
核心代码
module ALU(ALU_DA,ALU_DB,ALU_Func,ALU_Zero,ALU_DC,ALU_OverFlow);
input[31:0] ALU_DA,ALU_DB;
input[3:0] ALU_Func;
output ALU_Zero,ALU_OverFlow;
output[31:0] ALU_DC;
wire ALU_Zero;
reg[31:0] ALU_DC;
wire ALU_OverFlow;
integer ALU_SymbolA;
integer ALU_SymbolB;
wire sign;
assign sign = ALU_DC[31];
assign ALU_Zero = ALU_DC==32'b0 ? 1'b1:1'b0;
always@(ALU_DA,ALU_DB)
begin
ALU_SymbolA = ALU_DA;
ALU_SymbolB = ALU_DB;
end
always
begin
case(ALU_Func)
4'b0000:ALU_DC = ALU_DB; //no operation
4'b0001:ALU_DC = ALU_DA + ALU_DB; //unsigned addition
4'b0010:ALU_DC = ALU_DA + ALU_DB; //signed addition
4'b0011:ALU_DC = ALU_DA - ALU_DB; //unsigned subtraction
4'b0100:ALU_DC = ALU_DA - ALU_DB; //signed subtraction
4'b0101:ALU_DC = ALU_DA & ALU_DB; //and operation
4'b0110:ALU_DC = (ALU_DA | ALU_DB); //or operation
4'b0111:ALU_DC = ~(ALU_DA | ALU_DB); //nor operation
4'b1000:ALU_DC = ALU_DA ^ ALU_DB; //xor operation
4'b1001:ALU_DC = (ALU_DA < ALU_DB) ? 1:0; //set less than operation
4'b1010:ALU_DC = (ALU_SymbolA < ALU_SymbolB) ? 1:0;
//set less than when the number is signed
4'b1011:ALU_DC = (ALU_SymbolA <= ALU_SymbolB) ? 1:0;
//To Imply all kinds of branches
4'b1100:ALU_DC = {ALU_DB[15:0],16'b0}; //To Imply lui
default:
ALU_DC = ALU_DB; //assume not happen
endcase
end
assign ALU_OverFlow=((ALU_Func==4'b0010)&&((ALU_DA[31]==0)&&(ALU_DB[31]==0)&&(sign==1)))||((ALU_Func==4'b0010)&&((ALU_DA[31]==1)&&(ALU_DB[31]==1)&&(sign==0)))||((ALU_Func==4'b0100)&&((ALU_DA[31]==1)&&(ALU_DB[31]==0)&&(sign==0)))||((ALU_Func == 4'b0100)&&((ALU_DA[31]==0)&&(ALU_DB[31]==1)&&(sign==1)));
endmodule
仿真结果
图4-9 算数运算器仿真结果
ALU_DA[31:0],ALU_DB[31:0]分别是第一、第二个运算数据输入,ALU_DC[31:0]运算结果OverFlow算术异常输出,ALU_Zero,运算结果为0 的标志信号,ALU_Func是ALU的操作类型控制信号输入
ALU_Func=2’b0000,ALU_DC=ALU_DB
2’b0001无符号加法FFFFFFFDH+00000100H=000000FDH
0010有符号加法,因为使用补码,所以仍是直接相加000000FDH
0011,无符号加法,FFFFFFFDH-00000100H=FFFFFEFDH
0100,有符号减法
其他类似分析。
2.6 移位单元Shifter
接口说明
表4-11 移位单元接口信号定义
信号名 |
方向 |
描述 |
SHT_DA[31:0] |
I |
被移位的数据(来自寄存器A) |
SHT_DB[4:0] |
I |
移位位数(来自寄存器B或指令寄存器[10:6]) |
SHT_Func[1:0] |
I |
移位运算功能编码 |
SHT_DC[31:0] |
O |
移位运算完成结果 |
功能定义
表4-12 移位单元功能需求定义
功能名称 |
功能描述 |
SHT_Func编码 |
运算功能 |
无操作 |
00 |
SHT_DC = 032 |
逻辑左移 |
01 |
SHT_DC = SHT_DA31-SHT_DB:0 || 0SHT_DB |
逻辑右移 |
10 |
SHT_DC = 0SHT_DB || SHT_DA31:SHT_DB |
算数右移 |
11 |
SHT_DC = (SHT_DA31)SHT_DB || SHT_DA31:SHT_DB |
核心代码
module Shifter(SHT_DA,SHT_DB,SHT_Func,SHT_DC,);
input[31:0] SHT_DA;
input[4:0] SHT_DB;
input[1:0] SHT_Func;
output[31:0] SHT_DC;
reg[31:0] SHT_DC;
always
begin
case(SHT_Func)
2'b00: SHT_DC = 0;
2'b01: SHT_DC = (SHT_DA<<SHT_DB);
2'b10: SHT_DC = (SHT_DA>>SHT_DB);
2'b11:
begin
if(SHT_DA[31])SHT_DC = ~((~SHT_DA)>>SHT_DB);
else SHT_DC = (SHT_DA>>SHT_DB);
end
endcase
end
endmodule
仿真结果
图4-10 移位单元仿真结果
SHT_DA是要被移位的数据输入
SHT_DB是要移位的位数
SHT_Func要移位的类型01左移,10右移11算术右移
2.7 乘法单元Mul
接口说明
表4-13 乘法单元接口信号定义
信号名 |
方向 |
描述 |
Clk |
I |
MIPS-C处理器时钟 |
Reset |
I |
复位信号 |
MUL_DA[31:0] |
I |
乘法单元第1个输入(来自寄存器A) |
MUL_DB[31:0] |
I |
乘法单元第2个输入(来自寄存器B) |
MUL_SelMD |
I |
乘法单元运算功能编码 |
MUL_Start |
I |
启动运算 |
MUL_SelHL |
I |
HI/LO选择 |
MUL_Write |
I |
乘法单元HI/LO寄存器写入使能 |
MUL_Flag |
O |
运算完成标志 |
MUL_DC[31:0] |
O |
乘法/除法运算结果 |
功能定义
表4-14 乘法单元功能需求定义
编号 |
功能名称 |
功能描述 |
1 |
初始化 |
当Reset信号有效后,内部控制逻辑复位,内部的HI寄存器、LO寄存器清除 操作: 控制逻辑复位 LO ß 032 HI ß 032 |
2 |
乘法运算 |
当MUL_Start为1时,表明需要启动运算。如果MUL_SELMD为0时,则执行乘法运算。运算开始前,MUL_Flag置0;运算完成后,MUL_Flag置1 操作: product ß MUL_DA × MUL_DB LO ß product31:0 HI ß product63:32 |
3 |
除法运算 |
当MUL_Start为1时,表明需要启动运算。如果MUL_SELMD为1时,则执行除法运算。运算开始前,MUL_Flag置0;运算完成后,MUL_Flag置1 操作: LO ß MUL_DA / MUL_DB HI ß MUL_DA % MUL_DB |
4 |
输出HI/LO |
MUL_DC ß (MUL_SelHL == 1) ? HI : LO |
5 |
写入HI/LO |
当MULWrite为1时,MUL_DB数据将被写入HI寄存器或LO寄存器(MULSelHL为1,选择HI寄存器;MULSelHL为0,选择LO寄存器)。 操作: if MULWrite == 1 if MULSelHL == 1 then HI ß MUL_DB else LO ß MUL_DB |
核心代码
module MUL(Clk,Reset,MUL_Start,MUL_SelHL,MUL_SelMD,MUL_Write,MUL_Flag,MUL_DB,MUL_DA,MUL_DC);
input Clk,Reset,MUL_Start,MUL_SelHL,MUL_SelMD,MUL_Write;
output MUL_Flag;
input[31:0] MUL_DB,MUL_DA;
output[31:0] MUL_DC;
reg[31:0] hi,lo;
reg working,finish,finish2;
reg[63:0] result;
`define MUL_MUL 'b0
`define MUL_DIV 'b1
`define MUL_SEL_HIGH 'b1
`define MUL_SEL_LOW 'b0
function[63:0] result_mul;
input[31:0] a,b;
begin
result_mul = a*b;
end
endfunction
function[63:0] result_div;
input[31:0] a,b;
begin
result_div[31:0]=a/b;
result_div[63:32]=a%b;
end
endfunction
assign MUL_Flag = finish;
assign MUL_DC = finish ? (MUL_SelHL == `MUL_SEL_HIGH ? hi : lo):0;
always @(posedge Clk)
begin
if(Reset)
begin working <= 0 ;finish <= 0; end
else if(MUL_Start)
begin finish <= 0;working <=1; end
else if(finish2)
begin finish <= 1;working <= 0;end
end
always @(posedge working)
begin
if(working)
if(!finish)
begin
if(MUL_SelMD == 0)
result = result_mul(MUL_DA,MUL_DB);
else
result =result_div(MUL_DA,MUL_DB);
finish2 = 1;
end
else
;
else
;
end
always @(posedge Clk)
begin
if(Reset)
begin
lo <= 0;
hi <= 0;
end
else if(MUL_Write)
begin
if (MUL_SelHL == 1)
hi <= MUL_DA;//In order to ensure mthi/mtlo can get default data from rs(reg A)
else
lo <= MUL_DA;
end
else if(finish)
begin
lo = result[31:0];
hi = result[63:32];
end
end
endmodule
仿真结果
图4-11 乘法单元仿真结果
MUL_SelMD=0,MUL_Start做乘法运算,运算结束后finish有效2*6=12
2.8 存储器Mem
接口说明
表4-15 存储器单元接口信号定义
信号名 |
方向 |
描述 |
Clk |
I |
MIPS-C处理器时钟 |
CS |
I |
使能信号 |
BE [3:0] |
I |
存储器功能模式选择信号 |
RW |
I |
读写信号 |
Addr[31:0] |
I |
输入地址信号 |
DataIn[31:0] |
I |
输入数据信号 |
Reset |
I |
复位信号 |
DataOut[31:0] |
O |
输出数据信号 |
DataReady |
O |
数据准备信号 |
功能定义
表4-16 存储器单元功能需求定义
编号 |
功能描述 |
BE编码 |
运算功能 |
1 |
1111 |
读/写addr的2到6位指示的存储器地址的32位字 |
2 |
0111 |
读/写addr的2到6位指示的存储器地址的低16位字,高16位置0 |
3 |
0011 |
读/写addr的2到6位指示的存储器地址的低8位字,高24位置0 |
4 |
default |
读出0/ 写:addr的2到6位指示的存储器地址置0 |
核心代码
module Mem(Clk,BE,CS,RW,Addr,DataIn,Reset,DataOut,DataReady);
input Clk,CS,RW,Reset;
input[3:0] BE;
input[31:2] Addr;
input[31:0] DataIn;
output[31:0] DataOut;
output DataReady;
(* ram_init_file = "Mem.mif"*)
reg[31:0] memory[31:0];
reg[31:0] DataOut;
assign DataReady = 1;
always@(posedge Clk or posedge Reset)
if(Reset)begin
memory[0] <= 1;
memory[1] <= 2;
memory[2] <= 3;
end
else if(Clk)
begin
if(RW) begin
memory[Addr[6:2]][31:16] <= (BE[3:2] == 2'b11) ? DataIn[31:16] : 16'b0;
memory[Addr[6:2]][15:8] <= (BE[1] == 1'b1) ? DataIn[15:8] : 8'b0;
memory[Addr[6:2]][7:0] <= DataIn[7:0];
end else begin
DataOut[31:16] <= (BE[3:2] == 2'b11) ? memory[Addr[6:2]][31:16] : 16'b0;
DataOut[15:8] <= (BE[1] == 1'b1) ? memory[Addr[6:2]][15:8] : 8'b0;
DataOut[7:0] <= memory[Addr[6:2]][7:0];
end
end
endmodule
仿真结果
图4-12 存储器仿真结果
如图4-12所示,在不同模式下写相同的数据12345678,写入的结果不同。
2.9 多路选择器Multiplexor
多路选择器模块实现一系列的多路选择器,包括:32位的2选1、3选1、4选1、5选1、6选1;5位的2选1、3选1。下面以32位的3选1多路选择器为例说明接口和功能定义。
接口说明
表4-17 32位3选1多路选择器接口信号定义
信号名 |
方向 |
描述 |
in0 [31:0] |
I |
MIPS-C处理器时钟 |
in1 [31:0] |
I |
使能信号 |
in2 [31:0] |
I |
存储器功能模式选择信号 |
sel [1:0] |
I |
读写信号 |
out [31:0] |
O |
输入地址信号 |
功能定义
表4-18 32位3选1多路选择器功能需求定义
编号 |
功能描述 |
sel编码 |
运算功能 |
1 |
00 |
out<= in0; |
2 |
01 |
out<= in1; |
3 |
10 |
out<= in2; |
4 |
default |
out <= in0; |
核心代码
/* 32bit 3 select 1 */
module Mux3to1_32(
in0,
in1,
in2,
sel,
out
);
input [31:0] in0;
input [31:0] in1;
input [31:0] in2;
input [1:0]sel;
output reg[31:0] out;
always@(in0, in1, in2, sel)
case(sel)
0: out<= in0;
1: out<= in1;
2: out<= in2;
default: out <= in0;
endcase
endmodule
仿真结果
图4-13 32位3选1多路选择器仿真结果
3. 实验步骤
(1) 根据4.2节中MIPS-C处理器各组成部件的模块接口与功能定义,依次通过编写verilog程序实现其接口和功能。
(2) 根据每一个MIPS-C处理器各组成部件的功能要求,设计仿真输入波形,并对仿真结构波形进行分析和验证。
(3) 根据不同的组成部件,选择实验电路,并确定部件接口的引脚锁定方案。
(4) 下载硬件到实验台,进行硬件测试。
4. 实验思考
(1)绘制每一个MIPS-C处理器组成部件的仿真波形,并对照波形分析和说明其工作过程。
(2)设计每一个MIPS-C处理器组成部件的硬件下载验证方案。