基于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

如有疑问,欢迎打扰。

相关推荐
fei_sun16 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto16 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安21 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈21 小时前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun1 天前
【Verilog】第二章作业
fpga开发·verilog
碎碎思1 天前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望1 天前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT1 天前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思2 天前
很能体现FPGA硬件思维的一道面试题
fpga开发