<commit_before>// Copyright lowRISC contributors.
// Copyright 2018 ETH Zurich and University of Bologna.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

////////////////////////////////////////////////////////////////////////////////
// Engineer:       <NAME> - <EMAIL>                 //
//                                                                            //
//                                                                            //
// Design Name:    Fast Multiplier and Division                               //
// Project Name:   ibex                                                       //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    16x16 kernel multiplier and Long Division                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

`define OP_L 15:0
`define OP_H 31:16

/**
 * Fast Multiplier and Division
 *
 * 16x16 kernel multiplier and Long Division
 */
module ibex_multdiv_fast (
    input  logic                 clk_i,
    input  logic                 rst_ni,
    input  logic                 mult_en_i,
    input  logic                 div_en_i,
    input  ibex_defines::md_op_e operator_i,
    input  logic  [1:0]          signed_mode_i,
    input  logic [31:0]          op_a_i,
    input  logic [31:0]          op_b_i,
    input  logic [33:0]          alu_adder_ext_i,
    input  logic [31:0]          alu_adder_i,
    input  logic                 equal_to_zero,

    output logic [32:0]          alu_operand_a_o,
    output logic [32:0]          alu_operand_b_o,

    output logic [31:0]          multdiv_result_o,
    output logic                 ready_o
);

  import ibex_defines::*;

  logic [ 4:0] div_counter_q, div_counter_n;
  typedef enum logic [1:0] {
    ALBL, ALBH, AHBL, AHBH
  } mult_fsm_e;
  mult_fsm_e mult_state_q, mult_state_n;

  typedef enum logic [2:0] {
    MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
  } div_fsm_e;
  div_fsm_e divcurr_state_q, divcurr_state_n;

  logic signed [34:0] mac_res_signed;
  logic        [34:0] mac_res_ext;

  logic [33:0] mac_res_q, mac_res_n, mac_res, op_reminder_n;
  logic [15:0] mult_op_a;
  logic [15:0] mult_op_b;
  logic [33:0] accum;
  logic        sign_a, sign_b;
  logic        div_sign_a, div_sign_b;
  logic        signed_mult;
  logic        is_greater_equal;
  logic        div_change_sign, rem_change_sign;
  logic [31:0] one_shift;
  logic [31:0] op_denominator_q;
  logic [31:0] op_numerator_q;
  logic [31:0] op_quotient_q;
  logic [31:0] op_denominator_n;
  logic [31:0] op_numerator_n;
  logic [31:0] op_quotient_n;
  logic [31:0] next_reminder;
  logic [32:0] next_quotient;
  logic [32:0] res_adder_h;
  logic        mult_is_ready;

  always_ff @(posedge clk_i or negedge rst_ni) begin : proc_mult_state_q
    if (!rst_ni) begin
      mult_state_q      <= ALBL;
      mac_res_q         <= '0;
      div_counter_q     <= '0;
      divcurr_state_q   <= MD_IDLE;
      op_denominator_q  <= '0;
      op_numerator_q    <= '0;
      op_quotient_q     <= '0;
    end else begin

      if (mult_en_i) begin
        mult_state_q <= mult_state_n;
      end

      if (div_en_i) begin
        div_counter_q     <= div_counter_n;
        op_denominator_q  <= op_denominator_n  ;
        op_numerator_q    <= op_numerator_n    ;
        op_quotient_q     <= op_quotient_n     ;
        divcurr_state_q   <= divcurr_state_n;
      end

      unique case(1'b1)
        mult_en_i:
          mac_res_q <= mac_res_n;
        div_en_i:
          mac_res_q <= op_reminder_n;
        default:
          mac_res_q <= mac_res_q;
       endcase
    end
  end

  assign signed_mult    = (signed_mode_i != 2'b00);

  assign multdiv_result_o = div_en_i ? mac_res_q[31:0] : mac_res_n[31:0];

  assign mac_res_signed = $signed({sign_a, mult_op_a})*$signed({sign_b, mult_op_b}) + $signed(accum);
  assign mac_res_ext    = $unsigned(mac_res_signed);
  assign mac_res        = mac_res_ext[33:0];

  assign res_adder_h   = alu_adder_ext_i[33:1];

  assign next_reminder = is_greater_equal ? res_adder_h[31:0] : mac_res_q[31:0];
  assign next_quotient = is_greater_equal ? {1'b0,op_quotient_q} | {1'b0,one_shift} :
                                            {1'b0,op_quotient_q};

  assign one_shift     = {31'b0, 1'b1} << div_counter_q;

  /*
     The adder in the ALU computes alu_operand_a_o + alu_operand_b_o which means
     Reminder - Divisor. If Reminder - Divisor >= 0, is_greater_equal is equal to 1,
     the next Reminder is Reminder - Divisor contained in res_adder_h and the
  */<commit_msg>Add comment to clarify that ignoring the MSB in the MAC is safe.<commit_after>// Copyright lowRISC contributors.
// Copyright 2018 ETH Zurich and University of Bologna.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

////////////////////////////////////////////////////////////////////////////////
// Engineer:       <NAME> - <EMAIL>                 //
//                                                                            //
//                                                                            //
// Design Name:    Fast Multiplier and Division                               //
// Project Name:   ibex                                                       //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    16x16 kernel multiplier and Long Division                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

`define OP_L 15:0
`define OP_H 31:16

/**
 * Fast Multiplier and Division
 *
 * 16x16 kernel multiplier and Long Division
 */
module ibex_multdiv_fast (
    input  logic                 clk_i,
    input  logic                 rst_ni,
    input  logic                 mult_en_i,
    input  logic                 div_en_i,
    input  ibex_defines::md_op_e operator_i,
    input  logic  [1:0]          signed_mode_i,
    input  logic [31:0]          op_a_i,
    input  logic [31:0]          op_b_i,
    input  logic [33:0]          alu_adder_ext_i,
    input  logic [31:0]          alu_adder_i,
    input  logic                 equal_to_zero,

    output logic [32:0]          alu_operand_a_o,
    output logic [32:0]          alu_operand_b_o,

    output logic [31:0]          multdiv_result_o,
    output logic                 ready_o
);

  import ibex_defines::*;

  logic [ 4:0] div_counter_q, div_counter_n;
  typedef enum logic [1:0] {
    ALBL, ALBH, AHBL, AHBH
  } mult_fsm_e;
  mult_fsm_e mult_state_q, mult_state_n;

  typedef enum logic [2:0] {
    MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
  } div_fsm_e;
  div_fsm_e divcurr_state_q, divcurr_state_n;

  logic signed [34:0] mac_res_signed;
  logic        [34:0] mac_res_ext;

  logic [33:0] mac_res_q, mac_res_n, mac_res, op_reminder_n;
  logic [15:0] mult_op_a;
  logic [15:0] mult_op_b;
  logic [33:0] accum;
  logic        sign_a, sign_b;
  logic        div_sign_a, div_sign_b;
  logic        signed_mult;
  logic        is_greater_equal;
  logic        div_change_sign, rem_change_sign;
  logic [31:0] one_shift;
  logic [31:0] op_denominator_q;
  logic [31:0] op_numerator_q;
  logic [31:0] op_quotient_q;
  logic [31:0] op_denominator_n;
  logic [31:0] op_numerator_n;
  logic [31:0] op_quotient_n;
  logic [31:0] next_reminder;
  logic [32:0] next_quotient;
  logic [32:0] res_adder_h;
  logic        mult_is_ready;

  always_ff @(posedge clk_i or negedge rst_ni) begin : proc_mult_state_q
    if (!rst_ni) begin
      mult_state_q      <= ALBL;
      mac_res_q         <= '0;
      div_counter_q     <= '0;
      divcurr_state_q   <= MD_IDLE;
      op_denominator_q  <= '0;
      op_numerator_q    <= '0;
      op_quotient_q     <= '0;
    end else begin

      if (mult_en_i) begin
        mult_state_q <= mult_state_n;
      end

      if (div_en_i) begin
        div_counter_q     <= div_counter_n;
        op_denominator_q  <= op_denominator_n  ;
        op_numerator_q    <= op_numerator_n    ;
        op_quotient_q     <= op_quotient_n     ;
        divcurr_state_q   <= divcurr_state_n;
      end

      unique case(1'b1)
        mult_en_i:
          mac_res_q <= mac_res_n;
        div_en_i:
          mac_res_q <= op_reminder_n;
        default:
          mac_res_q <= mac_res_q;
       endcase
    end
  end

  assign signed_mult    = (signed_mode_i != 2'b00);

  assign multdiv_result_o = div_en_i ? mac_res_q[31:0] : mac_res_n[31:0];

  // The 2 MSBs of mac_res_ext (mac_res_ext[34:33]) are always equal since:
  // 1. The 2 MSBs of the multiplicants are always equal, and
  // 2. The 16 MSBs of the addend (accum[33:18]) are always equal.
  // Thus, it is safe to ignore mac_res_ext[34].
  assign mac_res_signed = $signed({sign_a, mult_op_a})*$signed({sign_b, mult_op_b}) + $signed(accum);
  assign mac_res_ext    = $unsigned(mac_res_signed);
  assign mac_res        = mac_res_ext[33:0];

  assign res_adder_h   = alu_adder_ext_i[33:1];

  assign next_reminder = is_greater_equal ? res_adder_h[31:0] : mac_res_q[31:0];
  assign next_quotient = is_greater_equal ? {1'b0,op_quotient_q} | {1'b0,one_shift} :
                                            {1'b0,op_quotient_q};

  assign one_shift     = {31'b0, 1'b1} << div_counter_q;

  /*
     The adder in the ALU computes alu_operand_a_o + alu_operand_b_o which means
     Reminder - Divisor. If Reminder - Divisor >= 0, is_greater_equal is equal to 1,
     the next Reminder is Reminder - Divisor contained in res_adder_h and the
  */
{'fraction_non_alphanumeric': 0.11555021527986382, 'fraction_numerical': 0.02983879042755582, 'mean_word_length': 1.6263476202997633, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '323440', 'n_tokens_mistral': 3540, 'n_tokens_neox': 3344, 'n_words': 753}