基于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 / 1ns

`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)
				// please add your code here
					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

如有疑问,欢迎打扰。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/455479.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

keycloak18.0.0==前后端分离项目中使用,前端react后端springboot

配置keycloak 启动keycloak18 新建一个realm,名字叫test1 新建两个client&#xff0c;一个用于前端&#xff0c;一个用于后端 第一个 react http://localhost:8081/auth/realms/test1/react/ 第二个 backend-service 在两个client下分别创建role testRole backend-servic…

CF575H Bots 题解 组合数学

Bots&#xff08;波特&#xff09; 传送门 Sasha and Ira are two best friends. But they aren’t just friends, they are software engineers and experts in artificial intelligence. They are developing an algorithm for two bots playing a two-player game. The ga…

生产企业如何发现瓶颈工序并解决它

众所周知&#xff0c;瓶颈工序决定整体产能&#xff0c;产能均衡是高效生产的重要保证&#xff0c;在100个工序中&#xff0c;只要存在一个工序效率低下&#xff0c;那么99个工序的努力都无法解决整体产能落后的问题。 如何解决瓶颈工序产能不足问题&#xff0c;进而提高工厂整…

k8s部署InfluxDB

&#xff08;作者&#xff1a;陈玓玏&#xff09; 1. 拉取镜像 docker pull influxdb #拉取镜像 docker run -d influxdb:latest #后台运行容器 docker exec -it 89b /bin/bash #进入容器&#xff0c;89b是容器ID的前三位 cd /usr/bin #进入容器后&#xff0c;进入此文件夹…

【WPS】压缩图片

第一步&#xff1a; 点击插入&#xff0c;点击图片 第二步&#xff1a; 点击图片工具&#xff0c;点击压缩图片 第三步&#xff1a;

Git 遇到合并冲突如何解决

Git 遇到合并冲突解决方法 前言一、解决冲突 回滚二、将解冲突后的文件 提交到暂存区三、git commit 提交代码到本地Git仓库四、git push 提交五、注意 ​ 2024/3/13 前言 Git突然无法拉取下来&#xff0c;显示有合并冲突&#xff1a; 步骤&#xff1a;解决回滚解决冲突后、添…

数据结构-链表(二)

1.两两交换列表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2…

[HackMyVm] Vinulizer

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

CCCorelib 点云ICP配准(CloudCompare内置算法库)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 ICP算法总共分为6个阶段,如下图所示: (1)挑选发生重叠的点云子集,这一步如果原始点云数据量比较巨大,一般会对原始点云进行下采样操作。 (2)匹配特征点。通常是距离最近的两个点,当然这需要视评判的准则而…

mysql不能远程连接的解决办法

问题: 安装完mysql之后,在本机可以正常使用,但是通过其它电脑不能远程连接. 解决方案: 在安装mysql的电脑上,登录mysql, 执行权限 GRANT ALL PRIVILEGES ON *.* TO root"%" IDENTIFIED BY "password"; 刷新权限 flush privileges;

C++(3/13)

设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>using namespace std; cla…

【C语言】C语言中执行命令

在C语言编程中&#xff0c;执行命令通常是通过调用库函数完成的。以下是一些C语言中用来执行系统命令的函数&#xff1a; 1. system(): 这是C语言标准库函数之一&#xff0c;能够执行命令行命令。它调用操作系统的命令处理器来执行给定的命令。 #include <stdlib.h>in…

雅特力AT32A403开发板评测 03 官方图形化配置工具Work Bench使用

03 雅特力AT32A403开发板评测 官方图形化配置工具Work Bench使用 1. 软硬件平台 AT32A403A Board开发板 MDK-ARM Keil Work Bench 2. AT32 Work Bench 为了方便开发者快速开发芯片&#xff0c;国外大厂的搞了单片机图形化配置工具&#xff0c;生成初始化配置代码&#x…

算法空间复杂度计算

目录 空间复杂度定义 影响空间复杂度的因素 算法在运行过程中临时占用的存储空间讲解 例子 斐波那契数列递归算法的性能分析 二分法&#xff08;递归实现&#xff09;的性能分析 空间复杂度定义 空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大…

MyBatis3源码深度解析(十一)MyBatis常用工具类(四)ObjectFactoryProxyFactory

文章目录 前言3.6 ObjectFactory3.7 ProxyFactory3.8 小结 前言 本节研究ObjectFactory和ProxyFactory的基本用法&#xff0c;因为它们在MyBatis的源码中比较常见。这里不深究ObjectFactory和ProxyFactory的源码&#xff0c;而是放到后续章节再展开。 3.6 ObjectFactory Obj…

ES6(三):Iterator、Generator、类的用法、类的继承

一、迭代器Iterator 迭代器是访问数据的一个接口&#xff0c;是用于遍历数据结构的一个指针&#xff0c;迭代器就是遍历器 const items[one,two,three];//创建新的迭代器const ititems[Symbol.iterator]();console.log(it.next()); done&#xff1a;返回false表示遍历继续&a…

04_拖动文件渲染在页面中

新建一个文件夹&#xff0c;跟之前一样&#xff0c;在 Vscode 终端里输入 yarn create electron-app Drag。 在 index.html 添加以下代码&#xff0c;JS 文件夹和 render.js 都是新创建的&#xff1a; 首先&#xff0c;css 文件一般和 html 结合使用&#xff0c;相当于 html 是…

Prometheus 监控系统

目录 概述 Prometheus定义 Prometheus 的特点 Prometheus 的生态组件 Prometheus 的工作模式 Prometheus 的工作流程 Prometheus 的局限性 1.部署 Prometheus 上传prometheus包二级制安装 配置系统启动文件&#xff0c;启动 Prometheust 2.部署 Exporters 上传node…

[Spark SQL]Spark SQL读取Kudu,写入Hive

SparkUnit Function&#xff1a;用于获取Spark Session package com.example.unitlimport org.apache.spark.sql.SparkSessionobject SparkUnit {def getLocal(appName: String): SparkSession {SparkSession.builder().appName(appName).master("local[*]").getO…

探索考古文字场景,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建文本考古场景下的甲骨文字符图像检测识别系统

甲骨文是一种非常历史悠久的古老文字&#xff0c;在前面我们基本上很少有涉及这块的内容&#xff0c;最近正好在做文字相关的项目开发研究&#xff0c;就想着基于甲骨文的场景来开发对应的检测识别系统&#xff0c;在前文中我们基于YOLOv5、YOLOv7和YOLOv9开发构建了在仿真数据…