基于Verilog的简易CPU设计

news2024/9/24 19:21:20

前言 

        本篇文章将简单讲解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

如有疑问,欢迎打扰。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

雷卯推荐基于USB 快充(USB-PD) 浪涌保护器件

USB PD 从2010年USB BC1.2 &#xff1a;单一5V 1.5A&#xff0c;到2021 年USB PD 3.1&#xff0c;支持电压 5V、9V、15V 和 20V&#xff0c;28V、36V 和 48V, 充电功率同步提升至240W。应用范围从从手机、平板电脑、笔记本电脑&#xff0c;逐渐向显示器、服务器、电机驱动和通信…

企业架构设计方法与实践中的架构治理演进、架构评估方法、架构成熟度模型

企业架构设计方法与实践中的架构治理演进、架构评估方法、架构成熟度模型。 架构治理演进: 架构治理是指通过设立和执行一套政策和程序,来管理和控制一个组织的架构活动。架构治理演进是一个持续的过程,需要根据组织的实际情况进行定期审查和调整。 在演进过程中,重点需要…

Python学习01 python开发的准备工作 1.Python解释器的下载 2.Pycharm集成开发环境的安装

0.按照步骤&#xff0c;快速进行python的开发准备工作 1. Python解释器的下载 下载地址 https://www.python.org/ 选择对应你的系统的安装包 2.记得勾选这里将python加入你的路径中 3.有如下四个程序表明安装成功 4.点击上图中的第二个程序打开窗口检查解释器能否正常工作 输…

Flutter 多语言自动化本地化生成器

Flutter 多语言自动化本地化生成器 这是一个为Flutter设计的插件&#xff0c;通过从Excel表格提取的CSV文件自动生成Dart本地化文件&#xff0c;以简化应用程序本地化的流程。这个工具通过自动化创建多语言资源文件&#xff0c;简化了开发人员和翻译人员的工作流程。 特点 默…

MQTT.fx实现(MQTT Client)连接物联网平台(ThingsCloud )

目录 概述 1 ThingsCloud平台介绍 2 ThingsCloud创建项目 2.1 创建项目 2.2 创建数据类型 2.3 创建设备类型 3 发布和订阅主题 3.1 发布Topic 3.2 订阅主题Topic 4 使用MQTT.fx 测试ThingsClond 4.1 使用MQTT.fx连接ThingsClond 4.2 MQTT.fx 订阅ThingsCloud Messag…

Unity资源热更新----AssetBundle

13.1 资源热更新——AssetBundle1-1_哔哩哔哩_bilibili Resources 性能消耗较大 Resources文件夹大小不能超过2个G 获取AssetBundle中的资源 打包流程 选择图片后点击 创建文件夹&#xff0c;Editor优先编译 打包文件夹位置 using UnityEditor; using UnityEngine; public cla…

探索编程新纪元:Code GeeX、Copilot与通义灵码的智能辅助之旅

在人工智能技术日新月异的今天&#xff0c;编程领域的革新也正以前所未有的速度推进。新一代的编程辅助工具&#xff0c;如Code GeeX、Copilot和通义灵码&#xff0c;正在重塑开发者的工作流程&#xff0c;提升编程效率&#xff0c;并推动编程教育的普及。本文将深入探讨这三款…

已解决Keil报错unknown type name “u8“或/u16/u32

出现问题如下所示&#xff0c;提示错误unknown type name “u8“ 解决方法&#xff1a; 在头文件中加入如下即可解决 typedef uint8_t u8; 这个错误通常表示编译器无法识别“u8”这个类型名。在C/C中&#xff0c;通常使用“uint8_t”来表示8位无符号整数类型。如果代码中…

django-q轻量级定时任务制定

django-q ,celery&#xff0c;apschedule都可以作为python的选型&#xff0c;但是django-q更轻量级&#xff0c;可以定制想要的任务&#xff0c;通过消息中间件&#xff0c;来实现不太高并发的实现 官网介绍地址 django-q官网地址 本次测试的是python3.12版本 首先需要安装dja…

ELK日志管理实现的3种常见方法

ELK日志管理实现的3种常见方法 1. 日志收集方法 1.1 使用DaemonSet方式日志收集 通过将node节点的/var/log/pods目录挂载给以DaemonSet方式部署的logstash来读取容器日志,并将日志吐给kafka并分布写入Zookeeper数据库.再使用logstash将Zookeeper中的数据写入ES,并通过kibana…

C语言函数—递归

这方面内容涉及到栈的使用&#xff0c;我们的递归函数如果被执行那么系统将会自动的去创建一个栈&#xff0c;相关内容有机会单独写文章讲解 什么是递归&#xff1f; 程序调用自身的编程技巧称为递归&#xff08; recursion&#xff09;。 递归做为一种算法在程序设计语言中广泛…

基于单片机的恒压供水控制器设计

摘 要 随着我国现代化的进程不断加快&#xff0c;城市居民生活水平不断提高&#xff0c;随之而来的是房屋的翻新和重建&#xff0c;但建筑层数的不断增高&#xff0c;使得供水所需压力不断提高&#xff0c;若建筑设计时对压力判断不足&#xff0c;会导致供水时无法供应到高楼层…

643.子数组最大平均数

题目&#xff1a;给你一个由 n 个元素组成的整数数组 nums 和一个整数k。 找出平均数最大且长度为 k 的连续子数组&#xff0c;并输出该最大平均数。 任何误差小于10^-5 的答案都将被视为正确答案。 解题思路&#xff1a;规定了子数组的长度为k&#xff0c;因此可以通过寻找子…

新冠疫情仍处流行期,防疫不松懈

2024年2月北京市法定传染病疫情概况已公布&#xff0c;全市共报告了21种法定传染病&#xff0c;累计病例数达到88971例&#xff0c;不幸有12人因疾病离世。这些病例主要集中在病毒性肝炎、肺结核、百日咳、梅毒、新型冠状病毒感染、流行性感冒以及其他感染性腹泻病等。 值得一提…

概率论与数理统计(随机事件与概率)

1随机事件与概率 1.1随机事件及其运算规律 1.1.1运算 交换律结合律分配律德摩根律 1.2概率的定义及其确定方法 1.2.1概率的统计定义 频率 设在 n 次试验中&#xff0c;事件 A 发生了(A)次&#xff0c;则称为事件 A 发生的频率。 1.2.2概率的统计定义 在一组恒定不变的条…

Mybatis(搭建,CRUD,方法参数,XML映射文件,动态SQL)【详解】

目录 一.准备基础代码 Mybatis的通用配置 二. 基本CURD操作 1.查询-根据id查询一条 2.查询-查询数量 3.删除 4.新增 获取主键值 5.修改 6.查询-模糊查询 预编译SQL #{}与${}的区别【面试题】 三. Mybatis的方法参数与结果集 1.SQL里取方法参数的值 2.查询结果集…

react native常用插件

react-native-async-storage/async-storage 说明&#xff1a;AsyncStorage 是一个在 react-native 中轻量存储的库&#xff1b;跟 localStorage 类似&#xff0c;API 也几乎一样&#xff1b;存储的时候需要将存储内容转成字符串存储。 react-navigation/material-bottom-tabs …

Ubuntu Flask 运行 gunicorn+Nginx 部署

linux Ubuntu 下运行python 程序出现killed 原因&#xff1a;CPU或内存限制&#xff1a;在华为云上&#xff0c;你可能有CPU或内存使用的限制。例如&#xff0c;如果你使用的是一个固定大小的实例&#xff0c;那么超过该实例的CPU或内存限制可能会导致进程被杀死。 参考&am…

Gateway网关在url参数带有特殊字符的情况下转发失败(响应400)

本文主要分享了&#xff0c;SpringCloud Gateway网关在url参数带有空格或者特殊字符的情况下&#xff0c;转发失败导致响应错误码400的解决方案。 响应400错误码的2种场景&#xff1a; 1.参数带空格&#xff0c;Gateway会误认为该空格是切割符&#xff0c;如?phone 135****6…

基于单片机的公交车IC卡操作系统的设计

目 录 摘 要 III Abstract IV 前 言 1 第一章 绪论 2 1.1 设计的背景和意义 2 1.2 设计的现状和发展 2 1.3 设计的目的与意义 2 第二章 总体设计 4 2.1 总体方案的设计与实现 4 2.1.1 主要设计的内容 4 2.1.2 系统的总体设计 4 2.2 系统方案论证 5 2.2.1 单片机的选择 6 2.2.2…