设计并实现一个单周期非流水的CPU(哈工大计组实验二:给定指令系统的处理器设计)

本文详细介绍了如何使用Xilinx ISE和ModelSim进行实验,通过VERILOG实现一个基本CPU的指令处理器,包括指令格式设计、处理器结构、模块功能描述、设计及测试,涵盖了寄存器组、数据存储、CPU控制器等关键组件。

一、实验目的

1.掌握Xilinx ISE集成开发环境和ModelSim仿真工具的使用方法
2.掌握VERILOG语言
3.掌握FPGA编程方法及硬件调试手段
4.深刻理解处理器结构和计算机系统的整体工作原理

二、实验环境(实验设备、开发环境)

  1. Windows10
  2. ISE14.7
  3. NEXYS3开发板

三、设计思想

1.指令格式设计

1
2
3

2.处理器结构设计框图及功能描述

1

上图是一个简单的基本上能够在单周期CPU上完成所要求设计的指令功能的数据通路和必要的控制线路图。其中指令和数据各存储在不同存储器中,即有指令存储器和数据存储器。访问存储器时,先给出内存地址,然后指令存储器以组合逻辑的方式来实现,而数据存储器以时序逻辑的方式来实现,在写时需要将对应的使能信号置为有效状态。对于寄存器组,先给出寄存器地址,读操作时不需要时钟信号,输出端就直接输出相应数据;而在写操作时,在 写使能信号为1时,在时钟边沿触发将数据写入寄存器。CU是整个CPU的控制器,随着节拍的改变而调整各个使能信号、MUX的选择输入端。

3.各功能模块结构的功能描述

PC,用于存放下一条要执行的指令的地址。
IMEM,指令存储器,用于存放所有要执行的指令。
IR,用于存放正要执行的指令。
NPC,用于暂存pc+4的值。
ADD,用于执行加法运算。
PC_select,用于在pc+4和跳转指令中地址进行选择。
Registers,寄存器组文件,这里实现了32个32位的通用寄存器。
Data_holder,用来暂存数据,A、B、IMM都是这个模块的实例化。
Extender,进行位扩展,如果是无条件跳转J指令,则将后26位符号扩展为32位,否则将后16位符号扩展为32位。
MUX,数据选择器。
ALU,算数运算单元,执行和指令相关的一些计算。
ALU_output,暂存ALU的结果。
DMEM,数据存储器。
LMD,用于暂存DMEM的数据。
CU,CPU的控制器,随着时钟节拍的改变而相应的变化控制信号。

4.各模块输入输出接口信号定义

模块名称及功能:PC,用于存放下一条要执行的指令的地址。
1

模块名称及功能:IMEM,指令存储器,用于存放所有要执行的指令。

2

模块名称及功能:IR,用于存放正要执行的指令。

3

模块名称及功能:NPC,用于暂存pc+4的值。

4

模块名称及功能:ADD,用于执行加法运算。
5

模块名称及功能:PC_select,用于在pc+4和跳转指令中地址进行选择。

6

模块名称及功能:Registers,寄存器组文件,这里实现了32个32位的通用寄存器。
7

模块名称及功能:Data_holder,用来暂存数据,A、B、IMM都是这个模块的实例化。

8

模块名称及功能:Extender,进行位扩展,如果是无条件跳转J指令,则将后26位符号扩展为32位,否则将后16位符号扩展为32位。

9

模块名称及功能:MUX,数据选择器。

10

模块名称及功能:ALU,算数运算单元,执行和指令相关的一些计算。

11

模块名称及功能:ALU_output,暂存ALU的结果。

11

模块名称及功能:DMEM,数据存储器。

12

模块名称及功能:LMD,用于暂存DMEM的数据。

13

模块名称及功能:CU,CPU的控制器,随着时钟节拍的改变而相应的变化控制信号。

14

四、实验设计及测试

用Verilog语言实现处理器设计与实现
① 各模块的详细设计
(1)PC:

module PC(
    input [31:0] new_address,  // 下一个地址
    input        clk,
    input		  reset,
    input 		  pc_enable,	// 是否可以更改PC
	 
    output reg [31:0] output_address	// 当前PC内容
);
	always@(posedge clk) begin
		if(reset == 1'b1) 
			output_address <= 0 - 4;
		else 
			output_address <= (pc_enable == 1)? new_address : output_address;
	end

endmodule

(2)ADD:

module ADD(
    input	[31:0] 	data1,
	 input	[31:0]	data2,
	 
    output	[31:0] 	result
);

	assign result = data1 + data2;
	
endmodule

(3)PC_select:

module PC_select(
    input  [31:0] JMP_address,	// 执行跳转类指令时PC值
    input  [31:0] PC_address,		// 向下执行时的PC值
    input         pc_select,		// 是否跳转
	 
    output [31:0] next_address
);
	 
	assign next_address = (pc_select == 1)? JMP_address : PC_address;


endmodule

(4)NPC:

module NPC(
    input	[31:0]	input_address,	// 下一个PC值
    input				clk,				
	 input				reset,
	 input				npc_enable,		// 是否可以更改NPC
	 
	 output reg [31:0] output_address	// NPC当前的值
);

	always@(negedge clk) begin
		if(reset == 1'b1) begin
			output_address <= 0;
		end
		else begin
			output_address <= (npc_enable==1)? input_address : output_address;
		end
	end


endmodule

(5)IMEM:

`include "./cpu.vh"
module IMEM(
    input [31:0] address,	// 指令的地址
	 
    output [31:0] output_instruction	// 指令
);

	reg [31:0] data [255:0];	// 32*256大小的指令存储缓冲器
	
	initial begin
		$readmemh(`INST_FILE_PATH, data);  // 读取文件内容并进行初始化
	end
	
	assign output_instruction = data[address / 4];

endmodule

(6)IR:

module IR(
    input [31:0] input_instruction,	// IR要修改为的值,即取出的指令
    input        ir_enable,			// IR是否可以被修改
    input        clk,
	 input        reset,
	 
    output reg [31:0] output_instruction	// 指令
);

	always@(negedge clk) begin
		if (reset == 1) begin
			output_instruction <= 32'h00000000;
		end
		else begin
			output_instruction <= (ir_enable == 1)? input_instruction : output_instruction;
		end
		
	end


endmodule

(7)Registers:

`include "./cpu.vh"

module Registers(
    input  [4:0] RS_1,	// 指令中的寄存器部分
    input  [4:0] RS_2,	// 指令中的寄存器部分
	 input  [4:0] writeback_address,	// 要写的寄存器的地址
	 input  [31:0] writeback_data,	// 要写入的内容
    input         clk,
    input         write_enable,	// 是否可以写
    input         reset,
	 
    output  [31:0] output_data_1,		// 读到的值
    output  [31:0] output_data_2		// 读到的值
);

	reg [31:0] memory [31:0];	// 32个32位寄存器
	
	assign output_data_1 = memory[RS_1];
	assign output_data_2 = memory[RS_2];
	
	
	//  使用本地文件初始化寄存器组
	initial begin
		$readmemb(`GPRS_FILE_PATH , memory);
	end
	
	always@(posedge clk) begin
		if(reset == 1) begin
			//output_data_1 = 32'h00000000;
			//output_data_2 = 32'h00000000;
		end
		else begin
			if(write_enable == 1) begin
				memory[writeback_address
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值