简单单周期MIPS指令处理器设计Verilog实现

一、实验目的:
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
 

使用的Mars汇编指令如下:
在这里插入图片描述
在这里插入图片描述

  • 22
    点赞
  • 203
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
实现一个24条指令单周期MIPS处理器的课程需要经历以下步骤: 1. 确定处理器的架构:单周期MIPS处理器的基本架构包括指令存储器、数据存储器、控制器、ALU和寄存器堆。 2. 实现指令存储器:指令存储器用于存储程序的指令。可以使用Verilog或VHDL编写指令存储器的代码。 3. 实现数据存储器:数据存储器用于存储程序的数据。可以使用Verilog或VHDL编写数据存储器的代码。 4. 实现寄存器堆:寄存器堆用于存储处理器中的寄存器。可以使用Verilog或VHDL编写寄存器堆的代码。 5. 实现控制器:控制器用于控制处理器的操作,包括指令的执行流程和数据的传输。可以使用Verilog或VHDL编写控制器的代码。 6. 实现ALU:ALU用于执行算术和逻辑运算。可以使用Verilog或VHDL编写ALU的代码。 7. 编写测试程序:为了验证处理器的正确性,需要编写一些测试程序。测试程序应该覆盖处理器支持的所有指令。 8. 进行仿真:使用仿真工具对处理器进行仿真,检查是否存在任何错误。 9. 实现时钟:为了使处理器能够按照预定的时序运行,需要实现时钟。 10. 进行综合:使用综合工具将Verilog或VHDL代码转换为硬件电路。 11. 实现布局:将电路布局在芯片上。 12. 进行布线:将电路的各个部分进行布线,以确保电路能够正常工作。 13. 进行时序分析:对电路进行时序分析,以保证电路的时序满足要求。 14. 进行后仿真:对电路进行后仿真,验证电路的正确性。 15. 进行FPGA验证:将电路加载到FPGA上进行验证。 16. 进行性能优化:对电路进行性能优化,以提高处理器的性能。 17. 进行功耗优化:对电路进行功耗优化,以降低处理器的功耗。 18. 进行可靠性验证:对电路进行可靠性验证,以确保处理器的可靠性。 19. 进行集成测试:对处理器进行集成测试,以确保处理器与其他系统组件的兼容性。 20. 进行系统测试:对整个系统进行测试,以验证系统的功能和性能。 21. 进行文档编写:编写处理器的文档,包括设计文档、用户手册和测试报告等。 22. 进行培训:为用户提供培训,以使用户能够正确地使用处理器。 23. 进行技术支持:为用户提供技术支持,以解决用户在使用处理器时遇到的问题。 24. 进行维护:对处理器进行维护,以确保处理器能够长期稳定地运行。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小陈的芯片学习之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值