之前的实验6仿真部分,由于端口定义问题,IF阶段出现无法设置reg类型的问题。
这边做补充修改:
在设计模块中,input类型才可以作为仿真时reg类型实例化,output类型只能作为仿真时的wire类型,无法参与仿真过程块。
强制修改一个wire变量为reg变量,无法实现,因为一个变量会同时传递到多个模块,可能会是input,可能会是output。
这边解决办法是将变量多定义一个,单独用于拥有input类型的模块。
(例如new_pc在IF模块中作为input,可以用reg类型,而在cpu控制模块作为output,只能使用wire类型。这边将尾号带有1的reg类型,实例化到IF模块,而wire类型,实例化到控制模块)
因为模块的内部是定义好连接的,所以在实例化过程还是可以进行参数传递。
定义相同变量如下,不同模块实例化如下:
wire if_flush; // IF stage
reg if_flush1;
wire if_stall; // IF stage
reg if_stall1;
wire [`WordAddrBus] new_pc; // New program counter
reg [`WordAddrBus] new_pc1;
//实例化
/********** IF stage **********/
if_stage if_stage (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** SPM interface **********/
.spm_rd_data (if_spm_rd_data),
.spm_addr (if_spm_addr),
.spm_as_ (if_spm_as_),
.spm_rw (if_spm_rw),
.spm_wr_data (if_spm_wr_data),
/********** Bus interface **********/
.bus_rd_data (if_bus_rd_data),
.bus_rdy_ (if_bus_rdy_),
.bus_grnt_ (if_bus_grnt_),
.bus_req_ (if_bus_req_),
.bus_addr (if_bus_addr),
.bus_as_ (if_bus_as_),
.bus_rw (if_bus_rw),
.bus_wr_data (if_bus_wr_data),
/********** Pipeline control signal **********/
.stall (if_stall1),
.flush (if_flush1),
.new_pc (new_pc1),
.br_taken (br_taken),
.br_addr (br_addr),
.busy (if_busy),
/********** IF/ID pipeline register **********/
.if_pc (if_pc),
.if_insn (if_insn),
.if_en (if_en)
);
/********** Control unit **********/
ctrl ctrl (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** Control register interface **********/
.creg_rd_addr (creg_rd_addr),
.creg_rd_data (creg_rd_data),
.exe_mode (exe_mode),
/********** Interrupt **********/
.irq (cpu_irq),
.int_detect (int_detect),
/********** ID/EX pipeline register **********/
.id_pc (id_pc),
/********** MEM/WB pipeline register **********/
.mem_pc (mem_pc),
.mem_en (mem_en),
.mem_br_flag (mem_br_flag),
.mem_ctrl_op (mem_ctrl_op),
.mem_dst_addr (mem_dst_addr),
.mem_exp_code (mem_exp_code),
.mem_out (mem_out),
/********** Pipeline control signal **********/
// Status of pipeline
.if_busy (if_busy),
.ld_hazard (ld_hazard),
.mem_busy (mem_busy),
// stall singal
.if_stall (if_stall),
.id_stall (id_stall),
.ex_stall (ex_stall),
.mem_stall (mem_stall),
// Flush signal
.if_flush (if_flush),
.id_flush (id_flush),
.ex_flush (ex_flush),
.mem_flush (mem_flush),
// New program counter
.new_pc (new_pc)
);
这样我们就可以实现通过流水线刷新,将new_pc作为传递地址指向SPM内存。IF阶段可以从SPM模块中取出指令,进行后续操作。
注意要在SPM的子模块(x_s3e_dpram.v)中添加一行指令:
mem[0] <= {{`ISA_OP_ADDSR},{5'b00001},{5'b00010},{5'b00011},{11{1'b0}}};
仿真代码如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2022/02/04 21:25:14
// Design Name:
// Module Name: cpu_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
/********** Global header **********/
`include "nettype.vh"
`include "global_config.vh"
`include "stddef.vh"
/********** Local header **********/
`include "isa.vh"
`include "cpu.vh"
`include "bus.vh"
`include "spm.vh"
module cpu_test(
);
//端口定义
/********** Clock & Reset **********/
reg clk; // Clock
reg clk_; // Clock (180)
reg reset; // Asynchronous reset
/********** Bus interface **********/
// IF Stage
reg [`WordDataBus] if_bus_rd_data; // Read data
reg if_bus_rdy_; // Ready
reg if_bus_grnt_; // Bus grant
wire if_bus_req_; // Bus request
wire [`WordAddrBus] if_bus_addr; // Address
wire if_bus_as_; // Address strobe
wire if_bus_rw; // Read/Write
wire [`WordDataBus] if_bus_wr_data; // Write data
// MEM Stage
reg [`WordDataBus] mem_bus_rd_data; // Read data
reg mem_bus_rdy_; // Ready
reg mem_bus_grnt_; // Bus grant
wire mem_bus_req_; // Bus reqeuest
wire [`WordAddrBus] mem_bus_addr; // Address
wire mem_bus_as_; // Address strobe
wire mem_bus_rw; // Read/Write
wire [`WordDataBus] mem_bus_wr_data; // Write data
/********** Interrupt **********/
reg [`CPU_IRQ_CH-1:0] cpu_irq; // Interrupt request
/********** Pipeline register **********/
// IF/ID
wire [`WordAddrBus] if_pc;
wire [`WordDataBus] if_insn;
wire if_en;
// ID/EX pipeline register
wire [`WordAddrBus] id_pc;
wire id_en;
wire [`AluOpBus] id_alu_op;
wire [`WordDataBus] id_alu_in_0;
wire [`WordDataBus] id_alu_in_1;
wire id_br_flag;
wire [`MemOpBus] id_mem_op;
wire [`WordDataBus] id_mem_wr_data;
wire [`CtrlOpBus] id_ctrl_op;
wire [`RegAddrBus] id_dst_addr;
wire id_gpr_we_;
wire [`IsaExpBus] id_exp_code;
// EX/MEM pipeline register
wire [`WordAddrBus] ex_pc;
wire ex_en;
wire ex_br_flag;
wire [`MemOpBus] ex_mem_op;
wire [`WordDataBus] ex_mem_wr_data;
wire [`CtrlOpBus] ex_ctrl_op;
wire [`RegAddrBus] ex_dst_addr;
wire ex_gpr_we_;
wire [`IsaExpBus] ex_exp_code;
wire [`WordDataBus] ex_out;
// MEM/WB pipeline register
wire [`WordAddrBus] mem_pc;
wire mem_en;
wire mem_br_flag;
wire [`CtrlOpBus] mem_ctrl_op;
wire [`RegAddrBus] mem_dst_addr;
wire mem_gpr_we_;
wire [`IsaExpBus] mem_exp_code;
wire [`WordDataBus] mem_out;
/********** Pipeline control signal **********/
// Stall signal
wire if_stall; // IF stage
reg if_stall1;
wire id_stall; // ID stage
wire ex_stall; // EX stage
wire mem_stall; // MEM stage
// Flush signal
wire if_flush; // IF stage
reg if_flush1;
wire id_flush; // ID stage
wire ex_flush; // EX stage
wire mem_flush; // MEM stage
// Busy signal
wire if_busy; // IF stage
wire mem_busy; // MEM stage
// Other control signal
wire [`WordAddrBus] new_pc; // New program counter
reg [`WordAddrBus] new_pc1;
wire [`WordAddrBus] br_addr; // Branch address
wire br_taken; // Branch taken
wire ld_hazard; // Load hazard
/********** GPR signal **********/
wire [`WordDataBus] gpr_rd_data_0;
wire [`WordDataBus] gpr_rd_data_1;
wire [`RegAddrBus] gpr_rd_addr_0;
wire [`RegAddrBus] gpr_rd_addr_1;
/********** Control register signal **********/
wire [`CpuExeModeBus] exe_mode;
wire [`WordDataBus] creg_rd_data;
wire [`RegAddrBus] creg_rd_addr;
/********** Interrupt Request **********/
wire int_detect;
/********** Scratchpad memory signal **********/
// IF stage
wire [`WordDataBus] if_spm_rd_data;
wire [`WordAddrBus] if_spm_addr;
wire if_spm_as_;
wire if_spm_rw;
wire [`WordDataBus] if_spm_wr_data;
// MEM stage
wire [`WordDataBus] mem_spm_rd_data;
wire [`WordAddrBus] mem_spm_addr;
wire mem_spm_as_;
wire mem_spm_rw;
wire [`WordDataBus] mem_spm_wr_data;
/********** Forwarding signal **********/
wire [`WordDataBus] ex_fwd_data; // EX stage
wire [`WordDataBus] mem_fwd_data; // MEM stage
//时钟激励:
integer i;
parameter STEP=100;
always#(STEP/2)begin
clk<=~clk;
clk_ <=~clk_;
end
//实例化
/********** IF stage **********/
if_stage if_stage (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** SPM interface **********/
.spm_rd_data (if_spm_rd_data),
.spm_addr (if_spm_addr),
.spm_as_ (if_spm_as_),
.spm_rw (if_spm_rw),
.spm_wr_data (if_spm_wr_data),
/********** Bus interface **********/
.bus_rd_data (if_bus_rd_data),
.bus_rdy_ (if_bus_rdy_),
.bus_grnt_ (if_bus_grnt_),
.bus_req_ (if_bus_req_),
.bus_addr (if_bus_addr),
.bus_as_ (if_bus_as_),
.bus_rw (if_bus_rw),
.bus_wr_data (if_bus_wr_data),
/********** Pipeline control signal **********/
.stall (if_stall1),
.flush (if_flush1),
.new_pc (new_pc1),
.br_taken (br_taken),
.br_addr (br_addr),
.busy (if_busy),
/********** IF/ID pipeline register **********/
.if_pc (if_pc),
.if_insn (if_insn),
.if_en (if_en)
);
/********** ID stage **********/
id_stage id_stage (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** GPR interface **********/
.gpr_rd_data_0 (gpr_rd_data_0),
.gpr_rd_data_1 (gpr_rd_data_1),
.gpr_rd_addr_0 (gpr_rd_addr_0),
.gpr_rd_addr_1 (gpr_rd_addr_1),
/********** Forwarding **********/
// Forwarding from EX stage
.ex_en (ex_en),
.ex_fwd_data (ex_fwd_data),
.ex_dst_addr (ex_dst_addr),
.ex_gpr_we_ (ex_gpr_we_),
// Forwarding from MEM stage
.mem_fwd_data (mem_fwd_data),
/********** Control register interface **********/
.exe_mode (exe_mode),
.creg_rd_data (creg_rd_data),
.creg_rd_addr (creg_rd_addr),
/********** Pipeline control signal **********/
.stall (id_stall),
.flush (id_flush),
.br_addr (br_addr),
.br_taken (br_taken),
.ld_hazard (ld_hazard),
/********** IF/ID pipeline register **********/
.if_pc (if_pc),
.if_insn (if_insn),
.if_en (if_en),
/********** ID/EX pipeline register **********/
.id_pc (id_pc),
.id_en (id_en),
.id_alu_op (id_alu_op),
.id_alu_in_0 (id_alu_in_0),
.id_alu_in_1 (id_alu_in_1),
.id_br_flag (id_br_flag),
.id_mem_op (id_mem_op),
.id_mem_wr_data (id_mem_wr_data),
.id_ctrl_op (id_ctrl_op),
.id_dst_addr (id_dst_addr),
.id_gpr_we_ (id_gpr_we_),
.id_exp_code (id_exp_code)
);
/********** EX stage **********/
ex_stage ex_stage (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** Pipeline control signal **********/
.stall (ex_stall),
.flush (ex_flush),
.int_detect (int_detect),
/********** Forwarding **********/
.fwd_data (ex_fwd_data),
/********** ID/EX pipeline register **********/
.id_pc (id_pc),
.id_en (id_en),
.id_alu_op (id_alu_op),
.id_alu_in_0 (id_alu_in_0),
.id_alu_in_1 (id_alu_in_1),
.id_br_flag (id_br_flag),
.id_mem_op (id_mem_op),
.id_mem_wr_data (id_mem_wr_data),
.id_ctrl_op (id_ctrl_op),
.id_dst_addr (id_dst_addr),
.id_gpr_we_ (id_gpr_we_),
.id_exp_code (id_exp_code),
/********** EX/MEM pipeline register **********/
.ex_pc (ex_pc),
.ex_en (ex_en),
.ex_br_flag (ex_br_flag),
.ex_mem_op (ex_mem_op),
.ex_mem_wr_data (ex_mem_wr_data),
.ex_ctrl_op (ex_ctrl_op),
.ex_dst_addr (ex_dst_addr),
.ex_gpr_we_ (ex_gpr_we_),
.ex_exp_code (ex_exp_code),
.ex_out (ex_out)
);
/********** MEM Stage **********/
mem_stage mem_stage (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** Pipeline control signal **********/
.stall (mem_stall),
.flush (mem_flush),
.busy (mem_busy),
/********** Forwarding **********/
.fwd_data (mem_fwd_data),
/********** SPM interface **********/
.spm_rd_data (mem_spm_rd_data),
.spm_addr (mem_spm_addr),
.spm_as_ (mem_spm_as_),
.spm_rw (mem_spm_rw),
.spm_wr_data (mem_spm_wr_data),
/********** Bus interface **********/
.bus_rd_data (mem_bus_rd_data),
.bus_rdy_ (mem_bus_rdy_),
.bus_grnt_ (mem_bus_grnt_),
.bus_req_ (mem_bus_req_),
.bus_addr (mem_bus_addr),
.bus_as_ (mem_bus_as_),
.bus_rw (mem_bus_rw),
.bus_wr_data (mem_bus_wr_data),
/********** EX/MEM pipeline register **********/
.ex_pc (ex_pc),
.ex_en (ex_en),
.ex_br_flag (ex_br_flag),
.ex_mem_op (ex_mem_op),
.ex_mem_wr_data (ex_mem_wr_data),
.ex_ctrl_op (ex_ctrl_op),
.ex_dst_addr (ex_dst_addr),
.ex_gpr_we_ (ex_gpr_we_),
.ex_exp_code (ex_exp_code),
.ex_out (ex_out),
/********** MEM/WB pipeline register **********/
.mem_pc (mem_pc),
.mem_en (mem_en),
.mem_br_flag (mem_br_flag),
.mem_ctrl_op (mem_ctrl_op),
.mem_dst_addr (mem_dst_addr),
.mem_gpr_we_ (mem_gpr_we_),
.mem_exp_code (mem_exp_code),
.mem_out (mem_out)
);
/********** Control unit **********/
ctrl ctrl (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** Control register interface **********/
.creg_rd_addr (creg_rd_addr),
.creg_rd_data (creg_rd_data),
.exe_mode (exe_mode),
/********** Interrupt **********/
.irq (cpu_irq),
.int_detect (int_detect),
/********** ID/EX pipeline register **********/
.id_pc (id_pc),
/********** MEM/WB pipeline register **********/
.mem_pc (mem_pc),
.mem_en (mem_en),
.mem_br_flag (mem_br_flag),
.mem_ctrl_op (mem_ctrl_op),
.mem_dst_addr (mem_dst_addr),
.mem_exp_code (mem_exp_code),
.mem_out (mem_out),
/********** Pipeline control signal **********/
// Status of pipeline
.if_busy (if_busy),
.ld_hazard (ld_hazard),
.mem_busy (mem_busy),
// stall singal
.if_stall (if_stall),
.id_stall (id_stall),
.ex_stall (ex_stall),
.mem_stall (mem_stall),
// Flush signal
.if_flush (if_flush),
.id_flush (id_flush),
.ex_flush (ex_flush),
.mem_flush (mem_flush),
// New program counter
.new_pc (new_pc)
);
/********** GPR **********/
gpr gpr (
/********** Clock & Reset **********/
.clk (clk),
.reset (reset),
/********** Read port 0 **********/
.rd_addr_0 (gpr_rd_addr_0),
.rd_data_0 (gpr_rd_data_0),
/********** Read port 1 **********/
.rd_addr_1 (gpr_rd_addr_1),
.rd_data_1 (gpr_rd_data_1),
/********** Write port **********/
.we_ (mem_gpr_we_),
.wr_addr (mem_dst_addr),
.wr_data (mem_out)
);
/********** Scratchpad memory **********/
spm spm (
/********** Clock **********/
.clk (clk_),
/********** PortA : IF stage **********/
.if_spm_addr (if_spm_addr[`SpmAddrLoc]),
.if_spm_as_ (if_spm_as_),
.if_spm_rw (if_spm_rw),
.if_spm_wr_data (if_spm_wr_data),
.if_spm_rd_data (if_spm_rd_data),
/********** PortB : MEM stage **********/
.mem_spm_addr (mem_spm_addr[`SpmAddrLoc]),
.mem_spm_as_ (mem_spm_as_),
.mem_spm_rw (mem_spm_rw),
.mem_spm_wr_data (mem_spm_wr_data),
.mem_spm_rd_data (mem_spm_rd_data)
);
//测试模式:
initial
begin
clk<=1;
clk_<=0;
reset<=`RESET_ENABLE;
#(STEP*3/4)
#STEP begin
reset<=`RESET_DISABLE;
#STEP
if_stall1<=`DISABLE;
#STEP
new_pc1<={{3'b001},{27{1'b0}}};
if_flush1<=`ENABLE;
#STEP
if_flush1<=`DISABLE;
end
end
endmodule
仿真结果如下:
1.IF阶段
通过newPC,将目标地址转向SPM中,实现在SPM中取出指令。
2.ID阶段
将指令分解,并准备好计算数据(在GPR模块,gpr[1]和gpr[2])
3.EX阶段
执行指令,将结果输入到MEM中。
4.MEM阶段
将EX阶段的结果写入寄存器(gpr[3])
实现100+200=300的寄存器间加法指令,仿真结束。