基于Verilog的简易CPU设计

前言

本篇文章将简单讲解CPU之间各部分的功能及接线,并提供Verilog模拟CPU的各个组成部分。该CPU可以完成一些操作,如:加减法,与或,指令跳转等,最后提供testbench用于测试该CPU的工作情况是否符合预期。

CPU简单讲解

CPU及相关硬件的作用:


Random Access Memory(RAM):随机存储寄存器,即内存,包含所有CPU要处理的数据RAM包含一系列的地址,每个地址对应的都是一个二进制数据。CPU一般将会按顺序从RAM中读取数据,但实际上是可以以任意顺序访问RAM。当计算机运行时,它向RAM发送一个地址以获得那个程序。通常,RAM不会有任何操作,除非CPU与RAM连线的读使能为高电平。如果读使能为高电平,电路导通,RAM将返回这个地址的数据给CPU。从此CPU开始处理数据,处理完成后,它会向RAM发送一个地址,并将读使能置高,接着获取下一个数据。如果CPU需要向RAM写入数据,它将输出一个值和一个地址,并将写使能置高,将数据写入RAM对应的地址上。RAM的地址上存储的二进制数可能表示一条指令,一个数字,一个字符,一个地址等等。


Instruction Set(IS):指令集,即CPU可以完成指令种类的集合,比如两个数相加,移动某个数去某个新地址等等。


Control Unit(CU):控制单元,队长,它从RAM中接收指令,通过解析这个指令,变成其他元件可以理解的命令,即向其他元件输出控制信号。


Arithmetic Logic Unit(ALU):算术逻辑单元,是受控制单元控制的一个元件,ALU执行所有的数学运算,例如之前提到的加法指令中的加法。ALU有两个输入口,inputA和inputB。ALU的工作过程如下:CU从RAM收到了指令,告诉ALU该做什么运算,ALU执行运算并输出结果。除此之外,ALU将会对CU输出一个状态标志信号,表明当前状态和下一个时钟需要做的事。当CU与寄存器的写使能为高电平的时候,ALU输出的结果将会被暂时性的存储到寄存器上。那么如何将寄存器上的数据读出?CU实际上也会有个与寄存器的读使能信号连线,当它为高电平时,寄存器输出该数据。寄存器的输出线路会连在CPU总线上,总线是一组连在计算机里多个元件之间的线路。总线上会有更多独立的寄存器(Group Registers),它们同样通过读使能和写使能与CU相连。它们用于存储刚刚那个寄存器放在总线上的数据。这些组寄存器用于在多个操作间存储数字。


Temporary Register:临时寄存器,由于总线上同一时间一般只能有一个数据,而ALU有两个输入端口,这就意味着我们需要先存好一个数据来自于组寄存器中的数据),再与总线上的数据(来自于组寄存器中的数据)进行运算。存放数据提供给ALU的寄存器就叫临时寄存器。需要注意的是,临时寄存器不需要和CU有读写使能的连线,因为它并不会与总线上的其他寄存器产生冲突。


Instruction Register(IR):指令寄存器,用于存放CU从RAM中读到的指令,它也不需要和CU有读写使能的连线,因为它并不会与总线上的其他寄存器产生冲突。它只会将指令输出给CU,基于这个指令,CU会告诉ALU执行什么运算。


Instruction Address Register:指令地址寄存器,在我的Verilog程序里也叫Program Counter(PC),CPU需要它去了解下一个指令在RAM中的何处,在没有"跳转"指令发生的前提下,下一条指令所在的地址通常是当前指令的所在地址+1,但如果发生了跳转,则新地址应为上一条指令在RAM中的地址+offset,offset随不同的跳转指令而各不相同(是一个变化的值)。因为CU并不需要读取PC中的数据,仅需要写入一条指令所在的地址,因此它们之间只需要有写使能连线,而不需要读使能连线。RAM收到PC传递给它的地址后,将会将这个地址上的数据传给IR,再由IR传给CU。

相关图示

Verilog代码

alu_mux.v

复制代码
module alu_mux (
	clk, 
	rst, 
	en_in,
	offset, 
	rd_q,
	rs_q,
	alu_in_sel,
	alu_a,
	alu_b,
	en_out
);

input [15:0] rd_q, rs_q ;
input clk, rst, en_in, alu_in_sel ;
input [7:0] offset ;
output reg [15:0] alu_a, alu_b ;
output reg en_out ;

	always @ (negedge rst or posedge clk) begin
		if (rst == 1'b0) begin
			alu_a <= 16'b0000_0000_0000_0000 ;
			alu_b <= 16'b0000_0000_0000_0000 ;
			en_out  <= 1'b0;
		end		
		else 
			if (en_in == 1'b1) begin
				alu_a <= rd_q;
				en_out  <= 1'b1;
				if (alu_in_sel == 1'b0) 
					alu_b <= {{8{offset[7]}}, offset[7:0]} ; 
				else 
					alu_b <= rs_q;					
			end
			else en_out <= 1'b0;
    end
endmodule

/* 
	alu_mux: 
	用于给alu输入数据,若alu_in_sel==0,则说明只需要一个操作数
	若alu_in_sel==1,则需要两个操作数
	当en_in是能有效时,输出使能有效
*/

alu.v

复制代码
`timescale 1ns / 1ps

`define B15to0H     3'b000
`define AandBH      3'b011
`define AorBH       3'b100
`define AaddBH      3'b001
`define AsubBH      3'b010
`define leftshift   3'b101
`define rightshift  3'b110

module alu (
	clk, 
	rst, 
	en_in, 
	alu_a, 
	alu_b, 
	alu_func, 
	en_out, 
	alu_out
);

input  [15:0] alu_a, alu_b ;
input  clk, rst, en_in ;
input  [2:0] alu_func ;
output reg [15:0] alu_out ;
output reg en_out ;

	always @ (negedge rst or posedge clk) begin
		if (rst == 1'b0) begin
			alu_out <= 16'b0000_0000_0000_0000 ;
			en_out  <= 1'b0 ;
		end				
		else begin
			if (en_in == 1'b1) begin
				en_out <= 1'b1;
				case (alu_func)
					B15to0H: alu_out <= alu_b ; 
					AandBH: alu_out <= a & b ; 
					AorBH: alu_out <= a | b ; 
					AaddBH: alu_out <= a + b ; 
					AsubBH: alu_out <= a - b ; 
					leftshift: alu_out <= (alu_out << 1) ; 
					rightshift: alu_out <= (alu_out >> 1) ;
					default: alu_out <= alu_out ; 
				endcase
			end
			else en_out <= 1'b0;
		end
    end
endmodule

/*
	根据输入alu_func的值,确定如何将两个操作数alu_a和alu_b运算得到alu_out
*/

control_unit.v

复制代码
module control_unit (
	clk,
	rst,
	en,
	en_alu,
	en_ram_out,
	ins,
	offset_addr,
	en_ram_in,	
	en_group_pulse,
	en_pc_pulse,
	reg_en,
	alu_in_sel,
	alu_func,
	pc_ctrl  		
);

/*
	en: Control_Unit的使能信号
	en_alu: alu的输出使能信号,即用于告诉control unit此时alu有输出
	en_ram_out: RAM的输出使能信号,即用于告诉control unit此时RAM有输出
	ins: 当前的指令
*/
input clk, rst, en, en_alu, en_ram_out ;	
input [15:0] ins ;

/*
	en_ram_in: RAM输入使能,告诉RAM此时有数据输入
	en_group_pulse: 与datapath同步时钟信号?
	en_pc_pulse: 连datapath的en_pc_pulse
	alu_in_sel: 连datapath的alu_in_sel
	offset_addr: 连datapath的offset_addr
	reg_en: 连datapath的reg_en
	alu_func: 连datapath的alu_func
	pc_ctrl: 连datapath的pc_ctrl
*/
output en_ram_in, en_group_pulse, en_pc_pulse, alu_in_sel ;	
output reg [7:0] offset_addr ;
output [3:0] reg_en ;
output [2:0] alu_func ;
output [1:0] pc_ctrl ;

wire [15:0] ir_out ;
wire en_out ;

	ir ir1(
		.clk(clk),
		.rst(rst),
		.ins(ins),
		.en_in(en_ram_out),
		.en_out(en_out),
		.ir_out(ir_out)
	);
		
	
	state_transition state_transition1(
		.clk(clk),
		.rst(rst),
		.en_in(en),
		.en1(en_out),
		.en2(en_alu),
		.rd(ir_out[11:10]),
		.opcode(ir_out[15:12]),
		.en_fetch_pulse(en_ram_in),	
		.en_group_pulse(en_group_pulse),
		.en_pc_pulse(en_pc_pulse),
		.pc_ctrl(pc_ctrl),
		.reg_en(reg_en),
		.alu_in_sel(alu_in_sel),
		.alu_func(alu_func)			
	);
					
	always @ (en_out or ir_out) begin
		offset_addr = ir_out[7:0] ;
	end

endmodule

cpu.v

复制代码
module cpu(
	clk,
	rst,
	en_in,
	en_ram_out,
	addr,
	ins,
	en_ram_in 	
);

input         clk, rst ,en_in, en_ram_out ;
input  [15:0] ins ;
output [15:0] addr ;
output        en_ram_in ;

wire         en_pc_pulse, en_group_pulse, alu_in_sel, en_alu ;
wire  [1:0]  pc_ctrl ;
wire  [3:0]  reg_en ;
wire  [2:0]  alu_func ;
wire  [7:0]  offset_addr ;

data_path data_path1(
	.clk(clk),
	.rst(rst),
	.offset(ins[7:0]),
	.offset_addr(offset_addr),
	.en_pc_pulse(en_pc_pulse),
	.pc_ctrl(pc_ctrl),
	.en_in(en_group_pulse),
	.reg_en(reg_en),
	.rd(ins[11:10]),
	.rs(ins[9:8]),
	.alu_in_sel(alu_in_sel),
	.alu_func(alu_func),
	.en_out(en_alu),
	.pc_out(addr)
);	                     

control_unit control_unit1(
	.clk(clk),
	.rst(rst),
	.en(en_in),
	.en_alu(en_alu),  
	.en_ram_out(en_ram_out),
	.ins(ins),
	.offset_addr(offset_addr),
	.en_ram_in(en_ram_in),
	.en_group_pulse(en_group_pulse),
	.en_pc_pulse(en_pc_pulse),
	.reg_en(reg_en),
	.alu_in_sel(alu_in_sel),
	.alu_func (alu_func),
	.pc_ctrl(pc_ctrl)			
);	
endmodule				

data_path.v

复制代码
module data_path (
	clk, 
	rst,
	offset_addr,	
	en_pc_pulse,
	pc_ctrl, 
	offset, 
	en_in,
	reg_en,	
	alu_in_sel,
	alu_func, 
	en_out,	
	pc_out,
	rd,
	rs		
);

input clk, rst, en_pc_pulse, en_in, alu_in_sel ;
input [7:0] offset_addr, offset ;
input [1:0] pc_ctrl, rd, rs ;
input [3:0] reg_en ;
input [2:0] alu_func ;
output en_out ;
output [15:0] pc_out ;

wire [15:0] rd_q, rs_q, alu_a, alu_b, alu_out ;	
wire en_out_group, en_out_alu_mux ;  

pc pc1(
    clk(clk),
    rst(rst),       
	en_in(en_pc_pulse),
	pc_ctrl(pc_ctrl),
	offset_addr(offset_addr), 		 			 
	pc_out(pc_out)	
);

reg_group reg_group1(
	.clk(clk),
	.rst(rst),
	.en_in(en_in),
	.reg_en(reg_en),
	.d_in(alu_out),
	.rd(rd),
	.rs(rs),
	.rd_q(rd_q),
	.en_out(en_out_group),
	.rs_q(rs_q)		
);
			
alu_mux alu_mux1(                                        
	.clk(clk),
	.rst(rst),
	.en_in(en_out_group),
	.rd_q(rd_q),
	.rs_q(rs_q),
	.offset(offset),
	.alu_in_sel(alu_in_sel),
	.alu_a(alu_a),
	.en_out(en_out_alu_mux),					
	.alu_b(alu_b)  		
);

alu alu1(
	.clk(clk),
	.rst(rst),
	.en_in(en_out_alu_mux),					
	.alu_a(alu_a),
	.alu_b(alu_b),
	.alu_func(alu_func),
	.en_out(en_out),
	.alu_out(alu_out ) 
);							
endmodule				
				
/*
	datapath包含alu,alu_mux等模块
*/

ir.v

复制代码
module ir(
	clk,
	rst,
	ins,
	en_in,
	en_out,
	ir_out
);

input clk, rst ;
input [15:0] ins ;
input en_in ;
output reg en_out ;
output reg [15:0] ir_out ;

always @ (posedge clk or negedge rst) begin
	if (!rst) begin
		ir_out <= 16'b000000000000 ;
		en_out <= 1'b1 ;
	end
	else begin
		if (en_in) begin
			en_out <= 1'b1 ;
			ir_out <= ins ;
		end
		else en_out <= 1'b0 ;
	end
end
endmodule

/* 
	IR: Instruction Register, 用于存放当前即将执行的指令
	在使能有效时,将指令输出给state_transition完成状态转移
*/

pc.v

复制代码
`timescale 1ns / 1ps

module pc(
   clk,
   rst,       
   en_in,
   pc_ctrl, // 控制指令寄存器的下一曲值
   offset_addr, 		 			 
   pc_out  		
);

input clk, rst, en_in ;
input wire [1:0] pc_ctrl ;
input wire [7:0] offset_addr ;
output reg [15:0] pc_out ;
   
   always @ (posedge clk or negedge rst) begin
      if (rst == 0) pc_out <= 0 ;
      else begin
         if (en_in == 1) begin
            case (pc_ctrl) 
               2'b00: pc_out <= pc_out ; 
               2'b01: pc_out <= pc_out + 1 ;
               2'b10: pc_out <= {8'b00000000, offset_addr[7:0]} ; // jump去指定的地址
               2'b11: pc_out <= pc_out + offset_addr ; 
               default: pc_out <= pc_out ;
            endcase
         end
      end
   end   
endmodule

/*
   pc: program counter
*/

reg_group.v

复制代码
`timescale 1ns / 1ps

module reg_group(
    clk,       
    rst,	
	en_in,		
	reg_en,		
	d_in,		
	rd,
    rs,		
	en_out,		
	rd_q,
	rs_q	
);
input clk, rst, en_in ; // 时钟信号,复位信号,操作四个寄存器的使能信号
input wire [3:0] reg_en ; // 用于实例化寄存器的使能信号
input wire [15:0] d_in ; // 输入数据
input wire [1:0] rd, rs ; // 用于选择如何分配寄存器的值给两个输出信号,两个输出信号均有4种取值(共有四个寄存器,每个信号读取其中一个寄存器中的值)共16种
output reg en_out ; // 输出使能
output reg [15:0] rd_q, rs_q ; // 输出信号 目标寄存器和源寄存器

wire [15:0] q0, q1, q2, q3 ; // 每个寄存器的输出

    register reg0(
            .clk(clk),
            .rst(rst),
            .en(reg_en[0]),                
            .d(d_in),                
            .q(q0)      
            );

    register reg1(
            .clk(clk),
            .rst(rst),
            .en(reg_en[1]),                
            .d(d_in),                
            .q(q1)      
            );

    register reg2(
            .clk(clk),
            .rst(rst),
            .en(reg_en[2]),                
            .d (d_in),                
            .q (q2)      
            );

    register reg3(
            .clk(clk),
            .rst(rst),
            .en(reg_en[3]),                
            .d(d_in),                
            .q(q3)      
            );      
            
    always @ (posedge clk or negedge rst)
        if (rst == 0) begin
                rd_q <= 0 ; 
                rs_q <= 0 ;    
                en_out <= 0; 
        end
        else begin
            if (en_in == 1) begin
                en_out <= 1 ;   
                case ({rd[1:0], rs[1:0]})
                    4'b0000: begin
                        rd_q <= q0 ;
                        rs_q <= q0 ;
                    end
                    4'b0001: begin
                        rd_q <= q0 ;
                        rs_q <= q1 ;
                    end   
                    4'b0010: begin 
                        rd_q <= q0 ; 
                        rs_q <= q2 ; 
                    end
                    4'b0011: begin      
                        rd_q <= q0;                                                           
                        rs_q <= q3;
                    end        
                    4'b0100: begin      
                        rd_q <= q1;
                        rs_q <= q0;
                    end        
                    4'b0101: begin      
                        rd_q <= q1;
                        rs_q <= q1;
                    end           
                    4'b0110: begin      
                        rd_q <= q1;
                        rs_q <= q2;
                    end   
                    4'b0111: begin      
                        rd_q <= q1;
                        rs_q <= q3;
                    end                   
                    4'b1000: begin      
                        rd_q <= q2 ;
                        rs_q <= q0 ;
                    end     
                    4'b1001: begin            
                        rd_q <= q2 ;     
                        rs_q <= q1 ;         
                    end       
                    4'b1010: begin       
                        rd_q <= q2 ;
                        rs_q <= q2 ;
                    end                 
                    4'b1011: begin       
                        rd_q <= q2 ;
                        rs_q <= q3 ;
                    end  
                    4'b1100: begin       
                        rd_q <= q3 ;
                        rs_q <= q0 ;
                    end               
                    4'b1101: begin         
                        rd_q <= q3 ;    
                        rs_q <= q1 ;          
                    end       
                    4'b1110: begin       
                        rd_q <= q3 ;
                        rs_q <= q2 ;
                    end         
                    4'b1111: begin       
                        rd_q <= q3 ;
                        rs_q <= q3 ;
                    end         
                    default: begin
                        rd_q <= 0 ;
                        rs_q <= 0 ;
                    end
                endcase
            end
            else en_out <= 0 ;
        end
endmodule               
                        
/* 
    在每个时钟上升沿,确定如何将哪些寄存器中的值赋给rd_q和rs_q,rd_q和rs_q将用于给alu_a和alu_b赋值
*/

register.v

复制代码
`timescale 1ns / 1ps

module register(
	clk,
	rst,
	en,				
	d,				
	q				
);

input clk, rst, en ;
input wire [15:0] d ;
output reg [15:0] q ;

    always @ (posedge clk or negedge rst) begin
      if (rst == 0) q <= 0 ;
      else 
        if (en == 1) q <= d ; 
        else q <= q ; 
      end
endmodule

/*
  寄存器模块,在时钟上升沿且Control Unit给出的控制信号en为高时,更新寄存器,否则锁存数据
*/

state_transistion.v

复制代码
module state_transition(
	clk,
	rst,
	en_in,
	en1,
	en2,
	rd,
	opcode,
	en_fetch_pulse,
	en_group_pulse,
	en_pc_pulse,
	pc_ctrl,
	reg_en,
	alu_in_sel,
	alu_func
);

input clk, rst ;
input en_in ; // 表示此时有指令需要处理,从空闲状态转为取指状态
input en1 ; // 接收指令寄存器的使能,只有有指令来临时,才会进行状态转移
input en2 ; // 接收alu的输出
input [1:0] rd ; // destination register 目的寄存器
input [3:0] opcode ; // 指令中的操作码,不同的操作码对应不同的next_state

/*
	en_ram_in: RAM输入使能,告诉RAM此时有数据输入
	en_group_pulse: 与datapath同步时钟信号?
	en_pc_pulse: 连datapath的en_pc_pulse
	alu_in_sel: 连datapath的alu_in_sel
	reg_en: 连datapath的reg_en
	alu_func: 连datapath的alu_func
	pc_ctrl: 连datapath的pc_ctrl
*/
output reg en_fetch_pulse ;
output reg en_group_pulse ;
output reg en_pc_pulse ;
output reg [1:0] pc_ctrl;
output reg [3:0] reg_en ;
output reg alu_in_sel ;
output reg [2:0] alu_func ;

reg en_fetch_reg, en_fetch ;
reg en_group_reg, en_group ; // group reg的写控制信号和读控制信号
reg en_pc_reg, en_pc ;
reg [3:0] current_state, next_state ; 

parameter Initial = 4'b0000 ;
parameter Fetch = 4'b0001 ;
parameter Decode = 4'b0010 ;
parameter Execute_Moveb = 4'b0011 ;
parameter Execute_Add = 4'b0100 ;
parameter Execute_Sub = 4'b0101 ;
parameter Execute_And = 4'b0110 ;
parameter Execute_Or = 4'b0111 ;
parameter Execute_Jump = 4'b1000 ;
parameter Write_back = 4'b1001 ;

always @ (posedge clk or negedge rst) begin // 有限状态机的现态与次态的转移
	if (!rst)
		current_state <= Initial ;
	else 
		current_state <= next_state ;
end

always @ (current_state or en_in or en1 or en2 or opcode) begin
	case (current_state)
		Initial: begin
			if (en_in)
				next_state = Fetch ;
			else
				next_state = Initial ;
		end
		Fetch: begin
			if (en1) 
				next_state = Decode ;
			else
				next_state = current_state ;
		end
		Decode: begin
			case (opcode) 
				4'b0000: next_state = Execute_Moveb ;
				4'b0010: next_state = Execute_Add ;
				4'b0101: next_state = Execute_Sub ;
				4'b0111: next_state = Execute_And ;
				4'b1001: next_state = Execute_Or ;
				4'b1010: next_state = Execute_Jump ;
				default: next_state = current_state ;
			endcase
		end
		Execute_Moveb: begin
			if (en2) // 如果此时alu确实有数输出,证明这个状态完成了
				next_state = Write_back ;
			else
				next_state = current_state ;
		end
		Execute_Add: begin
			if(en2) // 如果此时alu确实有数输出,证明这个状态完成了
				next_state = Write_back ;
			else
				next_state = current_state ;
		end
		Execute_Sub: begin
			if(en2) // 如果此时alu确实有数输出,证明这个状态完成了
				next_state = Write_back ;
			else
				next_state = current_state ;
		end
		Execute_And: begin
            if(en2) // 如果此时alu确实有数输出,证明这个状态完成了
				next_state = Write_back ;
			else
				next_state = current_state ;
		end   
		Execute_Or: begin
			if(en2) // 如果此时alu确实有数输出,证明这个状态完成了
                next_state = Write_back ;
            else
                next_state = current_state ;
        end  
		Execute_Jump: next_state = Fetch ;
		Write_back: next_state = Fetch ;
		default: next_state = current_state ;
	endcase
end

// 用于输出控制信号
always @ (rst or next_state) begin
	if (!rst) begin
		en_fetch = 1'b0 ;
		en_group = 1'b0 ;
		en_pc = 1'b0 ;
		pc_ctrl = 2'b00 ;
		reg_en = 4'b0000 ;
		alu_in_sel = 1'b0 ;
		alu_func = 3'b000 ;
	end
	else begin
		case (next_state)
			Initial: begin
				en_fetch = 1'b0 ;
				en_group = 1'b0 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b000 ;
			end
			Fetch: begin
				en_fetch = 1'b1 ;  // 此时需要取指
				en_group = 1'b0 ;
				en_pc = 1'b1 ;
				pc_ctrl = 2'b01 ; // 取下一个指令
				reg_en = 4'b0000 ; 
				alu_in_sel = 1'b0 ;
				alu_func = 3'b000 ;
			end
			Decode: begin
				en_fetch = 1'b0 ;
				en_group = 1'b0 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b000 ;
			end
			Execute_Moveb: begin
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b000 ;
			end
			Execute_Add: begin
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b001 ;
			end
			Execute_Sub: begin
				// please add your code here
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b001 ;
			end
			Execute_And: begin
				// please add your code here
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b001 ;
			end
			Execute_Or: begin
				// please add your code here
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b001 ;
			end
			Execute_Jump: begin
				// please add your code here
				en_fetch = 1'b0 ;
				en_group = 1'b1 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b001 ;
			end
			Write_back: begin
				case (rd)
					2'b00: reg_en = 4'b0001 ;
					2'b01: reg_en = 4'b0010 ;
					2'b10: reg_en = 4'b0100 ;
					2'b11: reg_en = 4'b1000 ;
					default: reg_en = 4'b0000 ;
				endcase
			end
			default: begin
				en_fetch = 1'b0 ;
				en_group = 1'b0 ;
				en_pc = 1'b0 ;
				pc_ctrl = 2'b00 ;
				reg_en = 4'b0000 ;
				alu_in_sel = 1'b0 ;
				alu_func = 3'b000 ;
			end
		endcase
	end
end

always @ (posedge clk or negedge rst) begin
	if (!rst) begin
		en_fetch_reg <= 1'b0 ;
		en_pc_reg <= 1'b0 ;
		en_group_reg <= 1'b0 ;
	end
	else begin
		en_fetch_reg <= en_fetch ; 
		en_pc_reg <= en_pc ;
		en_group_reg <= en_group ;
	end
end

always @ (en_fetch or en_fetch_reg)
	en_fetch_pulse = en_fetch & (~en_fetch_reg) ;
	
always @ (en_pc_reg or en_pc)
	en_pc_pulse = en_pc & (~en_pc_reg) ; // 此时需要读入下一个指令,且当此时指令寄存器中为空时,请求下一条指令
	
always @ (en_group_reg or en_group)
	en_group_pulse = en_group & (~en_group_reg) ;

endmodule

Testbench

复制代码
`timescale 1ns / 1ps

u();
reg         clk,rst,en_in,en_ram_out;
reg  [15:0] ins;
wire        en_ram_in;
wire [15:0] addr;

cpu test_cpu(
    .clk (clk),
    .rst (rst),
    .en_in (en_in),
    .en_ram_in (en_ram_in), 
    .ins (ins),	
    .en_ram_out (en_ram_out),
    .addr (addr)   	
);

parameter Tclk = 10;

initial begin
	    //define clk
		end
        
initial begin
		//define rst 
		end

initial begin                
		//define en_in and en_ram_out
end

initial begin
         //define ins ,you can assign 0000_0000_0000_0001
		    //0000_0100_0000_0010 and so on to ins.
        end
       
initial begin
    #(Tclk*400)  $stop;
end

endmodule

如有疑问,欢迎打扰。

相关推荐
仲南音2 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner3 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20203 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy3 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia3 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20203 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子4 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安4 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun5 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun5 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议