前言
本篇文章将简单讲解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
如有疑问,欢迎打扰。