Files
learnFPGAProject/RTL/Attic/mini_decoder.v
2025-11-27 04:28:54 +03:00

189 lines
7.5 KiB
Verilog

/********************* Instruction decoder *******************************/
// A drop-in replacement of the instruction decoder, meant to further
// reduce LUT count by not checking for errors.
// Optimized by @mecrisp
// in femtorv32.v, replace `include "decoder.v"
// with `include "mini_decoder.v"
// (does not seem to save many LUTs with my version of YOSYS, but it depends).
// NOTE: the structure of the decoder has changed, *** NEEDS TO BE ADAPTED ***
module NrvDecoder(
input wire [31:0] instr,
output wire [4:0] writeBackRegId,
output reg writeBackEn,
output reg [3:0] writeBackSel, // 0001: ALU 0010: PC+4 0100: RAM 1000: counters
// (could use 2 wires instead, but using 4 wires (1-hot encoding)
// reduces both LUT count and critical path in the end !)
output wire [4:0] inRegId1,
output wire [4:0] inRegId2,
output reg aluSel, // 0: force aluOp,aluQual to zero (ADD) 1: use aluOp,aluQual from instr field
output reg aluInSel1, // 0: reg 1: pc
output reg aluInSel2, // 0: reg 1: imm
output [2:0] aluOp,
output reg aluQual,
output wire aluM, // Asserted if operation is an RV32M operation
output reg isLoad,
output reg isStore,
output reg isJump,
output reg isBranch,
output reg needWaitALU,
output reg [31:0] imm,
output wire error
);
assign error = 1'b0; // We do not check for errors in the MiniDecoder.
assign aluM = 1'b0; // MiniDecoder only works for RV32I
reg inRegId1Sel; // 0: force inRegId1 to zero 1: use inRegId1 instr field
assign writeBackRegId = instr[11:7];
assign inRegId1 = instr[19:15] & {5{inRegId1Sel}}; // Internal sig InRegId1Sel used to force zero in reg1
assign inRegId2 = instr[24:20]; // (because I'm making maximum reuse of the adder of the ALU)
assign aluOp = instr[14:12];
wire [31:0] Iimm = {{21{instr[31]}}, instr[30:20]};
wire [31:0] Simm = {{21{instr[31]}}, instr[30:25], instr[11:7]};
wire [31:0] Bimm = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
wire [31:0] Jimm = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
wire [31:0] Uimm = {instr[31], instr[30:12], {12{1'b0}}};
// The rest of instruction decoding, for the following signals:
// writeBackEn
// writeBackSel 0001: ALU 0010: PC+4 0100: RAM 1000: counters
// inRegId1Sel 0: zero 1: regId
// aluInSel1 0: reg 1: PC
// aluInSel2 0: reg 1: imm
// aluQual +/- SRLI/SRAI
// aluM 1 if instr is RV32M
// aluSel 0: force aluOp,aluQual=00 1: use aluOp/aluQual
// nextPCSel 001: PC+4 010: ALU 100: (pred ? ALU : PC+4)
// imm (select one of Iimm,Simm,Bimm,Jimm,Uimm)
// We need to distingish shifts for two reasons:
// - We need to wait for ALU when it is a shift
// - For ALU ops with immediates, aluQual is 0, except
// for shifts (then it is instr[30]).
wire aluOpIsShift = (aluOp == 3'b001) || (aluOp == 3'b101);
always @(*) begin
inRegId1Sel = 1'b1; // reg 1 Id from instr
isLoad = 1'b0;
isStore = 1'b0;
isJump = 1'b0;
isBranch = 1'b0;
aluQual = 1'b0;
needWaitALU = 1'b0;
(* parallel_case, full_case *)
casez(instr[6:2])
5'b011?1: begin // LUI
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0001; // write back source = ALU
inRegId1Sel = 1'b0; // reg 1 Id = 0
aluInSel1 = 1'b0; // ALU source 1 = reg
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
imm = Uimm; // imm format = U
end
5'b001?1: begin // AUIPC
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0001; // write back source = ALU
inRegId1Sel = 1'bx; // reg 1 Id : don't care (we use PC)
aluInSel1 = 1'b1; // ALU source 1 = PC
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
imm = Uimm; // imm format = U
end
5'b11011: begin // JAL
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0010; // write back source = PC+4
inRegId1Sel = 1'bx; // reg 1 Id : don't care (we use PC)
aluInSel1 = 1'b1; // ALU source 1 = PC
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
isJump = 1'b1; // PC <- ALU
imm = Jimm; // imm format = J
end
5'b11001: begin // JALR
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0010; // write back source = PC+4
aluInSel1 = 1'b0; // ALU source 1 = reg
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
isJump = 1'b1; // PC <- ALU
imm = Iimm; // imm format = I
end
5'b110?0: begin // Branch
writeBackEn = 1'b0; // disable write back
writeBackSel = 4'bxxxx; // write back source = don't care
aluInSel1 = 1'b1; // ALU source 1 : PC
aluInSel2 = 1'b1; // ALU source 2 : imm
aluSel = 1'b0; // ALU op = ADD
isBranch = 1'b1; // PC <- pred ? ALU : PC+4
imm = Bimm; // imm format = B
end
5'b001?0: begin // ALU operation: Register,Immediate
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0001; // write back source = ALU
aluInSel1 = 1'b0; // ALU source 1 : reg
aluInSel2 = 1'b1; // ALU source 2 : imm
// Qualifier for ALU op: SRLI/SRAI
aluQual = aluOpIsShift ? instr[30] : 1'b0;
needWaitALU = aluOpIsShift;
aluSel = 1'b1; // ALU op : from instr
imm = Iimm; // imm format = I
end
5'b011?0: begin // ALU operation: Register,Register
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0001; // write back source = ALU
aluInSel1 = 1'b0; // ALU source 1 : reg
aluInSel2 = 1'b0; // ALU source 2 : reg
aluQual = instr[30]; // Qualifier for ALU op: +/- SRL/SRA
aluSel = 1'b1; // ALU op : from instr
needWaitALU = aluOpIsShift;
imm = 32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; // don't care
end
5'b000?0: begin // Load
writeBackEn = 1'b1; // enable write back
writeBackSel = 4'b0100; // write back source = RAM
aluInSel1 = 1'b0; // ALU source 1 = reg
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
imm = Iimm; // imm format = I
isLoad = 1'b1;
end
5'b010?0: begin // Store
writeBackEn = 1'b0; // disable write back
writeBackSel = 4'bxxxx; // write back sel = don't care
aluInSel1 = 1'b0; // ALU source 1 = reg
aluInSel2 = 1'b1; // ALU source 2 = imm
aluSel = 1'b0; // ALU op = ADD
imm = Simm; // imm format = S
isStore = 1'b1;
end
default: begin
writeBackEn = 1'b0;
writeBackSel = 4'bxxxx;
inRegId1Sel = 1'bx;
aluInSel1 = 1'bx;
aluInSel2 = 1'bx;
aluSel = 1'bx;
imm = 32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
end
endcase
end
endmodule