实验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处理器组成部件的硬件下载验证方案。