1. 流水线寄存器
此处所谓的流水线寄存器即我们常说的IR寄存器和PC寄存器,用于存放指令以及保存下一条指令的地址。
在本模块中,存在异步复位,如果复位信号有效,则进行复位操作。
如果刷新信号有效且流水线不存在延迟,则将流水线寄存器进行刷新操作。如果分支条件成立,则将流水线寄存器中的值修改为分支条件的值。否则,将寄存器中的内容按既定规则进行更新。
代码如下
`include "cpu.h"
`include "isa.h"
`include "stddef.h"
`include "nettype.h"
`include "global_config.h"
module if_reg (
input wire clk, //时钟信号
input wire reset, //复位信号
input wire [`WordDataBus] insn, //读取到的指令输入
input wire stall, //延迟状态
input wire flush, //刷新状态
input wire [`WordAddrBus] new_pc, //新程序计数器的值
input wire br_taken, //分支成立
input wire br_addr, //分支目标的地址
output reg [`WordAddrBus] if_pc, //程序计数器
output reg [`WordDataBus] if_insn, //指令寄存器
input reg if_en //流水线数据有效程序标志位
);
/* 流水线寄存器 */
always @ (posedge clk or `RESET_EDGE reset) begin
//异步复位
if (reset == `RESET_ENABLE) begin
//PC设为0地址(复位向量地址)、IR设为NOP,流水线数据无效
if_pc <= #1 `RESET_VECTOR;
if_insn <= #1 `ISA_NOP;
if_en <= #1 `DISABLE;
end
else begin
//检查是否存在延迟状态,只有非延迟状态流水线寄存器才能刷新
if (stall == `DISABLE) begin
//检查是否刷新
if (flush == `ENABLE) begin
//将流水线寄存器设置为输入的新地址
if_pc <= #1 new_pc;
if_insn <= #1 `ISA_NOP;
if_en <= #1 `DISABLE;
end
//检查分支是否成立
else if (br_taken == `ENABLE) begin
//将流水线寄存器设置为分支部分的值
if_pc <= #1 br_addr;
if_insn <= #1 insn;
if_en <= #1 `ENABLE;
end
else begin
//否则,将PC指向下一条指令,并完成取指操作
if_pc <= #1 if_pc + 1'd1;
if_insn <= #1 insn;
if_en <= #1 `ENABLE;
end
end
end
end
endmodule
2. 顶层模块
在将IF阶段所有的模块都完成后,我们需要将这些模块组合起来,即需要一个顶层模块。
这个顶层模块由总线接口和流水线寄存器组成。
由于IF阶段对数据、指令的操作仅仅涉及读取,为了方便起见,我们直接将总线接口的读写状态设置为读,写入的数据设置为0,而由于每个周期都会对其进行读取操作,则直接将地址有效信号设置为长期有效状态。
所谓的顶层模块主要的作用就是在模块中将所有需要使用到的模块进行实例化,并将它们连接起来。
具体代码如下:
`include "cpu.h"
`include "isa.h"
`include "stddef.h"
`include "nettype.h"
`include "global_config.h"
module if_reg (
input wire clk, //时钟信号
input wire reset, //复位信号
input wire [`WordDataBus] insn, //读取到的指令输入
input wire stall, //延迟状态
input wire flush, //刷新状态
input wire [`WordAddrBus] new_pc, //新程序计数器的值
input wire br_taken, //分支成立
input wire br_addr, //分支目标的地址
output reg [`WordAddrBus] if_pc, //程序计数器
output reg [`WordDataBus] if_insn, //指令寄存器
input reg if_en //流水线数据有效程序标志位
);
/* 流水线寄存器 */
always @ (posedge clk or `RESET_EDGE reset) begin
//异步复位
if (reset == `RESET_ENABLE) begin
//PC设为0地址(复位向量地址)、IR设为NOP,流水线数据无效
if_pc <= #1 `RESET_VECTOR;
if_insn <= #1 `ISA_NOP;
if_en <= #1 `DISABLE;
end
else begin
//检查是否存在延迟状态,只有非延迟状态流水线寄存器才能刷新
if (stall == `DISABLE) begin
//检查是否刷新
if (flush == `ENABLE) begin
//将流水线寄存器设置为输入的新地址
if_pc <= #1 new_pc;
if_insn <= #1 `ISA_NOP;
if_en <= #1 `DISABLE;
end
//检查分支是否成立
else if (br_taken == `ENABLE) begin
//将流水线寄存器设置为分支部分的值
if_pc <= #1 br_addr;
if_insn <= #1 insn;
if_en <= #1 `ENABLE;
end
else begin
//否则,将PC指向下一条指令,并完成取指操作
if_pc <= #1 if_pc + 1'd1;
if_insn <= #1 insn;
if_en <= #1 `ENABLE;
end
end
end
end
endmodule