ori是一条I型指令,指令格式如下图所示。
I类指令格式
ori指令的指令码是6'b001101,所以当处理器发现正在处理的指令的高6位是6'b001101时,就知道当前正在处理ori指令。
该指令的使用方法是:将指令中的16位立即数取符号扩展为32位,然后与索引为rs的通用寄存器的值进行逻辑“或”运算。 运算结果存储在索引为rt 的通用寄存器中。 这里需要说明以下两点。
(1) 无符号扩展
符号扩展是将n位立即数的最高位复制到扩展后的32位数据的高(32-n)位,无符号扩展是将所有的高(32-n)位置位扩展的 32 位数据为 0。
以指令中的16位立即数扩展为32位为例,16位立即数分别是0x8000和0x1000处符号扩展和无符号扩展的结果。
16 位立即数扩展示例
(2) 通用寄存器
在MIPS32指令集架构中,定义了32个通用寄存器$0-$31。 要使用某个通用寄存器,只需要给出相应的索引即可,该索引占用5位。 ori指令中的rs和rt是通用寄存器的索引。 例如:当rs为5'b00011时,表示通用寄存器$3。
流水线结构的建立
在流水线结构中。 信号在寄存器之间传递,每传递到一个电平都会引起相应的组合逻辑电路发生变化。 这种模型的抽象描述就是寄存器传输级(RTL:Register Transfer Level)。
管道的简单模型获取阶段的实现
取指令阶段从指令存储器中取指令。 同时。 PC值递增,准备取下一条指令,包括PC和IF/ID两个模块。
1.电脑模块
PC模块的作用是给出指令地址。
module pc_reg(
input wire clk,
input wire rst,
output reg[`InstAddrBus] pc
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
ce <= `ChipDisable; // 复位的时候指令存储器禁用
end else begin
ce <= `ChipEnable; // 复位结束后,指令存储器使能
end
end
always @ (posedge clk) begin
if (ce == `ChipDisable) begin
pc <= 32'h00000000; // 指令存储器禁用的时候,PC为0
end else begin
pc <= pc + 4'h4; // 指令存储器使能的时候。PC的值每时钟周期加4
end
end
endmodule
InstAddrBus宏表示指令地址线的宽度,这里定义为32,RstEnable宏表示复位信号有效寄存器传输级,定义为1'b1,即输入rst为高时,表示复位信号有效。
复位时,输出指令存储器使能信号为ChipDisable,表示指令存储器被禁止,其他时候输出指令存储器使能信号为ChipEnable,表示指令存储器被使能。
当禁用指令存储器时。 当启用指令存储器时,PC 的值保持为 0。 PC的值每一个时钟周期加4,表示下一条指令的地址。 由于一条指令是32位的,按照字节寻址,一条指令对应4个字节。 所以PC加4指向下一条指令的地址。
2.IF/ID模块
IF/ID模块的作用是暂时保存取指阶段得到的指令和对应的指令地址,在下一个时钟传递给译码阶段。
module if_id(
input wire clk,
input wire rst,
//来自取指阶段的信号,当中宏定义InstBus表示指令宽度,为32
input wire[`InstAddrBus] if_pc,
input wire[`InstBus] if_inst,
//相应译码阶段的信号
output reg[`InstAddrBus] id_pc,
output reg[`InstBus] id_inst
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
id_pc <= `ZeroWord; // 复位的时候pc为0
id_inst <= `ZeroWord; // 复位的时候指令也为0,实际就是空指令
end else begin
id_pc <= if_pc; // 其余时刻向下传递取指阶段的值
id_inst <= if_inst;
end
end
endmodule
从代码中可以看出,IF/ID模块只是在每个时钟周期的上升沿将fetch阶段的结果传送到decode阶段。
解码阶段的实现
此时我们的指令已经进入解码阶段。 在这个阶段,将对取出的指令进行解码:给出要执行的操作类型和操作涉及的操作数。 解码阶段包括三个模块:Regfile、ID和ID/EX。
1.regfile模块
Regfile模块实现了32个32位通用整数寄存器,可以同时读2个寄存器和写1个寄存器。
module regfile(
input wire clk,
input wire rst,
// 写port
input wire we,
input wire[`RegAddrBus] waddr,
input wire[`RegBus] wdata,
// 读port1
input wire re1,
input wire[`RegAddrBus] raddr1,
output reg[`RegBus] rdata1,
// 读port2
input wire re2,
input wire[`RegAddrBus] raddr2,
output reg[`RegBus] rdata2
);
/****************************************************************
*********** 第一段:定义32个32位寄存器 *********
*****************************************************************/
reg[`RegBus] regs[0:`RegNum-1];
/****************************************************************
*********** 第二段:写操作 *********
*****************************************************************/
always @ (posedge clk) begin
if (rst == `RstDisable) begin
if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin
regs[waddr] <= wdata;
end
end
end
/****************************************************************
*********** 第三段:读port1的读操作 *********
*****************************************************************/
always @ (*) begin
if(rst == `RstEnable) begin
rdata1 <= `ZeroWord;
end else if(raddr1 == `RegNumLog2'h0) begin
rdata1 <= `ZeroWord;
end else if((raddr1 == waddr) && (we == `WriteEnable)
&& (re1 == `ReadEnable)) begin
rdata1 <= wdata;
end else if(re1 == `ReadEnable) begin
rdata1 <= regs[raddr1];
end else begin
rdata1 <= `ZeroWord;
end
end
/****************************************************************
*********** 第四段:读port2的读操作 *********
*****************************************************************/
always @ (*) begin
if(rst == `RstEnable) begin
rdata2 <= `ZeroWord;
end else if(raddr2 == `RegNumLog2'h0) begin
rdata2 <= `ZeroWord;
end else if((raddr2 == waddr) && (we == `WriteEnable)
&& (re2 == `ReadEnable)) begin
rdata2 <= wdata;
end else if(re2 == `ReadEnable) begin
rdata2 <= regs[raddr2];
end else begin
rdata2 <= `ZeroWord;
end
end
endmodule
(1) 第一段:定义了一个二维向量。 元素个数为RegNum,为32,每个元素的宽度为RegBus,也为32,所以这里定义了32个32位的寄存器。
(2)第二段:实现写寄存器操作。 当复位信号无效时(rst为RstDisable),写使能信号
No.we是有效的(we是WriteEnable),当写操作的目标寄存器不等于0时,写输入数据可以保存到目标寄存器。
之所以推断目的寄存器不为0,是因为MIPS32架构规定$0的值只能为0,所以不要写。 WriteEnable是定义在defines.v中的一个宏寄存器传输级,表示写使能信号有效。 这些宏定义的意思很明显,从名字就可以知道详细的意思。 因此,本书后面不再对宏定义进行解释,除非宏定义的含义不容易从名字上看清楚。
(3)第三段:实现第一个读寄存器端口,依次类推后面的步骤。
(4)第四段:实现第二个读寄存器端口。 详细过程与第三段类似,不再赘述。
注意:读寄存器操作是一个组合逻辑电路,即一旦要读取的输入寄存器地址raddr1或raddr2发生变化,就会立即给出新地址对应的寄存器的值,以保证所需要的在解码阶段获得值。 读寄存器的值,而写寄存器的操作是时序逻辑电路,写操作发生在时钟信号的上升沿。