译码模块
/***************************************译码模块**********************************************************/
`include "defines.v"
module id( input wire rst, //复位
input wire[`InstAddrBus] pc_i, //程序计数器
input wire[`InstBus] inst_i, //指令
//读取的regfile的值
input wire[`RegBus] reg1_data_i, //寄存器堆中寄存器1数据
input wire[`RegBus] reg2_data_i, //寄存器堆中寄存器2数据
//输出到regfile的信息
output reg reg1_read_o, //
output reg reg2_read_o,
output reg[`RegAddrBus] reg1_addr_o,
output reg[`RegAddrBus] reg2_addr_o,
//送到执行阶段的信息
output reg[`AluOpBus] aluop_o, //具体运算:或、与...
output reg[`AluSelBus] alusel_o, //运算类型:算数、逻辑、移位...
output reg[`RegBus] reg1_o, //操作数1
output reg[`RegBus] reg2_o, //操作数2
output reg[`RegAddrBus] wd_o, //写入目的寄存器的地址
output reg wreg_o //写目的寄存器使能
);
//取得指令的指令码和功能码
wire[5:0] op = inst_i[31:26]; //指令操作码
wire[4:0] op2 = inst_i[10:6]; /*暂时好像没用*/
wire[5:0] op3 = inst_i[5:0]; /*功能码*/
wire[4:0] op4 = inst_i[20:16]; /*暂时好像没用*/
//保存指令执行需要的立即数
reg[`RegBus] imm;
//指令指针是否有效
reg instvalid;
/***************************************对指令译码*****************************************/
always @(*)
begin
if(rst == `RstEnable) //复位
begin
aluop_o <= `EXE_NOP_OP; //初始化
alusel_o <= `EXE_RES_NOP;
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= `ReadDisable;
reg2_read_o <= `ReadDisable;
reg1_addr_o <= `NOPRegAddr;
reg2_addr_o <= `NOPRegAddr;
imm <= `ZeroWord;
end
else //复位无效
begin
aluop_o <= `EXE_NOP_OP; //初始化
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11]; //默认目的寄存器地址
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= `ReadDisable;
reg2_read_o <= `ReadDisable;
reg1_addr_o <= inst_i[25:21]; //寄存器1地址
reg2_addr_o <= inst_i[20:16]; //寄存器2地址
imm <= `ZeroWord;
case(op) //指令译码
`EXE_SPECIAL_INST: SPECIAL指令码
begin
case(op2)
5'b00000:
begin
case(op3) //功能码
`EXE_AND: //AND指令码
begin
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
aluop_o <= `EXE_AND_OP; //逻辑运算中的“与”运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //and读第一个寄存器的值
reg2_read_o <= `ReadEnable; //and读第二个寄存器的值
end
`EXE_OR: //OR指令码
begin
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
aluop_o <= `EXE_OR_OP; //逻辑运算中的“或”运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable;
reg2_read_o <= `ReadEnable;
end
`EXE_XOR: //XOR指令码
begin
aluop_o <= `EXE_XOR_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //第一个寄存器的值
reg2_read_o <= `ReadEnable; //第二个寄存器的值
end
`EXE_NOR: //NOR指令码
begin
aluop_o <= `EXE_NOR_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //读第一个寄存器的值
reg2_read_o <= `ReadEnable; //读第二个寄存器的值
end
`EXE_SLLV: //SLLV指令码
begin
aluop_o <= `EXE_SLLV_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //读第一个寄存器的值
reg2_read_o <= `ReadEnable; //读第二个寄存器的值
end
`EXE_SRLV: //SRLV指令码
begin
aluop_o <= `EXE_SRLV_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //读第一个寄存器的值
reg2_read_o <= `ReadEnable; //读第二个寄存器的值
end
`EXE_SRAV: //SRAV指令码
begin
aluop_o <= `EXE_SRAV_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //OR读第一个寄存器的值
reg2_read_o <= `ReadEnable; //OR读第二个寄存器的值
end
`EXE_SYNC: //SYNC指令码
begin
aluop_o <= `EXE_SYNC_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wreg_o <= `WriteEnable; //写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadDisable; //OR读第一个寄存器的值
reg2_read_o <= `ReadEnable; //OR读第二个寄存器的值
end
default:
begin
end
end
default:
begin
end
end
`EXE_ORI: //ori指令
begin
aluop_o <= `EXE_OR_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wd_o <= inst_i[20:16]; //目的寄存器地址
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadDisable; //ORI指令无需读第二个寄存器的值
imm <= {16'h0,inst_i[15:0]}; //立即数扩展为32bit
end
`EXE_ANDI: //andi指令
begin
aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wd_o <= inst_i[20:16]; //目的寄存器地址
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadDisable; //ORI指令无需读第二个寄存器的值
imm <= {16'h0,inst_i[15:0]}; //立即数扩展为32bit
end
`EXE_XORI: //xori指令
begin
aluop_o <= `EXE_XOR_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wd_o <= inst_i[20:16]; //目的寄存器地址
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadDisable; //ORI指令无需读第二个寄存器的值
imm <= {16'h0,inst_i[15:0]}; //立即数扩展为32bit
end
`EXE_LUI: //lui指令
begin
aluop_o <= `EXE_OR_OP; //可用“或”运算代替
alusel_o <= `EXE_RES_LOGIC; //逻辑运算
wd_o <= inst_i[20:16]; //目的寄存器地址
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadEnable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadDisable; //ORI指令无需读第二个寄存器的值
imm <= {16'h0,inst_i[15:0]}; //立即数扩展为32bit
end
`EXE_PREF: //pref指令
begin
aluop_o <= `EXE_NOP_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_NOP; //逻辑运算
wreg_o <= `WriteDisable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadDisable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadDisable; //ORI指令无需读第二个寄存器的值
imm <= {16'h0,inst_i[15:0]}; //立即数扩展为32bit
end
default:
begin
end
endcase
if(op3 == `EXE_SLL)
begin
aluop_o <= `EXE_SLL_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_SHIFT; //逻辑运算
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadDisable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadEnable; //ORI指令无需读第二个寄存器的值
imm[4:0] <= inst_i[10:6]; //立即数扩展为32bit
end
else if(op3 == `EXE_SRL)
begin
aluop_o <= `EXE_SRL_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_SHIFT; //逻辑运算
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadDisable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadEnable; //ORI指令无需读第二个寄存器的值
imm[4:0] <= inst_i[10:6]; //立即数扩展为32bit
end
else if(op3 == `EXE_SRA)
begin
aluop_o <= `EXE_SRA_OP; //逻辑运算中的“或”运算
alusel_o <= `EXE_RES_SHIFT; //逻辑运算
wreg_o <= `WriteEnable; //ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
instvalid <= `InstValid; //有效指令
reg1_read_o <= `ReadDisable; //ORI指令需要读第一个寄存器的值
reg2_read_o <= `ReadEnable; //ORI指令无需读第二个寄存器的值
imm[4:0] <= inst_i[10:6]; //立即数扩展为32bit
end
end
end
/***************************************确定源操作数1*****************************************/
always @(*)
begin
if(rst == `RstEnable) //复位有效
reg1_o <= `ZeroWord;
else if(reg1_read_o ==`ReadEnable) //读使能
reg1_o <= reg1_data_i;
else if(reg1_read_o ==`ReadDisable) //读无效时,将立即数放到操作数中,传给执行部分
reg1_o <= imm;
else
reg1_o <= `ZeroWord;
end
/***************************************确定源操作数2*****************************************/
always @(*)
begin
if(rst == `RstEnable)
reg2_o <= `ZeroWord;
else if(reg2_read_o ==`ReadEnable)
reg2_o <= reg2_data_i;
else if(reg2_read_o ==`ReadDisable)
reg2_o <= imm;
else
reg2_o <= `ZeroWord;
end
endmodule
执行模块
/**************************************执行模块***************************************************/
`include "defines.v"
module ex( input wire rst, //复位
input wire[`AluOpBus] aluop_i, //具体运算:或、与...
input wire[`AluSelBus] alusel_i,//运算类型:算数、逻辑、移位...
input wire[`RegBus] reg1_i, //操作数1
input wire[`RegBus] reg2_i, //操作数2
input wire[`RegAddrBus] wd_i, //写入目的寄存器的地址
input wire wreg_i, //写目的寄存器使能
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o );
reg[`RegBus] logicout; //保存逻辑运算的结果
reg[`RegBus] shiftout; //保存移位运算的结果
/******************根据aluop_i指示的运算子类型进行运算,结果保存至logicout*****************/
//逻辑运算
always @(*)
begin
if(rst == `RstEnable)
begin
logicout <= `ZeroWord;
end
else
begin
case(aluop_i)
`EXE_OR_OP: //逻辑或运算
begin
logicout <= reg1_i | reg2_i;
end
`EXE_AND_OP: //逻辑与运算
begin
logicout <= reg1_i & reg2_i;
end
`EXE_NOR_OP: //逻辑或非运算
begin
logicout <= ~(reg1_i | reg2_i);
end
`EXE_XOR_OP: //逻辑异或运算
begin
logicout <= reg1_i ^ reg2_i;
end
default:
begin
logicout <= `ZeroWord;
end
endcase
end
end
//移位运算
always @(*)
begin
if(rst == `RstEnable)
begin
shiftout <= `ZeroWord;
end
else
begin
case(aluop_i)
`EXE_SLL_OP: //逻辑/算数左移
begin
shiftout <= reg2_i << reg1_i[4:0];
end
`EXE_SRL_OP: //逻辑右移
begin
shiftout <= reg2_i >> reg1_i[4:0];
end
`EXE_SRA_OP: //算数右移
begin
shiftout <= ($signed (reg2_i) )>>> reg1_i[4:0];
//shiftout <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];
end
default:
begin
shiftout <= `ZeroWord;
end
endcase
end
end
/*****************根据alusel_i指示的运算类型最终运算,将logicout输出******************/
always @(*)
begin
wd_o <= wd_i; //来自上一级模块的输入。写目的寄存器地址和写寄存器使能
wreg_o <= wreg_i;
case(alusel_i)
`EXE_RES_LOGIC:
begin
wdata_o <= logicout;
end
`EXE_RES_SHIFT:
begin
wdata_o <= shiftout;
end
default:
begin
wdata_o <= `ZeroWord;
end
endcase
end
endmodule
宏定义
//AluOp
`define EXE_OR_OP 8'b00100101 //OR指令
`define EXE_NOP_OP 8'b00000000 //空指令
`define EXE_NOP_OP 6'b000000 //空指令指令码
`define EXE_AND_OP 6'b100100 //AND的指令码
`define EXE_OR_OP 6'b100101 //OR指令码
`define EXE_XOR_OP 6'b100110 //XOR指令码
`define EXE_NOR_OP 6'b100111 //NOR指令码
`define EXE_ANDI_OP 6'b001100 //ANDI指令码
`define EXE_ORI_OP 6'b001101 //ORI指令码
`define EXE_XORI_OP 6'b001110 //XORI指令码
`define EXE_LUI_OP 6'b001111 //LUI指令码
`define EXE_SLL_OP 6'b000000 //SLL指令码
`define EXE_SLLV_OP 6'b000100 //SLLV指令码
`define EXE_SRL_OP 6'b000010 //SRL指令码
`define EXE_SRLV_OP 6'b000110 //SRLV指令码
`define EXE_SRA_OP 6'b000011 //SRA指令码
`define EXE_SRAV_OP 6'b000111 //SRAV指令码
`define EXE_SYNC_OP 6'b001111 //SYNC指令码
`define EXE_PREF_OP 6'b110011 //PREF指令码
`define EXE_SPECIAL_INST_OP 6'b000000 //SPECIAL指令码
//AluSe
`define EXE_RES_LOGIC 3'b001 //逻辑运算类型
`define EXE_RES_NOP 3'b000 //
`define EXE_RES_SHIFT 3'b010
测试指令
指令字 汇编指令 解释说明 执行后的结果(寄存器值)
34011100 ori $1,$0,0x1100 $0 or imm -> $1 $1 = 0x00001100
34210020 ori $1,$1,0x0020 $1 = 0x00001120
34214400 ori $1,$1,0x4400 $1 = 0x00005520
34210044 ori $1,$1,0x0044 $1 = 0x00005564
3c010101 lui $1,0x0101 imm -> $1 (high 16bit) low 16bit == 0 $1 = 0x01010000
34221010 ori $2,$1,0x1010 $2 = 0x01011010
00221825 or $3,$1,$2 $1 or $2 -> $3 $3 = 0x01011010
00431824 and $3,$3,$2 $2 and $3 -> $3 $3 = 0x01011010
3041ffff andi $1,$2,ffff $1 = 0x00001010
00231026 xor $2,$1,$3 $2 = 0x01010000
3843ff00 xori $3,$2,ff00 $3 = 0x0101ff00
000218c0 sll $3,$2,3 $3 = 0x08080000
00020882 srl $1,$2,2 $1 = 0x00404000
00611027 nor $2,$3,$1 $2 = 0xf7d7dfff
执行效果