blob: be8eb810bb664949524f4c30159d1502235d4021 [file] [log] [blame]
/*
*
* This file is part of the Elpis processor project.
*
* Copyright © 2020-present. All rights reserved.
* Authors: Aurora Tomas and Rodrigo Huerta.
*
* This file is licensed under both the BSD-3 license for individual/non-commercial
* use. Full text of both licenses can be found in LICENSE file.
*/
`default_nettype none
`ifdef TESTS
`include "elpis/definitions.v"
`else
`include "/project/openlane/user_proj_example/../../verilog/rtl/elpis/definitions.v"
`endif
module decoder(
input rst,
input[31:0] instr,
output reg[3:0] op_alu,
output reg wrd_reg,
output reg[4:0] addr_d,
output reg rb_immed, //rb (0) or immediate(1)
output reg[31:0] imm,
output reg mem_to_reg,
output reg wrd_mem,
output reg[2:0] branch_code,
output reg is_a_jump,
output reg is_byte,
output reg[1:0] is_mov,
output reg is_illegal,
output reg is_tlbwrite,
output reg is_iret,
output reg is_ecall,
output reg[6:0] io_code
);
wire[6:0] opcode = instr[6:0];
wire[4:0] reg_dest = instr[11:7];
wire[2:0] funct3 = instr[14:12];
wire[6:0] funct7 = instr[31:25];
wire[4:0] shamt = instr[24:20];
wire[11:0] ld_ali_immediate = instr[31:20];
wire[11:0] st_immediate = {instr[31:25], instr[11:7]};
wire[12:0] branch_inmediate = {instr[31], instr[7], instr[30:25], instr[11:8], 1'b0};
wire[19:0] jump_inmediate = {instr[31:20], instr[14:7]};
always@(*) begin
wrd_reg = 0;
wrd_mem = 0;
rb_immed = 0;
mem_to_reg = 0;
branch_code = `FUNCT3_BRANCH_NO;
is_a_jump = 0;
is_byte = 0;
is_mov = 0;
is_illegal = 0;
is_tlbwrite = 0;
is_iret = 0;
is_ecall = 0;
io_code = 7'b0;
op_alu = 0;
imm = 32'b0;
addr_d = 5'b0;
case(opcode)
`OPCODE_AL: begin
case(funct3)
`FUNCT3_OP_ADD_SUB: begin
addr_d = reg_dest;
if (instr != `NOP) begin
wrd_reg = 1;
end
case(funct7)
`FUNCT7_OP_ADD: begin
op_alu = `ALU_OP_ADD;
end
`FUNCT7_OP_SUB: begin
op_alu = `ALU_OP_SUB;
end
`FUNCT7_OP_MUL: begin
op_alu = `ALU_OP_MUL;
end
default: begin
is_illegal = 1;
wrd_reg = 0;
end
endcase
end
`FUNCT3_OP_OR: begin
addr_d = reg_dest;
wrd_reg = 1;
op_alu = `ALU_OP_OR;
end
`FUNCT3_OP_XOR: begin
addr_d = reg_dest;
wrd_reg = 1;
op_alu = `ALU_OP_XOR;
end
`FUNCT3_OP_AND: begin
addr_d = reg_dest;
wrd_reg = 1;
op_alu = `ALU_OP_AND;
end
`FUNCT3_OP_SLL: begin
addr_d = reg_dest;
wrd_reg = 1;
op_alu = `ALU_OP_SLL;
end
`FUNCT3_OP_SRL_SRA: begin
addr_d = reg_dest;
wrd_reg = 1;
case(funct7)
`FUNCT7_OP_SRL: begin
op_alu = `ALU_OP_SRL;
end
`FUNCT7_OP_SRA: begin
op_alu = `ALU_OP_SRA;
end
default: begin
wrd_reg = 0;
is_illegal = 1;
end
endcase
end
default:
is_illegal = 1;
endcase
end
`OPCODE_ALI: begin
rb_immed = 1;
addr_d = reg_dest;
wrd_reg = 1;
case(funct3)
`FUNCT3_OP_ADD_SUB: begin
imm = $signed(ld_ali_immediate);
op_alu = `ALU_OP_ADD;
end
`FUNCT3_OP_OR: begin
imm = $signed(ld_ali_immediate);
op_alu = `ALU_OP_OR;
end
`FUNCT3_OP_XOR: begin
imm = $signed(ld_ali_immediate);
op_alu = `ALU_OP_XOR;
end
`FUNCT3_OP_AND: begin
imm = $signed(ld_ali_immediate);
op_alu = `ALU_OP_AND;
end
`FUNCT3_OP_SLL: begin
imm = $signed(shamt);
op_alu = `ALU_OP_SLL;
end
`FUNCT3_OP_SRL_SRA: begin
imm = $signed(shamt);
case(funct7)
`FUNCT7_OP_SRL: begin
op_alu = `ALU_OP_SRL;
end
`FUNCT7_OP_SRA: begin
op_alu = `ALU_OP_SRA;
end
default: begin
wrd_reg = 0;
is_illegal = 1;
end
endcase
end
default: begin
is_illegal = 1;
wrd_reg = 0;
end
endcase
end
`OPCODE_LD: begin
wrd_reg = 1;
mem_to_reg = 1;
rb_immed = 1;
op_alu = `ALU_OP_ADD;
addr_d = reg_dest;
imm = $signed(ld_ali_immediate);
case (funct3)
`FUNCT3_OP_LB:
is_byte = 1;
`FUNCT3_OP_LW: begin
is_byte = 0;
end
default:
is_illegal = 1;
endcase
end
`OPCODE_ST: begin
wrd_mem = 1;
rb_immed = 1;
op_alu = `ALU_OP_ADD;
imm = $signed(st_immediate);
case (funct3)
`FUNCT3_OP_SB:
is_byte = 1;
`FUNCT3_OP_SW: begin
end
default:
is_illegal = 1;
endcase
end
`OPCODE_BRANCH: begin
op_alu = `ALU_OP_BRANCH;
rb_immed = 1;
imm = $signed(branch_inmediate);
branch_code = funct3;
case(funct3)
`FUNCT3_BRANCH_BEQ: begin
end
`FUNCT3_BRANCH_BNE: begin
end
`FUNCT3_BRANCH_BLT: begin
end
`FUNCT3_BRANCH_BGE: begin
end
default:
is_illegal = 1;
endcase
end
`OPCODE_JUMP: begin
is_a_jump = 1;
op_alu = `ALU_OP_BRANCH;
rb_immed = 1;
imm = $signed(jump_inmediate);
end
`OPCODE_MOV: begin
op_alu = `ALU_OP_ADD;
addr_d = reg_dest;
case(funct7)
`FUNCT7_MOV_RM_TO_REGULAR: begin
wrd_reg = 1;
is_mov = `MOV_RM_TO_REGULAR;
end
`FUNCT7_MOV_REGULAR_TO_RM: begin
is_mov = `MOV_REGULAR_TO_RM;
end
default:
is_illegal = 1;
endcase
end
`OPCODE_TLBWRITE: begin
op_alu = `ALU_OP_ADD;
is_tlbwrite = 1;
end
`OPCODE_IRET: begin
is_a_jump = 1;
is_iret = 1;
op_alu = `ALU_OP_ADD;
end
`OPCODE_ECALL: begin
imm = $signed(ld_ali_immediate);
rb_immed = 1;
is_ecall = 1;
op_alu = `ALU_OP_ADD;
end
`OPCODE_IO: begin
wrd_reg = 0;
case(funct7)
`FUNCT7_IO_PRINT_HEX: begin
io_code = `FUNCT7_IO_PRINT_HEX;
end
`FUNCT7_IO_READ_SW: begin
io_code = `FUNCT7_IO_READ_SW;
end
default:
is_illegal = 1;
endcase
end
default:
if (rst) is_illegal = 0;
else is_illegal = 1;
endcase
end
endmodule