自制cpu处理器 MIPS指令集 五级流水 带溢出 不带乘除

1.目的:

掌握RISC CPU与内存数据交换的方法,使用verilog设计一个多周期cpu,根据所给的mips指令集来实现

以数字电路为基础,设计基础组件

以组成原理为基础,各组件为原料,构造Minisys-1 CPU

能够使用vivado等软件通过verilog HDL语言实现cpu模型机的设计

五级流水线:取指,译码,执行,访存,回写

2.基本简况: 

   处理机机器字长32位,指令字长32位,定长指令,多周期

指令集:R,I,J三类

R型指令 op为0

Op6位

扫描二维码关注公众号,回复: 10279231 查看本文章

Rs 5位

Rt 5位

Rd 5位

Shamt 5位(op2)

Funct6位(op3)

 

I型指令

Op 6位

Rs 5位

Rt 5位

Immediate16位

 

J型指令

Op 6位

address26位

 

op:为操作码;

rs:为第1个源操作数寄存器,寄存器地址(编号)是00000~11111,00~1F;

rt:为第2个源操作数寄存器,或目的操作数寄存器,寄存器地址(同上);

rd:为目的操作数寄存器,寄存器地址(同上);

sa:为位移量(shift amt),移位指令用于指定移多少位;

funct:为功能码,在寄存器类型指令中(R类型)用来指定指令的功能;

immediate:为16位立即数,用作无符号的逻辑操作数、有符号的算术操作数、数据加载(Load)/数据保存(Store)指令的数据地址字节偏移量和分支指令中相对程序计数器(PC)的有符号偏移量;

address:为地址。

3.涉及到的指令

助记符

指      令       格     

示 

示例含义

操作及解释

BIT #

[31:26]

[25:21]

[20:16]

[15:11]

[10:6]

[5:0]

 

 

 

R-类型

op

rs

rt

rd

shamt

func

 

 

 

add

000000

rs

rt

rd

00000

100000

add $1,$2,$3

$1=$2+S3

(rd)←(rs)+(rt); rs=$2,rt=$3,rd=$1

addu

000000

rs

rt

rd

00000

100001

addu $1,$2,$3

$1=$2+S3

(rd)←(rs)+(rt); rs=$2,rt=$3,rd=$1,无符号数

sub

000000

rs

rt

rd

00000

100010

sub $1,$2,$3

$1=$2-S3

(rd)←(rs)-(rt); rs=$2,rt=$3,rd=$1

subu

000000

rs

rt

rd

00000

100011

subu $1,$2,$3

$1=$2-S3

(rd)←(rs)-(rt); rs=$2,rt=$3,rd=$1,无符号数

and

000000

rs

rt

rd

00000

100100

and $1,$2,$3

$1=$2&S3

(rd)←(rs)&(rt); rs=$2,rt=$3,rd=$1

or

000000

rs

rt

rd

00000

100101

or $1,$2,$3

$1=$2|S3

(rd)←(rs) | (rt); rs=$2,rt=$3,rd=$1

xor

000000

rs

rt

rd

00000

100110

xor $1,$2,$3

$1=$2^S3

(rd)←(rs)^(rt); rs=$2,rt=$3,rd=$1

sll

000000

00000

rt

rd

00000

000000

sll $1,$2,10

S1 = s2 <<10

 S1(rd)←(rt)<<shamt

nor

000000

rs

rt

rd

00000

100111

nor $1,$2,$3

$1= ~($2 | S3)

(rd)←~((rs) | (rt)); rs=$2,rt=$3,rd=$1

I-类型

op

rs

rt

immediate

 

addi

001000

rs

rt

immediate

addi $1,$2,10

$1=$2+10

(rt)←(rs)+(sign-extend)immediate,rt=$1,rs=$2

addiu

001001

rs

rt

immediate

addiu $1,$2,10

$1=$2+10

(rt)←(rs)+(sign-extend)immediate,rt=$1,rs=$2

andi

001100

rs

rt

immediate

andi $1,$2,10

$1=$2&10

(rt)←(rs)&(zero-extend)immediate,rt=$1,rs=$2

ori

001101

rs

rt

immediate

ori $1,$2,10

$1=$2|10

(rt)←(rs)|(zero-extend)immediate,rt=$1,rs=$2

xori

001110

rs

rt

immediate

xori $1,$2,10

$1=$2^10

(rt)←(rs)^(zero-extend)immediate,rt=$1,rs=$2

lui

001111

00000

rt

immediate

lui $1,10

$1=10*65536

(rt)←immediate<<16 & 0FFFF0000H,将16位立即数放到目的寄存器高16位,目的寄存器的低16位填0

lw

100011

rs

rt

offset

lw $1,10($2)

$1=Memory[

$2+10]

(rt)←Memory[(rs)+(sign_extend)offset],rt=$1,rs=$2

sw

101011

rs

rt

offset

sw $1,10($2)

Memory[

$2+10] =$1

Memory[(rs)+(sign_extend)offset]←(rt),

rt=$1,rs=$2

beq

000100

rs

rt

offset

beq $1,$2,40

if($1=$2) 
goto PC+4+40

if ((rt)=(rs)) then (PC)←(PC)+4+( (Sign-Extend) offset<<2), rs=$1, rt=$2

J-类型

op

address

 

j

000010

address

j 10000

goto 10000

(PC)←( (Zero-Extend) address<<2),

address=10000/4

jal

000011

address

jal 10000

$31=PC+4

goto 10000

($31)←(PC)+4;

(PC)←( (Zero-Extend) address<<2),address=10000/4

4程序测试结果

测试代码

5系统结构图

主要构成部分:

pc模块,pc,if_id,control,de_ex,ex,ex_mem,memory,mem_writeback,rf,im,dm,mips_c,mipstop,激励文件

由于代码太多,就不一一粘贴了,只放核心代码了

控制器:

1)基本描述

对来自去取指阶段的指令进行译码,分配读取寄存器数据,分配操作码

2)模块接口

Inst_i

In

来自中间寄存器的指令码

Pc_i

In

指令地址

Reg1_data_i  1/2

In

从通用寄存器组rf传来的数据

Aluop_o

Out

译码阶段产生的运算子类型

Alusel_op

Out

译码阶段产生的运算类型

Branch_flag_o

Out

跳转标志

Branc_target_address_o

Out

跳转地址

Inst_o

Out

指令

Link_addr_o

Out

要存储的指令地址(jal)

Reg1(2)_addr_o

Out

读取寄存器号

Reg1(2)_o

Out

操作数数据,传递给下一个中间寄存器

Reg1(2)_read_o

Out

读使能信号,传递给通用寄存器组

Wd_o

Out

写寄存器的寄存器号

Wreg_o

Out

是否写寄存器

 

3)功能定义

将指令进行译码,并从通用寄存器组读取所需要的数据,将来自上一阶段的部分数据传递到下一阶段,所有模块的核心

4)模块描述

`include "base.v"

module controlmoudle(

	input wire										rst,
	input wire[`InstAddrBus]			pc_i,
	input wire[`InstBus]          inst_i,
	input wire[`RegBus]           reg1_data_i,
	input wire[`RegBus]           reg2_data_i,

	//传�?�到RF
	output reg                    reg1_read_o,
	output reg                    reg2_read_o,     
	output reg[`RegAddrBus]       reg1_addr_o,
	output reg[`RegAddrBus]       reg2_addr_o, 	      
	
	//传�?�到下一阶段
	output reg[`AluOpBus]         aluop_o,
	output reg[`AluSelBus]        alusel_o,
	output reg[`RegBus]           reg1_o,
	output reg[`RegBus]           reg2_o,
	output reg[`RegAddrBus]       wd_o,
	output reg                    wreg_o,
	output wire[`RegBus]          inst_o,
	
	output reg                    branch_flag_o,          //分支标志
	output reg[`RegBus]           branch_target_address_o,//分支跳转目标   
	output reg[`RegBus]           link_addr_o
);

  wire[5:0] op = inst_i[31:26];				//顶级区分op
  wire[4:0] op2 = inst_i[10:6];				//次级sa
  wire[5:0] op3 = inst_i[5:0];				//低级funct
  reg[`RegBus]	imm;
  reg instvalid;
  wire[`RegBus] pc_plus_4;
  wire[`RegBus] imm_sll_2_signedext;  


  assign pc_plus_4 = pc_i +4;	      //下一条指令
  assign imm_sll_2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 };   //立即数符号位扩展,左移2位
  assign inst_o = inst_i;
    
	always @ (*) begin	
		if (rst == `RstEnable) begin
			aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;
			wd_o <= `NOPRegAddr;
			wreg_o <= `WriteDisable;
			 
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= `NOPRegAddr;
			reg2_addr_o <= `NOPRegAddr;
			imm <= 32'h0;	
			link_addr_o <= `ZeroWord;
			branch_target_address_o <= `ZeroWord;
			branch_flag_o <= `NotBranch;					
	  end else begin
			aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;
			wd_o <= inst_i[15:11];
			wreg_o <= `WriteDisable;
			instvalid <= `InstInvalid;	   
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= inst_i[25:21];
			reg2_addr_o <= inst_i[20:16];		
			imm <= `ZeroWord;
			link_addr_o <= `ZeroWord;
			branch_target_address_o <= `ZeroWord;
			branch_flag_o <= `NotBranch;			
		  case (op)
		    6'b000000:		begin
		    	case (op2)
		    		5'b00000:			begin
		    			case (op3)
		    				`EXE_OR:	begin
		    					wreg_o <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
		  						alusel_o <= `EXE_RES_LOGIC; 	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
		  						 	
								end  
		    				`EXE_AND:	begin
		    					wreg_o <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
		  						alusel_o <= `EXE_RES_LOGIC;	  reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
		  						 	
								end  	
		    				`EXE_XOR:	begin
		    					wreg_o <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
		  						alusel_o <= `EXE_RES_LOGIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
		  						 	
								end  				
		    				`EXE_NOR:	begin
		    					wreg_o <= `WriteEnable;		aluop_o <= `EXE_NOR_OP;
		  						alusel_o <= `EXE_RES_LOGIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
		  						 	
								end 
								
											
								`EXE_ADD: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_ADD_OP;
		  						alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
		  						 	
								end
								`EXE_ADDU: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_ADDU_OP;
		  						alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
								end
								`EXE_SUB: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_SUB_OP;
		  						alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
							end
								`EXE_SUBU: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_SUBU_OP; sel_o <= `EXE_RES_ARITHMETIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
								end
						    default:	begin
						    end
						  endcase
						 end
						default: begin
						end
					endcase	
					end									  
		  	`EXE_ORI:			begin                        //ORIָ
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
		  		alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};		wd_o <= inst_i[20:16];	 	
		  	end
		  	`EXE_ANDI:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
		  		alusel_o <= `EXE_RES_LOGIC;	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};		wd_o <= inst_i[20:16];		
				end	 	
		  	`EXE_XORI:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
		  		alusel_o <= `EXE_RES_LOGIC;	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};		wd_o <= inst_i[20:16];		  	
					 	
				end	 		
		  	`EXE_LUI:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
		  		alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {inst_i[15:0], 16'h0};		wd_o <= inst_i[20:16];		  				end						
				`EXE_ADDI:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_ADDI_OP;
		  		alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {{16{inst_i[15]}}, inst_i[15:0]};		wd_o <= inst_i[20:16];		  		end
				`EXE_J:			begin
		  		wreg_o <= `WriteDisable;		aluop_o <= `EXE_J_OP;
		  		alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b0;
		  		link_addr_o <= `ZeroWord;
			    branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
			    branch_flag_o <= `Branch;	
				end
				`EXE_JAL:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_JAL_OP;
		  		alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b0;
		  		wd_o <= 5'b11111;	
		  		link_addr_o <= pc_plus_4 + 4 ;
			    branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
			    branch_flag_o <= `Branch;	 
				end
				`EXE_BEQ:			begin
		  		wreg_o <= `WriteDisable;		aluop_o <= `EXE_BEQ_OP;
		  		alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
		  		 	
		  		if(reg1_o == reg2_o) begin
			    	branch_target_address_o <= pc_plus_4 + imm_sll_2_signedext+4;
			    	branch_flag_o <= `Branch;	  	
			    	end
				end
				
				`EXE_LW:			begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_LW_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	 
					wd_o <= inst_i[20:16];  	
				end
				`EXE_SW:			begin
		  		wreg_o <= `WriteDisable;		aluop_o <= `EXE_SW_OP;
		  		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;  	
		  		alusel_o <= `EXE_RES_LOAD_STORE; 
				end														  	
		    default:			begin
		    end
		  endcase		  //case op
		  if ((inst_i[31:21] == 11'b00000000000) && inst_i[5:0] == 6'b000000)begin
		  	if (op3 == `EXE_SLL) begin
		  		wreg_o <= `WriteEnable;		aluop_o <= `EXE_SLL_OP;
		  		alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b1;
					imm[4:0] <= inst_i[10:6];		wd_o <= inst_i[15:11]; 	
				end
			end		  
		  
		end       //if
	end         //always
	
// 1
	always @ (*) begin	
	  if(rst == `RstEnable) begin
			reg1_o <= `ZeroWord;										
	  end else if(reg1_read_o == 1'b1) begin
	  	reg1_o <= reg1_data_i;
	  end else if(reg1_read_o == 1'b0) begin
	  	reg1_o <= imm;
	  end else begin
	    reg1_o <= `ZeroWord;
	  end
	end
	//2
	always @ (*) begin
	  if(rst == `RstEnable) begin
			reg2_o <= `ZeroWord;			
	  end else if(reg2_read_o == 1'b1) begin
	  	reg2_o <= reg2_data_i;
	  end else if(reg2_read_o == 1'b0) begin
	  	reg2_o <= imm;
	  end else begin
	    reg2_o <= `ZeroWord;
	  end
	end
endmodule

顶层文件

 mipstop模块

1)基本描述

2)模块接口

Clk

In

时钟信号

Rst

In

复位信号

 

3)功能定义

初始化dm,mips_c,im模块,传递激励信号

4)模块描述

`include "base.v"



module mipstop(



       input       wire                                                                clk,

       input wire                                                                      rst

);



  wire[`InstAddrBus] inst_addr;

  wire[`InstBus] inst;

  wire rom_ce;

  wire[`RegBus] mem_addr_i;

  wire[`RegBus] mem_data_i;

  wire[`RegBus] mem_data_o;

  wire mem_ce_i; 



 mips_C mipsc(

              .clk(clk),

              .rst(rst),

              .rom_addr_o(inst_addr),

              .rom_data_i(inst),

              .rom_ce_o(rom_ce),

              .ram_addr_o(mem_addr_i),

              .ram_data_o(mem_data_i),

              .ram_data_i(mem_data_o),

              .ram_ce_o(mem_ce_i)         

       );

      

       IM U_IM(

              .ce(rom_ce),

              .addr(inst_addr),

              .inst(inst)

       );



       DM U_DM(

              .clk(clk),

              .addr(mem_addr_i),

              .data_i(mem_data_i),

              .data_o(mem_data_o),

              .ce(mem_ce_i)      

       );



endmodule

搭建的环境:vivado 2017

发布了6 篇原创文章 · 获赞 9 · 访问量 7007

猜你喜欢

转载自blog.csdn.net/xiu_2460918833/article/details/89376962