一、实验目的:
1、利用Verilog语言完成单周期MIPS指令处理器的设计,
2、锻炼复杂电路的设计能力。
二、实验要求
完成单周期MIPS指令处理器设计,并下载到FPGA开发板上,开发板的LED灯显示ALU的计算结果,处理器的时钟由开发板上的按键产生,每按一次键,产生一个时钟脉冲。
单周期MIPS指令处理器能在一个时钟周期内完成add、sub、and、or、sw、lw、beq、j等一条MIPS指令的处理。
单周期MIPS指令处理器包括以下几部分电路:指令存储器、数据存储器、寄存器堆、算术逻辑运算单元、控制电路。
指令存储器:保存处理器的指令,起始地址为0x00400000;
数据存储器:保存处理器的数据,起始地址为0x10010000;
寄存器堆:32个32bit寄存器;
算术逻辑运算单元:完成各种运算;
控制电路:产生处理器的控制信号,包括PC生成。
三、实验内容
1、熟悉MIPS指令处理器的指令编码与电路结构,理解MIPS指令处理器工作过程,画出单周期MIPS指令处理器电路结构图。
2、熟悉软件Mars的使用方法,用add、sub、and、or、sw、lw、beq、j等指令编写一段有意义的程序,并在Mars上进行编译得到程序的机器码;
3、完成MIPS指令处理器的VerilogHDL代码,其中指令存储器、数据存储器的初值为实验内容第2点得到的指令与数据;
4、编写testbench,在ModelSim上对VerilogHDL代码进行仿真测试;
5、用QuartusⅡ对VerilogHDL代码进行综合,并下载到FPGA开发板上进行验证。
四、实验思路
由《计算机组成与设计:硬件、软件接口》可以得到单周期MIPS指令处理器的总体电路图:
由电路图可以知道电路总体可以分为以下几个部分:①程序计数器PC;②指令存储器;③程序计数加法器PC+4;④控制单元;⑤左移部件;⑥寄存器堆;⑦符号扩展单元;⑧ALU控制器;⑨ALU运算器;⑩加法器;⑪数据存储器;⑫数据选择器;⑬相应的门电路。下面分别给出每个组成部分的作用以及生成该部件的VerilogHDL代码。
1、程序计数器PC:指令地址存储器,存放当前正在执行的指令地址或下一条指令地址。由实验要求指令存储器的初始地址为0x00400000;所以上电时,程序计数器PC的指令自动跳转变为0x00400000,即找到存储器中的第一条指令。在实际开发中,由异步复位信号来决定指令处理器是否正常工作。
module PC(CLK,Address_in,Address_out,rst);
input CLK,rst;
input [31:0] Address_in;
output reg [31:0] Address_out;
always@(posedge CLK,negedge rst)
begin
if(!rst) Address_out<=32'h0040_0000;
else Address_out<=Address_in;
end
endmodule
2、指令存储器:该部件实际由ROM组成,根据给定的地址,读出地址对应的数据,即存储的指令。ROM中存储的数据需要进行初始化。因为PC的值总是+4,且要将ROM中的存储器全部都利用起来,所以所以地址的最低位应该为PC值的倒数第3位。
module Order_Mem(Address_in,Order);
input [31:0] Address_in;
output [31:0] Order;
reg [31:0] Rom [31:0] /*synthesis ram_init_file="MIPS.mif" */;
assign Order = Rom[Address_in[6:2]];
endmodule
其中的初始化mif文件为:
3、程序计数加法器PC+4:该部件的作用为自动使PC的值+4,找到下一条需要正常执行的地址。
module Add_PC(adr,n_adr);
input [31:0] adr;
output [31:0] n_adr;
assign n_adr = adr + 32'd4;
endmodule
4、控制单元:该部件为整个MIPS指令器的“大脑”,根据其给出的控制信号来执行相应的指令功能。控制单元的输入为指令的操作码部分(指令 [31:26]),则根据信号,产生的控制信号如下表所示:
module Control_Unit(op,RegDst,jump,Branch,MemRead,MemtoReg,ALUop,MemWrite,ALUSrc,RegWrite);
input [5:0] op;
output reg RegDst,jump,Branch,MemtoReg,ALUSrc,RegWrite,MemWrite,MemRead;
output reg [1:0] ALUop;
always @ *
begin
case(op)
//R型指令
6'd0:begin
RegDst <= 1; jump <= 0; ALUop <= 2'b10;
Branch <= 0; MemtoReg <= 0; RegWrite <= 1;
MemWrite <= 0; MemRead <= 0; ALUSrc <= 0;end
//I型lw存指令
6'd35:begin
RegDst <= 0; jump <= 0; ALUop <= 2'b00;
Branch <= 0; MemtoReg <= 1; RegWrite <= 1;
MemWrite <= 0; MemRead <= 1; ALUSrc <= 1;end
//I型sw取指令
6'd43:begin
RegDst <= 0; jump <= 0; ALUop <= 2'b00;
Branch <= 0; MemtoReg <= 0; RegWrite <= 0;
MemWrite <= 1; MemRead <= 0; ALUSrc <= 1;end
//I型beq指令分支反指令
6'd4:begin
RegDst <= 0; jump <= 0; ALUop <= 2'b01;
Branch <= 1; MemtoReg <= 0; RegWrite <= 0;
MemWrite <= 0; MemRead <= 0; ALUSrc <= 0;end
//J型指令
6'd2:begin
RegDst <= 0; jump <= 1; ALUop <= 0;
Branch <= 0; MemtoReg <= 0; RegWrite <= 0;
MemWrite <= 0; MemRead <= 0; ALUSrc <= 0;end
default:begin
RegDst <= 0; jump <= 0; ALUop <= 0;
Branch <= 0; MemtoReg <= 0; RegWrite <= 0;
MemWrite <= 0; MemRead <= 0; ALUSrc <= 0;end
endcase
end
endmodule
5、左移部件:电路中存在两个左移部件,其中一个部件的作用为将指令的高26位左移两位,低两位补0;另一个部件的作用为将整个指令左移两位,低两位补0;
module Left2(data,odata);
input [31:0] data;
output reg [31:0] odata;
always @(data)
begin
odata[31:2]<=data[29:0];
odata[1:0]<=2'b00;
end
endmodule
module Left2_26(data,data1,odata);
input [25:0] data;
input [3:0] data1;
output reg [31:0] odata;
always @(data,data1)
begin
odata[27:2]<=data[25:0];
odata[1:0]<=2'b00;
odata[31:28]<=data1[3:0];
end
endmodule
6、寄存器堆:该部件的作用是生成32个寄存器,上电即初始化为0(除第18个寄存器被初始化为数据存储器的初始地址外)
module Registers(Read_registers1,Read_registers2,Write_registers,Write_Data,Read_Data1,Read_Data2,RegWire,CLK);//寄存器堆
input [4:0] Read_registers1,Read_registers2,Write_registers;
input [31:0] Write_Data;
input RegWire,CLK;
output [31:0] Read_Data1,Read_Data2;
reg [31:0] register[31:0] /*synthesis ram_init_file="Mif2.mif" */;
assign Read_Data1 = register[Read_registers1];
assign Read_Data2 = register[Read_registers2];
//写信号上升沿到来
always @(posedge CLK)
begin
//当RegWire信号有效时,进行写操作
if(RegWire) register[Write_registers] <= Write_Data;
end
endmodule
其中Mif2.mif文件内容如下:
其中的第18个寄存器是用10进制表示,将其转化为16进制为0x10010000,即数据存储器的初始地址。
7、符号扩展单元:该部件的作用是将指令的后16位扩展成为32位,
module sign_ep(order,addr);
input [15:0] order;
output reg [31:0] addr;
always @(order)
begin
if(order[15]==1) addr[31:16]=16'b1111111111111111;
else addr[31:16]=16'b0000000000000000;
addr[15:0]=order[15:0];
end
endmodule
8、ALU控制器:该部件的功能为根据控制单元发出的信号ALUop和指令后五位代表的功能码共同作用于ALU控制器,来产生相应的信号控制ALU进行的运算操作。
module ALU_Control(ALUop,FunctionCode,ALUctr);
input [1:0] ALUop; //一个占两位的控制字段
input [5:0] FunctionCode; //一个6位功能码
output reg [3:0] ALUctr; //输出为一个4位的ALU控制信号
always @(ALUop,FunctionCode)
begin
case(ALUop)
2'b00: ALUctr <= 4'b0010; //取、存字,加
2'b01: ALUctr <= 4'b0110; //相等分支,减
//R型
2'b10:
begin
case(FunctionCode)
6'b100000: ALUctr <= 4'b0010; //加
6'b100010: ALUctr <= 4'b0110; //减
6'b100100: ALUctr <= 4'b0000; //与
6'b100101: ALUctr <= 4'b0001; //或
default: ALUctr <= 4'b1111;
endcase
end
default: ALUctr <= 4'b1111;
endcase
end
endmodule
9、ALU运算器:该部件的功能为根据ALU控制器给出的信号进行相应的运算。
module ALU(ctr,A,B,Zero,result);//ALU为组合逻辑电路
input [3:0] ctr;
input [31:0] A,B;
output Zero;
output reg [31:0] result;
always @ (A,B,ctr)
begin
case(ctr)
4'd0: result <= A&B;
4'd1: result <= A|B;
4'd2: result <= A+B;
4'd6: result <= A-B;
4'd7: result <= A<B ? 1:0;
4'd12:result <= ~(A|B);
default: result <= 0;
endcase
end
assign Zero = (result==0);
endmodule
10、加法器:该部件的作用为计算跳转指令的地址;
module ALU_Add_32(addr1,addr2,out_addr);
input [31:0] addr1,addr2;
output [31:0] out_addr;
assign out_addr = addr1+addr2;
endmodule
11、数据存储器:该部件的作用为存储运算的数据或地址;
module Data_Mem(input wire[31:0] Address_in,
input wire[31:0] in_data,
output wire[31:0] data,
input wire CLK,MemWrite,MemRead);
reg [31:0] mem [31:0] /*synthesis ram_init_file="m_ros.mif" */;
always @(posedge CLK)
begin
if(MemWrite) mem[Address_in[6:2]]<=in_data;
end
assign data = mem[Address_in[6:2]];
endmodule
初始化的m_ros.mif文件如下:
其中的第1个存储器是用10进制表示,将其转化为16进制为0x10010000,即数据存储器的初始地址。
12、数据选择器:
module Mux_32(A,B,Src,S);
input [31:0] A,B;
input Src;
output [31:0] S;
assign S = (Src==0) ? A:B;
endmodule
module Mux_6(A,B,Src,S);
input [5:0] A,B;
input Src;
output [5:0] S;
assign S = (Src==0) ? A:B;
endmodule
顶层电路描述如下:
module MIPS(CLK,rst,out_ALU,clk1,data1,data2,data3,data4,Read_Data1,Read_Data2,Address_in_PC,Address_out_PC,Address_Add_PC,Order,Read_Data_Mem,Order_Left);
input clk1;
output CLK;
input rst;
output [6:0] data1,data2,data3,data4;
output [31:0]out_ALU;
assign CLK = ~clk1;
output [31:0] Read_Data1,Read_Data2,Address_in_PC,Address_out_PC,Address_Add_PC,Order,Read_Data_Mem,Order_Left;
wire [31:0] Read_Data1;
wire [31:0] Read_Data2;
wire [31:0] Address_in_PC,Address_out_PC;//用于PC的输入和输出
wire [31:0] Address_Add_PC;//用于程序计数器正常指令进行加4的输出
wire [31:0] Order;//用于指令存储器的指令输出
wire RegDst,Jump,Branch,MemtoReg,ALUSrc,RegWrite,MemWrite,MemRead;//用于对控制信号的连线
wire [1:0] ALUop;//控制信号ALUop的连线
wire [5:0] Write_register;//寄存器堆中写入寄存器所在的位号的连线
wire [31:0] Write_Data;//Read_Data1,Read_Data2;//寄存器堆中的连线
wire [31:0] sign,out_sign,ALU1,out_ALU;
wire [31:0] ALU_Add_32_out,Branch_or_normal;
wire [3:0] ALU_ctr;
wire [31:0] Read_Data_Mem;
wire [31:0] Order_Left;
wire zero,Mux32_EN;
PC(CLK,Address_in_PC,Address_out_PC,rst);
Add_PC(Address_out_PC,Address_Add_PC);
Order_Mem(Address_out_PC,Order);
Control_Unit(Order[31:26],RegDst,Jump,Branch,MemRead,MemtoReg,ALUop,MemWrite,ALUSrc,RegWrite);
Mux_6(Order[20:16],Order[15:11],RegDst,Write_register);
Registers(Order[25:21],Order[20:16],Write_register,Write_Data,Read_Data1,Read_Data2,RegWrite,CLK);
sign_ep(Order[15:0],sign);
Mux_32(Read_Data2,sign,ALUSrc,ALU1);
ALU_Control(ALUop,Order[5:0],ALU_ctr);
ALU(ALU_ctr,Read_Data1,ALU1,zero,out_ALU);
Data_Mem(out_ALU,Read_Data2,Read_Data_Mem,CLK,MemWrite,MemRead);
Mux_32(out_ALU,Read_Data_Mem,MemtoReg,Write_Data);
Left2(sign,out_sign);
ALU_Add_32(Address_Add_PC,out_sign,ALU_Add_32_out);
and(Mux32_EN,Branch,zero);
Mux_32(Address_Add_PC,ALU_Add_32_out,Mux32_EN,Branch_or_normal);
Left2_26(Order[25:0],Address_Add_PC[31:28],Order_Left);
Mux_32(Branch_or_normal,Order_Left,Jump,Address_in_PC);
dec4_7(out_ALU[15:12],data1);
dec4_7(out_ALU[11:8],data2);
dec4_7(out_ALU[7:4],data3);
dec4_7(out_ALU[3:0],data4);
endmodule