blob: 684f95e5b34c0258647f2546284a8f644b3b0a82 [file] [log] [blame]
// SPDX-FileCopyrightText: 2022 Piotr Wegrzyn
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
`include "config.v"
module decode (
`ifdef USE_POWER_PINS
inout vccd1,
inout vssd1,
`endif
input wire i_clk,
input wire i_rst,
input [15:0] i_instr_l,
input [`I_SIZE-17:0] i_imm_pass,
output reg [`I_SIZE-17:0] o_imm_pass,
input i_jmp_pred_pass,
output reg o_jmp_pred_pass,
// Pipeline control
input i_next_ready,
input i_submit,
output o_ready,
output reg o_submit,
input i_flush,
output reg oc_pc_inc, oc_pc_ie,
output reg oc_r_bus_imm,
output reg [`ALU_MODE_W-1:0] oc_alu_mode,
output reg oc_alu_carry_en, oc_alu_flags_ie,
output reg [`REGNO_LOG-1:0] oc_l_reg_sel, oc_r_reg_sel,
output reg [`REGNO-1:0] oc_rf_ie,
output reg [`JUMP_CODE_W-1:0] oc_jump_cond_code,
output reg oc_mem_access, oc_mem_we, oc_mem_width,
output reg [1:0] oc_used_operands,
output reg oc_sreg_load, oc_sreg_store, oc_sreg_jal_over, oc_sreg_irt, oc_sys,
output reg oc_mem_long,
output dbg_out
);
// COMBINATIONAL INSTRUCTION DECODER
`define OPC_NOP 7'h00
`define OPC_MOV 7'h01
`define OPC_LDD 7'h02
`define OPC_LDO 7'h03
`define OPC_LDI 7'h04
`define OPC_STD 7'h05
`define OPC_STO 7'h06
`define OPC_ADD 7'h07
`define OPC_ADI 7'h08
`define OPC_ADC 7'h09
`define OPC_SUB 7'h0a
`define OPC_SUC 7'h0b
`define OPC_CMP 7'h0c
`define OPC_CMI 7'h0d
`define OPC_JMP 7'h0e
`define OPC_JAL 7'h0f
`define OPC_SRL 7'h10
`define OPC_SRS 7'h11
`define OPC_SYS 7'h12
`define OPC_AND 7'h13
`define OPC_ORR 7'h14
`define OPC_XOR 7'h15
`define OPC_ANI 7'h16
`define OPC_ORI 7'h17
`define OPC_XOI 7'h18
`define OPC_SHL 7'h19
`define OPC_SHR 7'h1a
`define OPC_CAI 7'h1b
`define OPC_MUL 7'h1c // Temporary instructions (MUL,DIV) to be removed after compiler patch
`define OPC_DIV 7'h1d
`define OPC_IRT 7'h1e
`define OPC_LD8 7'h1f
`define OPC_LO8 7'h20
`define OPC_SD8 7'h21
`define OPC_SO8 7'h22
`define OPC_SLI 7'h23
`define OPC_SRI 7'h24
`define OPC_SAR 7'h25
`define OPC_SAI 7'h26
`define OPC_SEX 7'h27
`define OPC_LLO 7'h28
`define OPC_SLO 7'h29
`define OPC_LL8 7'h2a
`define OPC_SL8 7'h2b
`define OPC_MOD 7'h2c
// sreg imm??
wire [6:0] opcode = i_instr_l[6:0];
wire [2:0] reg_dst = i_instr_l[9:7];
wire [2:0] reg_st = i_instr_l[12:10];
wire [2:0] reg_nd = i_instr_l[15:13];
// Comb output signals
reg c_pc_inc, c_pc_ie;
reg c_r_bus_imm;
reg [`ALU_MODE_W-1:0] c_alu_mode;
reg c_alu_carry_en, c_alu_flags_ie;
reg [`REGNO_LOG-1:0] c_l_reg_sel, c_r_reg_sel;
reg [`REGNO-1:0] c_rf_ie;
reg [`JUMP_CODE_W-1:0] c_jump_cond_code;
reg c_mem_access, c_mem_we, c_mem_width;
reg [1:0] c_used_operands;
reg c_sreg_load, c_sreg_store, c_sreg_jal_over, c_sreg_irt, c_sys, c_mem_long;
always @(*) begin
// defaults
c_pc_inc = 1'b1;
{c_pc_ie, c_r_bus_imm, c_alu_carry_en, c_alu_flags_ie, c_mem_access,
c_mem_we, c_sreg_load, c_sreg_store, c_sreg_jal_over, c_sreg_irt, c_sys, c_mem_width, c_mem_long} = 13'b0;
c_rf_ie = `REGNO'b0;
c_alu_mode = `ALU_MODE_W'b0;
c_l_reg_sel = `REGNO_LOG'b0;
c_r_reg_sel = `REGNO_LOG'b0;
c_jump_cond_code = `JUMP_CODE_W'b0;
c_used_operands = 2'b0;
case (opcode)
`OPC_NOP: begin
end
`OPC_MOV: begin
c_alu_mode = `ALU_MODE_L_PASS;
c_l_reg_sel = reg_st;
c_rf_ie[reg_dst] = 1'b1;
c_used_operands = 2'b01;
end
`OPC_LDD: begin
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_R_PASS;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
end
`OPC_LDO: begin
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
c_used_operands = 2'b01;
end
`OPC_LDI: begin
c_alu_mode = `ALU_MODE_R_PASS;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
end
`OPC_STD: begin
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_R_PASS;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_used_operands = 2'b10;
end
`OPC_STO: begin
c_l_reg_sel = reg_nd;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_used_operands = 2'b11;
end
`OPC_ADD: begin
c_alu_mode = `ALU_MODE_ADD;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_ADI: begin
c_alu_mode = `ALU_MODE_ADD;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_ADC: begin
c_alu_mode = `ALU_MODE_ADD;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_alu_carry_en = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_SUB: begin
c_alu_mode = `ALU_MODE_SUB;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_SUC: begin
c_alu_mode = `ALU_MODE_SUB;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_r_bus_imm = 1'b1;
c_alu_carry_en = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_CMP: begin
c_alu_mode = `ALU_MODE_SUB;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_CMI: begin
c_alu_mode = `ALU_MODE_SUB;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_JMP: begin
// NOTE: Conditional jumps are decoded in execute stage
// to not unnecessarily stall the pipeline each time prediction
// is taken
c_pc_inc = 1'b0;
c_pc_ie = 1'b0;
c_alu_mode = `ALU_MODE_R_PASS;
c_r_bus_imm = 1'b1;
c_jump_cond_code = {1'b1, i_instr_l[10:7]};
end
`OPC_JAL: begin
c_pc_ie = 1'b0;
c_pc_inc = 1'b0;
c_alu_mode = `ALU_MODE_R_PASS;
c_r_bus_imm = 1'b1;
c_sreg_jal_over = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
// set jump code to unconditional jump, pred is set by fetch
c_jump_cond_code = {1'b1, 4'b0};
end
`OPC_SRL: begin
c_sreg_load = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
end
`OPC_SRS: begin
c_r_reg_sel = reg_st;
c_sreg_store = 1'b1;
c_used_operands = 2'b10;
end
`OPC_AND: begin
c_alu_mode = `ALU_MODE_AND;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_ORR: begin
c_alu_mode = `ALU_MODE_OR;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_XOR: begin
c_alu_mode = `ALU_MODE_XOR;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_ANI: begin
c_alu_mode = `ALU_MODE_AND;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_ORI: begin
c_alu_mode = `ALU_MODE_OR;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_XOI: begin
c_alu_mode = `ALU_MODE_XOR;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_SHL: begin
c_alu_mode = `ALU_MODE_SHL;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_SHR: begin
c_alu_mode = `ALU_MODE_SHR;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_CAI: begin
c_alu_mode = `ALU_MODE_AND;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_MUL: begin
c_alu_mode = `ALU_MODE_MUL;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_used_operands = 2'b11;
end
`OPC_DIV: begin
c_alu_mode = `ALU_MODE_DIV;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_used_operands = 2'b11;
end
`OPC_SYS: begin
c_sys = 1'b1;
end
`OPC_IRT: begin
c_sreg_irt = 1'b1;
c_pc_ie = 1'b0;
c_pc_inc = 1'b0;
end
`OPC_LD8: begin
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_R_PASS;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
c_mem_width = 1'b1;
end
`OPC_LO8: begin
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
c_used_operands = 2'b01;
c_mem_width = 1'b1;
end
`OPC_SD8: begin
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_R_PASS;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_used_operands = 2'b10;
c_mem_width = 1'b1;
end
`OPC_SO8: begin
c_l_reg_sel = reg_nd;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_used_operands = 2'b11;
c_mem_width = 1'b1;
end
`OPC_SLI: begin
c_alu_mode = `ALU_MODE_SHL;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_SRI: begin
c_alu_mode = `ALU_MODE_SHR;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_SAR: begin
c_alu_mode = `ALU_MODE_ASHR;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b11;
end
`OPC_SAI: begin
c_alu_mode = `ALU_MODE_ASHR;
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_SEX: begin
c_alu_mode = `ALU_MODE_SEXT;
c_l_reg_sel = reg_st;
c_rf_ie[reg_dst] = 1'b1;
c_alu_flags_ie = 1'b1;
c_used_operands = 2'b01;
end
`OPC_LLO: begin
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
c_mem_long = 1'b1;
c_used_operands = 2'b01;
end
`OPC_SLO: begin
c_l_reg_sel = reg_nd;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_mem_long = 1'b1;
c_used_operands = 2'b11;
end
`OPC_LL8: begin
c_l_reg_sel = reg_st;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_rf_ie[reg_dst] = 1'b1;
c_mem_access = 1'b1;
c_used_operands = 2'b01;
c_mem_long = 1'b1;
c_mem_width = 1'b1;
end
`OPC_SL8: begin
c_l_reg_sel = reg_nd;
c_r_bus_imm = 1'b1;
c_alu_mode = `ALU_MODE_ADD;
c_r_reg_sel = reg_st;
c_mem_access = 1'b1;
c_mem_we = 1'b1;
c_used_operands = 2'b11;
c_mem_long = 1'b1;
c_mem_width = 1'b1;
end
`OPC_MOD: begin
c_alu_mode = `ALU_MODE_MOD;
c_l_reg_sel = reg_st;
c_r_reg_sel = reg_nd;
c_rf_ie[reg_dst] = 1'b1;
c_used_operands = 2'b11;
end
default: begin
end
endcase
end
// PIPELINE WRAPPER
reg input_valid;
// ready signal must be combinational to be registered on time by previous stage
assign o_ready = i_next_ready & ~input_valid;
always @(posedge i_clk) begin
if(i_rst) begin
o_submit <= 1'b0;
input_valid <= 1'b0;
// default values for control signals at reset not zzz. Later delete it and catch bugs with load of zzz without exec_submit at gl tests
oc_pc_inc = 1'b0;
{oc_pc_ie, oc_r_bus_imm, oc_alu_carry_en, oc_alu_flags_ie, oc_mem_access,
oc_mem_we, oc_sreg_load, oc_sreg_store, oc_sreg_jal_over, oc_sreg_irt, oc_sys, oc_mem_width, oc_mem_long} = 13'b0;
oc_rf_ie = `REGNO'b0;
oc_alu_mode = `ALU_MODE_W'b0;
oc_l_reg_sel = `REGNO_LOG'b0;
oc_r_reg_sel = `REGNO_LOG'b0;
oc_jump_cond_code = `JUMP_CODE_W'b0;
oc_used_operands = 2'b0;
end else begin
// default bubble
o_submit <= 1'b0;
if (i_next_ready & (i_submit | input_valid) & ~i_flush) begin
o_submit <= 1'b1;
input_valid <= 1'b0;
o_imm_pass <= i_imm_pass;
o_jmp_pred_pass <= i_jmp_pred_pass;
// Submit control signals
oc_pc_inc <= c_pc_inc;
oc_pc_ie <= c_pc_ie;
oc_r_bus_imm <= c_r_bus_imm;
oc_alu_carry_en <= c_alu_carry_en;
oc_alu_flags_ie <= c_alu_flags_ie;
oc_rf_ie <= c_rf_ie;
oc_alu_mode <= c_alu_mode;
oc_l_reg_sel <= c_l_reg_sel;
oc_r_reg_sel <= c_r_reg_sel;
oc_jump_cond_code <= c_jump_cond_code;
oc_mem_access <= c_mem_access;
oc_mem_we <= c_mem_we;
oc_mem_width <= c_mem_width;
oc_used_operands <= c_used_operands;
oc_sreg_load <= c_sreg_load;
oc_sreg_store <= c_sreg_store;
oc_sreg_jal_over <= c_sreg_jal_over;
oc_sreg_irt <= c_sreg_irt;
oc_sys <= c_sys;
oc_mem_long <= c_mem_long;
end
if (i_submit & ~i_next_ready & ~i_flush) begin
input_valid <= 1'b1; // don't overwrite buffer
end
if (i_flush) begin
o_submit <= 1'b0;
input_valid <= 1'b0;
end
end
end
assign dbg_out = o_ready;
endmodule