<commit_before>// Copyright 2015 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.

////////////////////////////////////////////////////////////////////////////////
// Engineer        <NAME> - <EMAIL>                    //
//                                                                            //
// Additional contributions by:                                               //
//                 <NAME> - <EMAIL>                   //
//                 <NAME> - <EMAIL>                               //
//                 <NAME> - <EMAIL>                     //
//                                                                            //
// Design Name:    Decoder                                                    //
// Project Name:   RI5CY                                                      //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    Decoder                                                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

`include "riscv_defines.sv"

module riscv_decoder
(
  // singals running to/from controller
  input  logic        deassert_we_i,           // deassert we, we are stalled or not active
  input  logic        data_misaligned_i,       // misaligned data load/store in progress

  output logic        illegal_insn_o,          // illegal instruction encountered
  output logic        trap_insn_o,             // trap instruction encountered
  output logic        eret_insn_o,             // return from exception instruction encountered
  output logic        ecall_insn_o,            // environment call (syscall) instruction encountered
  output logic        pipe_flush_o,            // pipeline flush is requested

  output logic        rega_used_o,             // rs1 is used by current instruction
  output logic        regb_used_o,             // rs2 is used by current instruction
  output logic        regc_used_o,             // rs3 is used by current instruction

  output logic        imm_bmask_needed_o,      // immediate registers for bit manipulation mask is needed

  // from IF/ID pipeline
  input  logic [31:0] instr_rdata_i,           // instruction read from instr memory/cache
  input  logic        illegal_c_insn_i,        // compressed instruction decode failed

  // ALU signals
  output logic [`ALU_OP_WIDTH-1:0] alu_operator_o, // ALU operation selection
  output logic [1:0]  alu_op_a_mux_sel_o,      // operand a selection: reg value, PC, immediate or zero
  output logic [1:0]  alu_op_b_mux_sel_o,      // operand b selection: reg value or immediate
  output logic [1:0]  alu_op_c_mux_sel_o,      // operand c selection: reg value or jump target
  output logic [1:0]  alu_vec_mode_o,          // selects between 32 bit, 16 bit and 8 bit vectorial modes
  output logic        scalar_replication_o,    // scalar replication enable
  output logic [2:0]  immediate_mux_sel_o,     // immediate selection for operand b
  output logic [1:0]  regc_mux_o,              // register c selection: S3, RD or 0

  // MUL related control signals
  output logic        mult_en_o,               // perform multiplication
  output logic        mult_mac_en_o,           // accumulate multiplication result
  output logic [1:0]  mult_sel_subword_o,      // Select subwords for 16x16 bit of multiplier
  output logic [1:0]  mult_signed_mode_o,      // Multiplication in signed mode
  output logic        mult_vec_mode_o,         // selects between 32 bit and 16 bit modes

  // register file related signals
  output logic        regfile_mem_we_o,        // write enable for regfile
  output logic        regfile_alu_we_o,        // write enable for 2nd regfile port
  output logic        regfile_alu_waddr_sel_o, // Select register write address for ALU/MUL operations

  // CSR manipulation
  output logic        csr_access_o,            // access to CSR
  output logic [1:0]  csr_op_o,                // operation to perform on CSR

  // LD/ST unit signals
  output logic        data_req_o,              // start transaction to data memory
  output logic        data_we_o,               // data memory write enable
  output logic        prepost_useincr_o,       // when not active bypass the alu result for address calculation
  output logic [1:0]  data_type_o,             // data type on data memory: byte, half word or word
  output logic        data_sign_extension_o,   // sign extension on read data from data memory
  output logic [1:0]  data_reg_offset_o,       // offset in byte inside register for stores
  output logic        data_load_event_o,       // data request is in the special event range

  // hwloop signals
  output logic [2:0]  hwloop_we_o,             // write enable for hwloop regs
  output logic        hwloop_target_mux_sel_o, // selects immediate for hwloop target
  output logic        hwloop_start_mux_sel_o,  // selects hwloop start address input
  output logic        hwloop_cnt_mux_sel_o,    // selects hwloop counter input

  // jump/branches
  output logic [1:0]  jump_in_dec_o,           // jump_in_id without deassert
  output logic [1:0]  jump_in_id_o,            // jump is being calculated in ALU
  output logic [1:0]  jump_target_mux_sel_o    // jump target selection
);

  // write enable/request control
  logic       regfile_mem_we;
  logic       regfile_alu_we;
  logic       data_req;
  logic [2:0] hwloop_we;

  logic       trap_insn;
  logic       eret_insn;
  logic       pipe_flush;

  logic [1:0] jump_in_id;

  logic       mult_en;
  logic       mult_mac_en;
  logic [1:0] csr_op;


  /////////////////////////////////////////////
  //   ____                     _            //
  //  |  _ \  ___  ___ ___   __| | ___ _ __  //
  //  | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| //
  //  | |_| |  __/ (_| (_) | (_| |  __/ |    //
  //  |____/ \___|\___\___/ \__,_|\___|_|    //
  //                                         //
  /////////////////////////////////////////////

  always_comb
  begin
    jump_in_id                  = `BRANCH_NONE;
    jump_target_mux_sel_o       = `JT_JAL;

    alu_operator_o              = `ALU_SLTU;
    alu_op_a_mux_sel_o          = `OP_A_REGA_OR_FWD;
    alu_op_b_mux_sel_o          = `OP_B_REGB_OR_FWD;
    alu_op_c_mux_sel_o          = `OP_C_REGC_OR_FWD;
    alu_vec_mode_o              = `VEC_MODE32;
    scalar_replication_o        = 1'b0;
    regc_mux_o                  = `REGC_ZERO;
    immediate_mux_sel_o         = `IMM_I;

    mult_en                     = 1'b0;
    mult_signed_mode_o          = 2'b00;
    mult_sel_subword_o          = 2'b00;
    mult_mac_en                 = 1'b0;
    mult_vec_mode_o             = 1'b0;

    regfile_mem_we              = 1'b0;
    regfile_alu_we              = 1'b0;
    regfile_alu_waddr_sel_o     = 1'b1;

    prepost_useincr_o           = 1'b1;

    hwloop_we                   = 3'b0;
    hwloop_target_mux_sel_o     = 1'b0;
    hwloop_start_mux_sel_o      = 1'b0;
    hwloop_cnt_mux_sel_o        = 1'b0;

    csr_access_o                = 1'b0;
    csr_op                      = `CSR_OP_NONE;

    data_we_o                   = 1'b0;
    data_type_o                 = 2'b00;
    data_sign_extension_o       = 1'b0;
    data_reg_offset_o           = 2'b00;
    data_req                    = 1'b0;
    data_load_event_o           = 1'b0;

    illegal_insn_o              = 1'b0;
    trap_insn                   = 1'b0;
    eret_insn                   = 1'b0;
    ecall_insn_o                = 1'b0;
    pipe_flush                  = 1'b0;

    rega_used_o                 = 1'b0;
    regb_used_o                 = 1'b0;
    regc_used_o                 = 1'b0;
    imm_bmask_needed_o          = 1'b0;


    unique case (instr_rdata_i[6:0])

      //////////////////////////////////////
      //      _ _   _ __  __ ____  ____   //
      //     | | | | |  \/  |  _ \/ ___|  //
      //  _  | | | | | |\/| | |_) \___ \  //
      // | |_| | |_| | |  | |  __/ ___) | //
      //  \___/ \___/|_|  |_|_|   |____/  //
      //                                  //
      //////////////////////////////////////

      `OPCODE_JAL: begin   // Jump and Link
        jump_target_mux_sel_o = `JT_JAL;
        jump_in_id            = `BRANCH_JAL;
        // Calculate and store PC+4
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_PCINCR;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
        // Calculate jump target (= PC + UJ imm)
      end

      `OPCODE_JALR: begin  // Jump and Link Register
        jump_target_mux_sel_o = `JT_JALR;
        jump_in_id            = `BRANCH_JALR;
        // Calculate and store PC+4
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_PCINCR;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
        // Calculate jump target (= RS1 + I imm)
        rega_used_o         = 1'b1;

        if (instr_rdata_i[14:12] != 3'b0) begin
          jump_in_id       = `BRANCH_NONE;
          regfile_alu_we   = 1'b0;
          illegal_insn_o   = 1'b0;
        end
      end

      `OPCODE_BRANCH: begin // Branch
        jump_target_mux_sel_o = `JT_COND;
        jump_in_id            = `BRANCH_COND;
        alu_op_c_mux_sel_o    = `OP_C_JT;
        rega_used_o           = 1'b1;
        regb_used_o           = 1'b1;

        unique case (instr_rdata_i[14:12])
          3'b000: alu_operator_o = `ALU_EQ;
          3'b001: alu_operator_o = `ALU_NE;
          3'b100: alu_operator_o = `ALU_LTS;
          3'b101: alu_operator_o = `ALU_GES;
          3'b110: alu_operator_o = `ALU_LTU;
          3'b111: alu_operator_o = `ALU_GEU;
          3'b010: alu_operator_o = `ALU_EQALL;

          default: begin
            illegal_insn_o = 1'b1;
          end
        endcase
      end


      //////////////////////////////////
      //  _     ____    ______ _____  //
      // | |   |  _ \  / / ___|_   _| //
      // | |   | | | |/ /\___ \ | |   //
      // | |___| |_| / /  ___) || |   //
      // |_____|____/_/  |____/ |_|   //
      //                              //
      //////////////////////////////////

      `OPCODE_STORE,
      `OPCODE_STORE_POST: begin
        data_req       = 1'b1;
        data_we_o      = 1'b1;
        rega_used_o    = 1'b1;
        regb_used_o    = 1'b1;
        alu_operator_o = `ALU_ADD;

        // pass write data through ALU operand c
        alu_op_c_mux_sel_o = `OP_C_REGB_OR_FWD;

        // post-increment setup
        if (instr_rdata_i[6:0] == `OPCODE_STORE_POST) begin
          prepost_useincr_o       = 1'b0;
          regfile_alu_waddr_sel_o = 1'b0;
          regfile_alu_we          = 1'b1;
        end

        if (instr_rdata_i[14] == 1'b0) begin
          // offset from immediate
          immediate_mux_sel_o = `IMM_S;
          alu_op_b_mux_sel_o  = `OP_B_IMM;
        end else begin
          // offset from register
          regc_used_o        = 1'b1;
          alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
          regc_mux_o         = `REGC_S3;
        end

        // store size
        unique case (instr_rdata_i[13:12])
          2'b00: data_type_o = 2'b10; // SB
          2'b01: data_type_o = 2'b01; // SH
          2'b10: data_type_o = 2'b00; // SW
          default: begin
            data_req       = 1'b0;
            data_we_o      = 1'b0;
            illegal_insn_o = 1'b1;
          end
        endcase
      end

      `OPCODE_LOAD,
      `OPCODE_LOAD_POST: begin
        data_req        = 1'b1;
        regfile_mem_we  = 1'b1;
        rega_used_o     = 1'b1;
        data_type_o     = 2'b00;

        // offset from immediate
        alu_operator_o      = `ALU_ADD;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_I;

        // post-increment setup
        if (instr_rdata_i[6:0] == `OPCODE_LOAD_POST) begin
          prepost_useincr_o       = 1'b0;
          regfile_alu_waddr_sel_o = 1'b0;
          regfile_alu_we          = 1'b1;
        end

        // sign/zero extension
        data_sign_extension_o = ~instr_rdata_i[14];

        // load size
        unique case (instr_rdata_i[13:12])
          2'b00:   data_type_o = 2'b10; // LB
          2'b01:   data_type_o = 2'b01; // LH
          2'b10:   data_type_o = 2'b00; // LW
          default: data_type_o = 2'b00; // illegal or reg-reg
        endcase

        // reg-reg load (different encoding)
        if (instr_rdata_i[14:12] == 3'b111) begin
          // offset from RS2
          regb_used_o        = 1'b1;
          alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD;

          // sign/zero extension
          data_sign_extension_o = ~instr_rdata_i[30];

          // load size
          unique case (instr_rdata_i[31:25])
            7'b0000_000,
            7'b0100_000: data_type_o = 2'b10; // LB, LBU
            7'b0001_000,
            7'b0101_000: data_type_o = 2'b01; // LH, LHU
            7'b0010_000: data_type_o = 2'b00; // LW
            default: begin
              data_type_o    = 2'b00;
              // illegal instruction
              data_req       = 1'b0;
              regfile_mem_we = 1'b0;
              regfile_alu_we = 1'b0;
              illegal_insn_o = 1'b1;
            end
          endcase
        end

        // special p.elw (event load)
        if (instr_rdata_i[14:12] == 3'b110)
          data_load_event_o = 1'b1;

        if (instr_rdata_i[14:12] == 3'b011) begin
          // LD -> RV64 only
          illegal_insn_o = 1'b1;
        end
      end


      //////////////////////////
      //     _    _    _   _  //
      //    / \  | |  | | | | //
      //   / _ \ | |  | | | | //
      //  / ___ \| |__| |_| | //
      // /_/   \_\_____\___/  //
      //                      //
      //////////////////////////

      `OPCODE_LUI: begin  // Load Upper Immediate
        alu_op_a_mux_sel_o  = `OP_A_ZERO;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_U;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
      end

      `OPCODE_AUIPC: begin  // Add Upper Immediate to PC
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_U;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
      end

      `OPCODE_OPIMM: begin // Register-Immediate ALU Operations
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_I;
        regfile_alu_we      = 1'b1;
        rega_used_o         = 1'b1;

        unique case (instr_rdata_i[14:12])
          3'b000: alu_operator_o = `ALU_ADD;  // Add Immediate
          3'b010: alu_operator_o = `ALU_SLTS; // Set to one if Lower Than Immediate
          3'b011: alu_operator_o = `ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
          3'b100: alu_operator_o = `ALU_XOR;  // Exclusive Or with Immediate
          3'b110: alu_operator_o = `ALU_OR;   // Or with Immediate
          3'b111: alu_operator_o = `ALU_AND;  // And with Immediate

          3'b001: begin
            alu_operator_o = `ALU_SLL;  // Shift Left Logical by Immediate
            if (instr_rdata_i[31:25] != 7'b0)
              illegal_insn_o = 1'b1;
          end

          3'b101: begin
            if (instr_rdata_i[31:25] == 7'b0)
              alu_operator_o = `ALU_SRL;  // Shift Right Logical by Immediate
            else if (instr_rdata_i[31:25] == 7'b010_0000)
              alu_operator_o = `ALU_SRA;  // Shift Right Arithmetically by Immediate
            else
              illegal_insn_o = 1'b1;
          end

          default: illegal_insn_o = 1'b1;
        endcase
      end

      `OPCODE_OP: begin  // Register-Register ALU operation
        regfile_alu_we = 1'b1;
        rega_used_o    = 1'b1;

        if (instr_rdata_i[31]) begin
          // bit-manipulation instructions
          alu_op_b_mux_sel_o  = `OP_B_IMM;
          imm_bmask_needed_o  = 1'b1;

          unique case (instr_rdata_i[14:12])
            3'b000: begin alu_operator_o = `ALU_BEXT;  immediate_mux_sel_o = `IMM_S2; end
            3'b001: begin alu_operator_o = `ALU_BEXTU; immediate_mux_sel_o = `IMM_S2; end
            3'b010: begin
              alu_operator_o      = `ALU_BINS;
              immediate_mux_sel_o = `IMM_S2;
              regc_used_o         = 1'b1;
              regc_mux_o          = `REGC_RD;
            end

            3'b011: begin alu_operator_o = `ALU_BCLR; end
            3'b100: begin alu_operator_o = `ALU_BSET; end

            default: illegal_insn_o = 1'b1;
          endcase
        end
        else
        begin // non bit-manipulation instructions

          if (~instr_rdata_i[28])
            regb_used_o = 1'b1;

          unique case ({instr_rdata_i[30:25], instr_rdata_i[14:12]})
            // RV32I ALU operations
            {6'b00_0000, 3'b000}: alu_operator_o = `ALU_ADD;   // Add
            {6'b10_0000, 3'b000}: alu_operator_o = `ALU_SUB;   // Sub
            {6'b00_0000, 3'b010}: alu_operator_o = `ALU_SLTS;  // Set Lower Than
            {6'b00_0000, 3'b011}: alu_operator_o = `ALU_SLTU;  // Set Lower Than Unsigned
            {6'b00_0000, 3'b100}: alu_operator_o = `ALU_XOR;   // Xor
            {6'b00_0000, 3'b110}: alu_operator_o = `ALU_OR;    // Or
            {6'b00_0000, 3'b111}: alu_operator_o = `ALU_AND;   // And
            {6'b00_0000, 3'b001}: alu_operator_o = `ALU_SLL;   // Shift Left Logical
            {6'b00_0000, 3'b101}: alu_operator_o = `ALU_SRL;   // Shift Right Logical
            {6'b10_0000, 3'b101}: alu_operator_o = `ALU_SRA;   // Shift Right Arithmetic

            // supported RV32M instructions
            {6'b00_0001, 3'b000}: mult_en      = 1'b1;       // Multiplication
            {6'b00_0001, 3'b001}: begin // MAC
              regc_used_o  = 1'b1;
              regc_mux_o   = `REGC_RD;
              mult_en      = 1'b1;
              mult_mac_en  = 1'b1;
            end

            // PULP specific instructions
            {6'b00_0010, 3'b000}: alu_operator_o = `ALU_AVG;   // Average
            {6'b00_0010, 3'b001}: alu_operator_o = `ALU_AVGU;  // Average Unsigned
            {6'b00_0010, 3'b010}: alu_operator_o = `ALU_SLETS; // Set Lower Equal Than
            {6'b00_0010, 3'b011}: alu_operator_o = `ALU_SLETU; // Set Lower Equal Than Unsigned
            {6'b00_0010, 3'b100}: alu_operator_o = `ALU_MIN;   // Min
            {6'b00_0010, 3'b101}: alu_operator_o = `ALU_MINU;  // Min Unsigned
            {6'b00_0010, 3'b110}: alu_operator_o = `ALU_MAX;   // Max
            {6'b00_0010, 3'b111}: alu_operator_o = `ALU_MAXU;  // Max Unsigned

            {6'b00_0100, 3'b101}: alu_operator_o = `ALU_ROR;   // Rotate Right

            // PULP specific instructions using only one source register
            {6'b00_1000, 3'b000}: alu_operator_o = `ALU_FF1;   // Find First 1
            {6'b00_1000, 3'b001}: alu_operator_o = `ALU_FL1;   // Find Last 1
            {6'b00_1000, 3'b010}: alu_operator_o = `ALU_CLB;   // Count Leading Bits
            {6'b00_1000, 3'b011}: alu_operator_o = `ALU_CNT;   // Count set bits (popcount)
            {6'b00_1000, 3'b100}: alu_operator_o = `ALU_EXTHS; // Sign-extend Half-word
            {6'b00_1000, 3'b101}: alu_operator_o = `ALU_EXTHZ; // Zero-extend Half-word
            {6'b00_1000, 3'b110}: alu_operator_o = `ALU_EXTBS; // Sign-extend Byte
            {6'b00_1000, 3'b111}: alu_operator_o = `ALU_EXTBZ; // Zero-extend Byte

            {6'b00_1010, 3'b000}: alu_operator_o = `ALU_ABS;   // Absolute

            default: begin
              illegal_insn_o = 1'b1;
            end
          endcase
        end
      end

      `OPCODE_PULP_OP: begin  // PULP specific ALU instructions with three source operands
        regfile_alu_we = 1'b1;
        rega_used_o    = 1'b1;
        regb_used_o    = 1'b1;

        case (instr_rdata_i[13:12])
          2'b00: begin // multiply with subword selection
            mult_vec_mode_o    = 1'b1;
            mult_sel_subword_o = {2{instr_rdata_i[30]}};
            mult_signed_mode_o = {2{instr_rdata_i[31]}};

            mult_en = 1'b1;
          end

          2'b01: begin // MAC with subword selection
            regc_used_o        = 1'b1;
            regc_mux_o         = `REGC_RD;
            mult_vec_mode_o    = 1'b1;
            mult_sel_subword_o = {2{instr_rdata_i[30]}};
            mult_signed_mode_o = {2{instr_rdata_i[31]}};

            mult_en     = 1'b1;
            mult_mac_en = 1'b1;
          end

          default: begin
            regfile_alu_we = 1'b0;
            illegal_insn_o = 1'b1;
          end
        endcase
      end

      `OPCODE_VECOP: begin
        rega_used_o         = 1'b1;
        immediate_mux_sel_o = `IMM_VS;

        // vector size
        if (instr_rdata_i[12])
          alu_vec_mode_o = `VEC_MODE8;
        else
          alu_vec_mode_o = `VEC_MODE16;

        // distinguish normal vector, sc and sci modes
        if (instr_rdata_i[14]) begin
          scalar_replication_o = 1'b1;

          if (instr_rdata_i[13]) begin
            // immediate scalar replication, .sci
            alu_op_b_mux_sel_o = `OP_B_IMM;
          end else begin<commit_msg>We should also active the WE for vectorial instructions...<commit_after>// Copyright 2015 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.

////////////////////////////////////////////////////////////////////////////////
// Engineer        <NAME> - <EMAIL>                    //
//                                                                            //
// Additional contributions by:                                               //
//                 <NAME> - <EMAIL>                   //
//                 <NAME> - <EMAIL>                               //
//                 <NAME> - <EMAIL>                     //
//                                                                            //
// Design Name:    Decoder                                                    //
// Project Name:   RI5CY                                                      //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    Decoder                                                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

`include "riscv_defines.sv"

module riscv_decoder
(
  // singals running to/from controller
  input  logic        deassert_we_i,           // deassert we, we are stalled or not active
  input  logic        data_misaligned_i,       // misaligned data load/store in progress

  output logic        illegal_insn_o,          // illegal instruction encountered
  output logic        trap_insn_o,             // trap instruction encountered
  output logic        eret_insn_o,             // return from exception instruction encountered
  output logic        ecall_insn_o,            // environment call (syscall) instruction encountered
  output logic        pipe_flush_o,            // pipeline flush is requested

  output logic        rega_used_o,             // rs1 is used by current instruction
  output logic        regb_used_o,             // rs2 is used by current instruction
  output logic        regc_used_o,             // rs3 is used by current instruction

  output logic        imm_bmask_needed_o,      // immediate registers for bit manipulation mask is needed

  // from IF/ID pipeline
  input  logic [31:0] instr_rdata_i,           // instruction read from instr memory/cache
  input  logic        illegal_c_insn_i,        // compressed instruction decode failed

  // ALU signals
  output logic [`ALU_OP_WIDTH-1:0] alu_operator_o, // ALU operation selection
  output logic [1:0]  alu_op_a_mux_sel_o,      // operand a selection: reg value, PC, immediate or zero
  output logic [1:0]  alu_op_b_mux_sel_o,      // operand b selection: reg value or immediate
  output logic [1:0]  alu_op_c_mux_sel_o,      // operand c selection: reg value or jump target
  output logic [1:0]  alu_vec_mode_o,          // selects between 32 bit, 16 bit and 8 bit vectorial modes
  output logic        scalar_replication_o,    // scalar replication enable
  output logic [2:0]  immediate_mux_sel_o,     // immediate selection for operand b
  output logic [1:0]  regc_mux_o,              // register c selection: S3, RD or 0

  // MUL related control signals
  output logic        mult_en_o,               // perform multiplication
  output logic        mult_mac_en_o,           // accumulate multiplication result
  output logic [1:0]  mult_sel_subword_o,      // Select subwords for 16x16 bit of multiplier
  output logic [1:0]  mult_signed_mode_o,      // Multiplication in signed mode
  output logic        mult_vec_mode_o,         // selects between 32 bit and 16 bit modes

  // register file related signals
  output logic        regfile_mem_we_o,        // write enable for regfile
  output logic        regfile_alu_we_o,        // write enable for 2nd regfile port
  output logic        regfile_alu_waddr_sel_o, // Select register write address for ALU/MUL operations

  // CSR manipulation
  output logic        csr_access_o,            // access to CSR
  output logic [1:0]  csr_op_o,                // operation to perform on CSR

  // LD/ST unit signals
  output logic        data_req_o,              // start transaction to data memory
  output logic        data_we_o,               // data memory write enable
  output logic        prepost_useincr_o,       // when not active bypass the alu result for address calculation
  output logic [1:0]  data_type_o,             // data type on data memory: byte, half word or word
  output logic        data_sign_extension_o,   // sign extension on read data from data memory
  output logic [1:0]  data_reg_offset_o,       // offset in byte inside register for stores
  output logic        data_load_event_o,       // data request is in the special event range

  // hwloop signals
  output logic [2:0]  hwloop_we_o,             // write enable for hwloop regs
  output logic        hwloop_target_mux_sel_o, // selects immediate for hwloop target
  output logic        hwloop_start_mux_sel_o,  // selects hwloop start address input
  output logic        hwloop_cnt_mux_sel_o,    // selects hwloop counter input

  // jump/branches
  output logic [1:0]  jump_in_dec_o,           // jump_in_id without deassert
  output logic [1:0]  jump_in_id_o,            // jump is being calculated in ALU
  output logic [1:0]  jump_target_mux_sel_o    // jump target selection
);

  // write enable/request control
  logic       regfile_mem_we;
  logic       regfile_alu_we;
  logic       data_req;
  logic [2:0] hwloop_we;

  logic       trap_insn;
  logic       eret_insn;
  logic       pipe_flush;

  logic [1:0] jump_in_id;

  logic       mult_en;
  logic       mult_mac_en;
  logic [1:0] csr_op;


  /////////////////////////////////////////////
  //   ____                     _            //
  //  |  _ \  ___  ___ ___   __| | ___ _ __  //
  //  | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| //
  //  | |_| |  __/ (_| (_) | (_| |  __/ |    //
  //  |____/ \___|\___\___/ \__,_|\___|_|    //
  //                                         //
  /////////////////////////////////////////////

  always_comb
  begin
    jump_in_id                  = `BRANCH_NONE;
    jump_target_mux_sel_o       = `JT_JAL;

    alu_operator_o              = `ALU_SLTU;
    alu_op_a_mux_sel_o          = `OP_A_REGA_OR_FWD;
    alu_op_b_mux_sel_o          = `OP_B_REGB_OR_FWD;
    alu_op_c_mux_sel_o          = `OP_C_REGC_OR_FWD;
    alu_vec_mode_o              = `VEC_MODE32;
    scalar_replication_o        = 1'b0;
    regc_mux_o                  = `REGC_ZERO;
    immediate_mux_sel_o         = `IMM_I;

    mult_en                     = 1'b0;
    mult_signed_mode_o          = 2'b00;
    mult_sel_subword_o          = 2'b00;
    mult_mac_en                 = 1'b0;
    mult_vec_mode_o             = 1'b0;

    regfile_mem_we              = 1'b0;
    regfile_alu_we              = 1'b0;
    regfile_alu_waddr_sel_o     = 1'b1;

    prepost_useincr_o           = 1'b1;

    hwloop_we                   = 3'b0;
    hwloop_target_mux_sel_o     = 1'b0;
    hwloop_start_mux_sel_o      = 1'b0;
    hwloop_cnt_mux_sel_o        = 1'b0;

    csr_access_o                = 1'b0;
    csr_op                      = `CSR_OP_NONE;

    data_we_o                   = 1'b0;
    data_type_o                 = 2'b00;
    data_sign_extension_o       = 1'b0;
    data_reg_offset_o           = 2'b00;
    data_req                    = 1'b0;
    data_load_event_o           = 1'b0;

    illegal_insn_o              = 1'b0;
    trap_insn                   = 1'b0;
    eret_insn                   = 1'b0;
    ecall_insn_o                = 1'b0;
    pipe_flush                  = 1'b0;

    rega_used_o                 = 1'b0;
    regb_used_o                 = 1'b0;
    regc_used_o                 = 1'b0;
    imm_bmask_needed_o          = 1'b0;


    unique case (instr_rdata_i[6:0])

      //////////////////////////////////////
      //      _ _   _ __  __ ____  ____   //
      //     | | | | |  \/  |  _ \/ ___|  //
      //  _  | | | | | |\/| | |_) \___ \  //
      // | |_| | |_| | |  | |  __/ ___) | //
      //  \___/ \___/|_|  |_|_|   |____/  //
      //                                  //
      //////////////////////////////////////

      `OPCODE_JAL: begin   // Jump and Link
        jump_target_mux_sel_o = `JT_JAL;
        jump_in_id            = `BRANCH_JAL;
        // Calculate and store PC+4
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_PCINCR;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
        // Calculate jump target (= PC + UJ imm)
      end

      `OPCODE_JALR: begin  // Jump and Link Register
        jump_target_mux_sel_o = `JT_JALR;
        jump_in_id            = `BRANCH_JALR;
        // Calculate and store PC+4
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_PCINCR;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
        // Calculate jump target (= RS1 + I imm)
        rega_used_o         = 1'b1;

        if (instr_rdata_i[14:12] != 3'b0) begin
          jump_in_id       = `BRANCH_NONE;
          regfile_alu_we   = 1'b0;
          illegal_insn_o   = 1'b0;
        end
      end

      `OPCODE_BRANCH: begin // Branch
        jump_target_mux_sel_o = `JT_COND;
        jump_in_id            = `BRANCH_COND;
        alu_op_c_mux_sel_o    = `OP_C_JT;
        rega_used_o           = 1'b1;
        regb_used_o           = 1'b1;

        unique case (instr_rdata_i[14:12])
          3'b000: alu_operator_o = `ALU_EQ;
          3'b001: alu_operator_o = `ALU_NE;
          3'b100: alu_operator_o = `ALU_LTS;
          3'b101: alu_operator_o = `ALU_GES;
          3'b110: alu_operator_o = `ALU_LTU;
          3'b111: alu_operator_o = `ALU_GEU;
          3'b010: alu_operator_o = `ALU_EQALL;

          default: begin
            illegal_insn_o = 1'b1;
          end
        endcase
      end


      //////////////////////////////////
      //  _     ____    ______ _____  //
      // | |   |  _ \  / / ___|_   _| //
      // | |   | | | |/ /\___ \ | |   //
      // | |___| |_| / /  ___) || |   //
      // |_____|____/_/  |____/ |_|   //
      //                              //
      //////////////////////////////////

      `OPCODE_STORE,
      `OPCODE_STORE_POST: begin
        data_req       = 1'b1;
        data_we_o      = 1'b1;
        rega_used_o    = 1'b1;
        regb_used_o    = 1'b1;
        alu_operator_o = `ALU_ADD;

        // pass write data through ALU operand c
        alu_op_c_mux_sel_o = `OP_C_REGB_OR_FWD;

        // post-increment setup
        if (instr_rdata_i[6:0] == `OPCODE_STORE_POST) begin
          prepost_useincr_o       = 1'b0;
          regfile_alu_waddr_sel_o = 1'b0;
          regfile_alu_we          = 1'b1;
        end

        if (instr_rdata_i[14] == 1'b0) begin
          // offset from immediate
          immediate_mux_sel_o = `IMM_S;
          alu_op_b_mux_sel_o  = `OP_B_IMM;
        end else begin
          // offset from register
          regc_used_o        = 1'b1;
          alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD;
          regc_mux_o         = `REGC_S3;
        end

        // store size
        unique case (instr_rdata_i[13:12])
          2'b00: data_type_o = 2'b10; // SB
          2'b01: data_type_o = 2'b01; // SH
          2'b10: data_type_o = 2'b00; // SW
          default: begin
            data_req       = 1'b0;
            data_we_o      = 1'b0;
            illegal_insn_o = 1'b1;
          end
        endcase
      end

      `OPCODE_LOAD,
      `OPCODE_LOAD_POST: begin
        data_req        = 1'b1;
        regfile_mem_we  = 1'b1;
        rega_used_o     = 1'b1;
        data_type_o     = 2'b00;

        // offset from immediate
        alu_operator_o      = `ALU_ADD;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_I;

        // post-increment setup
        if (instr_rdata_i[6:0] == `OPCODE_LOAD_POST) begin
          prepost_useincr_o       = 1'b0;
          regfile_alu_waddr_sel_o = 1'b0;
          regfile_alu_we          = 1'b1;
        end

        // sign/zero extension
        data_sign_extension_o = ~instr_rdata_i[14];

        // load size
        unique case (instr_rdata_i[13:12])
          2'b00:   data_type_o = 2'b10; // LB
          2'b01:   data_type_o = 2'b01; // LH
          2'b10:   data_type_o = 2'b00; // LW
          default: data_type_o = 2'b00; // illegal or reg-reg
        endcase

        // reg-reg load (different encoding)
        if (instr_rdata_i[14:12] == 3'b111) begin
          // offset from RS2
          regb_used_o        = 1'b1;
          alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD;

          // sign/zero extension
          data_sign_extension_o = ~instr_rdata_i[30];

          // load size
          unique case (instr_rdata_i[31:25])
            7'b0000_000,
            7'b0100_000: data_type_o = 2'b10; // LB, LBU
            7'b0001_000,
            7'b0101_000: data_type_o = 2'b01; // LH, LHU
            7'b0010_000: data_type_o = 2'b00; // LW
            default: begin
              data_type_o    = 2'b00;
              // illegal instruction
              data_req       = 1'b0;
              regfile_mem_we = 1'b0;
              regfile_alu_we = 1'b0;
              illegal_insn_o = 1'b1;
            end
          endcase
        end

        // special p.elw (event load)
        if (instr_rdata_i[14:12] == 3'b110)
          data_load_event_o = 1'b1;

        if (instr_rdata_i[14:12] == 3'b011) begin
          // LD -> RV64 only
          illegal_insn_o = 1'b1;
        end
      end


      //////////////////////////
      //     _    _    _   _  //
      //    / \  | |  | | | | //
      //   / _ \ | |  | | | | //
      //  / ___ \| |__| |_| | //
      // /_/   \_\_____\___/  //
      //                      //
      //////////////////////////

      `OPCODE_LUI: begin  // Load Upper Immediate
        alu_op_a_mux_sel_o  = `OP_A_ZERO;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_U;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
      end

      `OPCODE_AUIPC: begin  // Add Upper Immediate to PC
        alu_op_a_mux_sel_o  = `OP_A_CURRPC;
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_U;
        alu_operator_o      = `ALU_ADD;
        regfile_alu_we      = 1'b1;
      end

      `OPCODE_OPIMM: begin // Register-Immediate ALU Operations
        alu_op_b_mux_sel_o  = `OP_B_IMM;
        immediate_mux_sel_o = `IMM_I;
        regfile_alu_we      = 1'b1;
        rega_used_o         = 1'b1;

        unique case (instr_rdata_i[14:12])
          3'b000: alu_operator_o = `ALU_ADD;  // Add Immediate
          3'b010: alu_operator_o = `ALU_SLTS; // Set to one if Lower Than Immediate
          3'b011: alu_operator_o = `ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
          3'b100: alu_operator_o = `ALU_XOR;  // Exclusive Or with Immediate
          3'b110: alu_operator_o = `ALU_OR;   // Or with Immediate
          3'b111: alu_operator_o = `ALU_AND;  // And with Immediate

          3'b001: begin
            alu_operator_o = `ALU_SLL;  // Shift Left Logical by Immediate
            if (instr_rdata_i[31:25] != 7'b0)
              illegal_insn_o = 1'b1;
          end

          3'b101: begin
            if (instr_rdata_i[31:25] == 7'b0)
              alu_operator_o = `ALU_SRL;  // Shift Right Logical by Immediate
            else if (instr_rdata_i[31:25] == 7'b010_0000)
              alu_operator_o = `ALU_SRA;  // Shift Right Arithmetically by Immediate
            else
              illegal_insn_o = 1'b1;
          end

          default: illegal_insn_o = 1'b1;
        endcase
      end

      `OPCODE_OP: begin  // Register-Register ALU operation
        regfile_alu_we = 1'b1;
        rega_used_o    = 1'b1;

        if (instr_rdata_i[31]) begin
          // bit-manipulation instructions
          alu_op_b_mux_sel_o  = `OP_B_IMM;
          imm_bmask_needed_o  = 1'b1;

          unique case (instr_rdata_i[14:12])
            3'b000: begin alu_operator_o = `ALU_BEXT;  immediate_mux_sel_o = `IMM_S2; end
            3'b001: begin alu_operator_o = `ALU_BEXTU; immediate_mux_sel_o = `IMM_S2; end
            3'b010: begin
              alu_operator_o      = `ALU_BINS;
              immediate_mux_sel_o = `IMM_S2;
              regc_used_o         = 1'b1;
              regc_mux_o          = `REGC_RD;
            end

            3'b011: begin alu_operator_o = `ALU_BCLR; end
            3'b100: begin alu_operator_o = `ALU_BSET; end

            default: illegal_insn_o = 1'b1;
          endcase
        end
        else
        begin // non bit-manipulation instructions

          if (~instr_rdata_i[28])
            regb_used_o = 1'b1;

          unique case ({instr_rdata_i[30:25], instr_rdata_i[14:12]})
            // RV32I ALU operations
            {6'b00_0000, 3'b000}: alu_operator_o = `ALU_ADD;   // Add
            {6'b10_0000, 3'b000}: alu_operator_o = `ALU_SUB;   // Sub
            {6'b00_0000, 3'b010}: alu_operator_o = `ALU_SLTS;  // Set Lower Than
            {6'b00_0000, 3'b011}: alu_operator_o = `ALU_SLTU;  // Set Lower Than Unsigned
            {6'b00_0000, 3'b100}: alu_operator_o = `ALU_XOR;   // Xor
            {6'b00_0000, 3'b110}: alu_operator_o = `ALU_OR;    // Or
            {6'b00_0000, 3'b111}: alu_operator_o = `ALU_AND;   // And
            {6'b00_0000, 3'b001}: alu_operator_o = `ALU_SLL;   // Shift Left Logical
            {6'b00_0000, 3'b101}: alu_operator_o = `ALU_SRL;   // Shift Right Logical
            {6'b10_0000, 3'b101}: alu_operator_o = `ALU_SRA;   // Shift Right Arithmetic

            // supported RV32M instructions
            {6'b00_0001, 3'b000}: mult_en      = 1'b1;       // Multiplication
            {6'b00_0001, 3'b001}: begin // MAC
              regc_used_o  = 1'b1;
              regc_mux_o   = `REGC_RD;
              mult_en      = 1'b1;
              mult_mac_en  = 1'b1;
            end

            // PULP specific instructions
            {6'b00_0010, 3'b000}: alu_operator_o = `ALU_AVG;   // Average
            {6'b00_0010, 3'b001}: alu_operator_o = `ALU_AVGU;  // Average Unsigned
            {6'b00_0010, 3'b010}: alu_operator_o = `ALU_SLETS; // Set Lower Equal Than
            {6'b00_0010, 3'b011}: alu_operator_o = `ALU_SLETU; // Set Lower Equal Than Unsigned
            {6'b00_0010, 3'b100}: alu_operator_o = `ALU_MIN;   // Min
            {6'b00_0010, 3'b101}: alu_operator_o = `ALU_MINU;  // Min Unsigned
            {6'b00_0010, 3'b110}: alu_operator_o = `ALU_MAX;   // Max
            {6'b00_0010, 3'b111}: alu_operator_o = `ALU_MAXU;  // Max Unsigned

            {6'b00_0100, 3'b101}: alu_operator_o = `ALU_ROR;   // Rotate Right

            // PULP specific instructions using only one source register
            {6'b00_1000, 3'b000}: alu_operator_o = `ALU_FF1;   // Find First 1
            {6'b00_1000, 3'b001}: alu_operator_o = `ALU_FL1;   // Find Last 1
            {6'b00_1000, 3'b010}: alu_operator_o = `ALU_CLB;   // Count Leading Bits
            {6'b00_1000, 3'b011}: alu_operator_o = `ALU_CNT;   // Count set bits (popcount)
            {6'b00_1000, 3'b100}: alu_operator_o = `ALU_EXTHS; // Sign-extend Half-word
            {6'b00_1000, 3'b101}: alu_operator_o = `ALU_EXTHZ; // Zero-extend Half-word
            {6'b00_1000, 3'b110}: alu_operator_o = `ALU_EXTBS; // Sign-extend Byte
            {6'b00_1000, 3'b111}: alu_operator_o = `ALU_EXTBZ; // Zero-extend Byte

            {6'b00_1010, 3'b000}: alu_operator_o = `ALU_ABS;   // Absolute

            default: begin
              illegal_insn_o = 1'b1;
            end
          endcase
        end
      end

      `OPCODE_PULP_OP: begin  // PULP specific ALU instructions with three source operands
        regfile_alu_we = 1'b1;
        rega_used_o    = 1'b1;
        regb_used_o    = 1'b1;

        case (instr_rdata_i[13:12])
          2'b00: begin // multiply with subword selection
            mult_vec_mode_o    = 1'b1;
            mult_sel_subword_o = {2{instr_rdata_i[30]}};
            mult_signed_mode_o = {2{instr_rdata_i[31]}};

            mult_en = 1'b1;
          end

          2'b01: begin // MAC with subword selection
            regc_used_o        = 1'b1;
            regc_mux_o         = `REGC_RD;
            mult_vec_mode_o    = 1'b1;
            mult_sel_subword_o = {2{instr_rdata_i[30]}};
            mult_signed_mode_o = {2{instr_rdata_i[31]}};

            mult_en     = 1'b1;
            mult_mac_en = 1'b1;
          end

          default: begin
            regfile_alu_we = 1'b0;
            illegal_insn_o = 1'b1;
          end
        endcase
      end

      `OPCODE_VECOP: begin
        regfile_alu_we      = 1'b1;
        rega_used_o         = 1'b1;
        immediate_mux_sel_o = `IMM_VS;

        // vector size
        if (instr_rdata_i[12])
          alu_vec_mode_o = `VEC_MODE8;
        else
          alu_vec_mode_o = `VEC_MODE16;

        // distinguish normal vector, sc and sci modes
        if (instr_rdata_i[14]) begin
          scalar_replication_o = 1'b1;

          if (instr_rdata_i[13]) begin
            // immediate scalar replication, .sci
            alu_op_b_mux_sel_o = `OP_B_IMM;
          end else begin
{'fraction_non_alphanumeric': 0.10969869243888573, 'fraction_numerical': 0.04188743604320637, 'mean_word_length': 1.4221194095615775, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 56, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1392487', 'n_tokens_mistral': 16327, 'n_tokens_neox': 15114, 'n_words': 3097}