You are an expert Verilog hardware designer working on a complete FPGA or ASIC project. You are given the full source code of a Verilog project. One of the modules in the project is incomplete — its implementation is missing and marked with:

// >>> Module Implementation Begin

// <<< Module Implementation End

Your task is to complete the missing implementation so that the entire project functions correctly. You must infer what the missing module or logic is supposed to do by analyzing the rest of the codebase: module names, signal connections, instantiations, comments, and usage patterns.

Follow these rules:

1. Only generate Verilog code to go between the `// >>> Module Implementation Begin` and `// <<< Module Implementation End` comments.
2. Use Verilog-2001 syntax. Ensure the code is synthesizable.
3. Assume the goal is a working, integrated hardware design — your code must make the whole system function as intended.
4. Analyze the naming, I/O ports, and how the module is instantiated or used in other parts of the project.
5. Implement correct behavior based on design context. Do not guess randomly — reason it out.
6. Avoid vendor-specific features unless explicitly required.
7. Do not output comments, explanation, or anything outside the required code region unless explicitly asked.

Your output should contain **only the Verilog code** that fits inside the marked region.

/*
 * Copyright (c) 2024 Uri Shaked
 * SPDX-License-Identifier: Apache-2.0
 */

`default_nettype none

module tt_um_mandelbrot_accel (
    input  wire [7:0] ui_in,    // Dedicated inputs
    output wire [7:0] uo_out,   // Dedicated outputs
    input  wire [7:0] uio_in,   // IOs: Input path
    output wire [7:0] uio_out,  // IOs: Output path
    output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
    input  wire       ena,      // always 1 when the design is powered, so you can ignore it
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




// SPDX-FileCopyrightText: 2020 Efabless Corporation
//
// 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

`default_nettype none
module fp_add_sub (
    input  wire [31:0] a_operand,
    input  wire [31:0] b_operand,
    input  wire op_subtract,
    output reg  [31:0] o_result
);


  add_sub a(
    .in_x(a_operand),
    .in_y(b_operand),
    .operation(op_subtract),
    .round_mode(3'b000),
    .out_z(o_result)
  );

endmodule

module add_sub( 
  input  wire [31:0] in_x,
  input  wire [31:0] in_y,
  input  wire        operation,
  input  wire [2:0]  round_mode,
  output wire [31:0] out_z,
  output wire [4:0]  exceptions);

  wire        sign_x, sign_y;
  wire [7:0]  exp_x, exp_y, exp_a, exp_b, subnorm_exp, norm_exp;
  wire [22:0] mant_x, mant_y, mant_a, mant_b;

  wire        x_is_zero, x_is_inf, x_is_qNaN, x_is_sNaN;
  wire        y_is_zero, y_is_inf, y_is_qNaN, y_is_sNaN;
  wire        a_is_subnorm, b_is_subnorm;
  wire        hd_bit_a, hd_bit_b;

  wire [26:0] arg1, arg2;
  wire [26:0] rt_shift_mant;
  wire [26:0] lt_shft_mant, norm_sum;
  wire [26:0] mant_sum;
  wire [23:0] rounded_mant;
  wire [31:0] inter_result, of_result;

  wire        comp, exp_shft_comp;
  wire        operator_y, subtract;
  wire        cout, cout_check;

  wire [7:0]  exp_diff;
  wire [4:0]  ld_zero_cnt, inc_dec_exp_amt;
  wire [7:0]  inter_shft_amt, shft_amt;
  wire        round_of;

  wire        sign_z;
  wire [7:0]  exp_z;
  wire [22:0] mant_z;
	
  wire        invalid_operation;
  wire        divide_by_zero;
  wire        overflow;
  wire        underflow;
  wire        inexact;
  wire [9:0]  x_check_res, y_check_res;

  // checking inputs for special values
  special_check #(8, 24) check_x (.in(in_x), .result(x_check_res));
  special_check #(8, 24) check_y (.in(in_y), .result(y_check_res));

  assign x_is_zero = x_check_res[3] | x_check_res[4];
  assign x_is_inf  = x_check_res[0] | x_check_res[7];
  assign x_is_qNaN = x_check_res[9];
  assign x_is_sNaN = x_check_res[8];

  assign y_is_zero = y_check_res[3] | y_check_res[4];
  assign y_is_inf  = y_check_res[0] | y_check_res[7];
  assign y_is_qNaN = y_check_res[9];
  assign y_is_sNaN = y_check_res[8];

  // unpacking inputs
  assign sign_x = in_x[31];
  assign sign_y = in_y[31];
  assign exp_x  = in_x[30:23];
  assign exp_y  = in_y[30:23];
  assign mant_x = in_x[22:0];
  assign mant_y = in_y[22:0];

  // comparing both numbers
  assign comp = (exp_y > exp_x) ? 1'b1 : (exp_y != exp_x) ? 1'b0 : (mant_y > mant_x);

  // determining operation to be performed
  assign operator_y = sign_y ^ operation;
  assign subtract   = sign_x ^ operator_y;

  // determining output sign
  assign sign_z = x_is_zero ? (operator_y) : (y_is_zero ? sign_x : 
                  (subtract ? (comp ? operator_y : sign_x) : sign_x));
	
  // swapping operands
  assign {exp_a, mant_a} = comp ? {exp_y, mant_y} : {exp_x, mant_x};
  assign {exp_b, mant_b} = comp ? {exp_x, mant_x} : {exp_y, mant_y};

  // checking for subnormal numbers
  assign a_is_subnorm = (|exp_a == 0);
  assign b_is_subnorm = (|exp_b == 0);

  // checking difference in exponents
  assign exp_diff = (a_is_subnorm | b_is_subnorm) & (exp_a != exp_b) ? (exp_a - exp_b - 1) 
                    : (exp_a - exp_b);

  // generating hidden bits
  assign hd_bit_a = !a_is_subnorm;
  assign hd_bit_b = !b_is_subnorm;
	
  // right shifting mantissa to make exponents equal
  right_shifter exp_equalizer (.mantisa({hd_bit_b, mant_b, 3'b000}), .shift_amount(exp_diff), 
                               .out(rt_shift_mant));
	
  // computing sum of the mantissas
  assign arg1 = {hd_bit_a, mant_a, 3'b0};
  assign arg2 = subtract ? (~rt_shift_mant + 27'b1) : rt_shift_mant;

  assign {cout, mant_sum} = {1'b0,arg1} + {1'b0,arg2};
  assign cout_check       = cout & ~subtract;

  leading_zero norm_dist_checker (.in(mant_sum[26:3]), .out(ld_zero_cnt));
	
  // computing the shift amount
  assign inter_shft_amt = a_is_subnorm ? 8'b0 : {3'b0, ld_zero_cnt};
  assign exp_shft_comp  = (exp_a <= inter_shft_amt);
  assign shft_amt       = exp_shft_comp ? (exp_a - |exp_a) : inter_shft_amt;

  left_shifter #(27) norm_shifter (.mantisa(mant_sum), .shift_amount(shft_amt), 
                             .out(lt_shft_mant));

  // determining the exponent increment/decrement
  assign norm_sum        = cout_check ? {cout, mant_sum[26:2], |mant_sum[1:0]} : lt_shft_mant;
  assign inc_dec_exp_amt = a_is_subnorm ? 5'b0 : cout_check ? 5'b1 : shft_amt;
	
  rounding add_sub_rounder (.sign(sign_z), .mantisa(norm_sum), .round_mode(round_mode), 
                            .rounded_mantisa(rounded_mant), .rounding_overflow(round_of));

  // determine exponent in case of normal numbers
  assign norm_exp = cout_check ? (exp_a + inc_dec_exp_amt + round_of) : 
                    (exp_a - inc_dec_exp_amt + round_of);

  // determine exponent in case of subnormal numbers
  assign subnorm_exp = (rounded_mant[23] & !(|norm_exp)) ? 8'b1 : 
                       (norm_exp - ((hd_bit_a | hd_bit_b) & exp_shft_comp & !rounded_mant[23]));
	
  assign {exp_z, mant_z} = x_is_zero ? {exp_y, mant_y} : (y_is_zero ? {exp_x, mant_x} : 
                           ((mant_x == mant_y) & (exp_x == exp_y) & subtract ? 'd0 : 
                           {subnorm_exp, rounded_mant[22:0]}));

  // result check for special numbers
  assign inter_result = (x_is_qNaN | y_is_qNaN) ? {1'h0, 8'hff, 23'h400000} : 
                        ((x_is_inf | y_is_inf) ? {sign_z, 8'hff, 23'h0} : ((exp_z == 8'hff) ? 
                        {sign_z, exp_z, 23'd0} : {sign_z, exp_z, mant_z}));

  assign invalid_operation = !(x_is_qNaN | y_is_qNaN) & (x_is_inf & y_is_inf & subtract) | 
                               x_is_sNaN | y_is_sNaN;

  // does not occur in addition subtraction
  assign divide_by_zero = 0;

  assign overflow = !(x_is_qNaN | y_is_qNaN) & &exp_z & !(x_is_inf | y_is_inf | x_is_qNaN | 
                      y_is_qNaN | x_is_sNaN | y_is_sNaN);
	
  // determining result in case of overflow
  assign of_result = ({32{(round_mode == 3'h0) | (round_mode == 3'h4)}} & {sign_z, 8'hff, 23'h0}) |
                     ({32{round_mode == 3'h1}} & {sign_z, 8'hfe, 23'h7fffff}) |
                     ({32{round_mode == 3'h2}} & (sign_z ? {1'h1, 8'hff, 23'h0} : 
                                                 {1'h0, 8'hfe, 23'h7fffff})) |
                     ({32{round_mode == 3'h3}} & (sign_z ? {1'h1, 8'hfe, 23'h7fffff} : 
                                                 {1'h0, 8'hff, 23'h0}));

  // does not occur in addition subtraction
  assign underflow = 0;

  assign inexact = !(x_is_qNaN | y_is_qNaN) & (|norm_sum[2:0] | overflow | underflow) & 
                   !(x_is_zero | y_is_zero | x_is_qNaN | y_is_qNaN | x_is_sNaN | y_is_sNaN | 
                     x_is_inf  | y_is_inf);

  assign exceptions = {invalid_operation, divide_by_zero, overflow, underflow, inexact};

  // assign output
  assign out_z = overflow ? of_result : underflow ? 32'd0 : invalid_operation ? 
                 {1'h0, 8'hff, 23'h400000} : inter_result;

endmodule


module left_shifter #(parameter mant = 24) 
(
	input  wire [mant-1:0] mantisa,
	input  wire [7:0] shift_amount,

	output wire [mant-1:0] out
);

	wire [mant-1:0] temp;

	assign temp  = mantisa << shift_amount;
	assign out   = {temp[mant-1:1], mantisa[0]};

endmodule

module right_shifter 
(
  input  wire [26:0] mantisa,
  input  wire [7:0] shift_amount,

  output wire [26:0] out
);

  assign out = ({27{(shift_amount[7:0]==8'd0)}}  &         mantisa)                          |
              ({27{(shift_amount[7:0]==8'd1)}}  & {1'd0,  mantisa[26:2],   |mantisa[1:0]})  |
              ({27{(shift_amount[7:0]==8'd2)}}  & {2'd0,  mantisa[26:3],   |mantisa[2:0]})  |
              ({27{(shift_amount[7:0]==8'd3)}}  & {3'd0,  mantisa[26:4],   |mantisa[3:0]})  |
              ({27{(shift_amount[7:0]==8'd4)}}  & {4'd0,  mantisa[26:5],   |mantisa[4:0]})  |
              ({27{(shift_amount[7:0]==8'd5)}}  & {5'd0,  mantisa[26:6],   |mantisa[5:0]})  |
              ({27{(shift_amount[7:0]==8'd6)}}  & {6'd0,  mantisa[26:7],   |mantisa[6:0]})  |
              ({27{(shift_amount[7:0]==8'd7)}}  & {7'd0,  mantisa[26:8],   |mantisa[7:0]})  |
              ({27{(shift_amount[7:0]==8'd8)}}  & {8'd0,  mantisa[26:9],   |mantisa[8:0]})  |
              ({27{(shift_amount[7:0]==8'd9)}}  & {9'd0,  mantisa[26:10],  |mantisa[9:0]})  |
              ({27{(shift_amount[7:0]==8'd10)}} & {10'd0, mantisa[26:11],  |mantisa[10:0]}) |
              ({27{(shift_amount[7:0]==8'd11)}} & {11'd0, mantisa[26:12],  |mantisa[11:0]}) |
              ({27{(shift_amount[7:0]==8'd12)}} & {12'd0, mantisa[26:13],  |mantisa[12:0]}) |
              ({27{(shift_amount[7:0]==8'd13)}} & {13'd0, mantisa[26:14],  |mantisa[13:0]}) |
              ({27{(shift_amount[7:0]==8'd14)}} & {14'd0, mantisa[26:15],  |mantisa[14:0]}) |
              ({27{(shift_amount[7:0]==8'd15)}} & {15'd0, mantisa[26:16],  |mantisa[15:0]}) |
              ({27{(shift_amount[7:0]==8'd16)}} & {16'd0, mantisa[26:17],  |mantisa[16:0]}) |
              ({27{(shift_amount[7:0]==8'd17)}} & {17'd0, mantisa[26:18],  |mantisa[17:0]}) |
              ({27{(shift_amount[7:0]==8'd18)}} & {18'd0, mantisa[26:19],  |mantisa[18:0]}) |
              ({27{(shift_amount[7:0]==8'd19)}} & {19'd0, mantisa[26:20],  |mantisa[19:0]}) |
              ({27{(shift_amount[7:0]==8'd20)}} & {20'd0, mantisa[26:21],  |mantisa[20:0]}) |
              ({27{(shift_amount[7:0]==8'd21)}} & {21'd0, mantisa[26:22],  |mantisa[21:0]}) |
              ({27{(shift_amount[7:0]==8'd22)}} & {22'd0, mantisa[26:23],  |mantisa[22:0]}) |
              ({27{(shift_amount[7:0]==8'd23)}} & {23'd0, mantisa[26:24],  |mantisa[23:0]}) |
              ({27{(shift_amount[7:0]==8'd24)}} & {24'd0, mantisa[26:25],  |mantisa[24:0]}) |
              ({27{(shift_amount[7:0]==8'd25)}} & {25'd0, mantisa[26],     |mantisa[25:0]}) |
              ({27{(shift_amount[7:0]>=8'd26)}} & {26'd0,                  |mantisa[26:0]});
endmodule


module rounding
(
  input  wire sign,
  input  wire [26:0] mantisa,
  input  wire [2:0] round_mode,

  output wire [23:0] rounded_mantisa,
  output wire rounding_overflow
);
  
  wire [23:0] rne, rtz, rdn, rup, rmm;
  wire rne_overflow, rtz_overflow, rdn_overflow, rup_overflow, rmm_overflow;

  assign {rne_overflow, rne} = mantisa[2] ? (|mantisa[1:0] ? ({1'b0, mantisa[26:3]} + 1'b1) 
                               : ({1'b0, mantisa[26:3]} + mantisa[3])) : {1'b0, mantisa[26:3]};

  assign {rtz_overflow, rtz} = {1'b0, mantisa[26:3]};

  assign {rdn_overflow, rdn} = |mantisa[2:0] ? (sign ? ({1'b0, mantisa[26:3]} + 1'b1) 
                                : {1'b0, mantisa[26:3]}) : {1'b0, mantisa[26:3]};

  assign {rup_overflow, rup} = |mantisa[2:0] ? (sign ? {1'b0, mantisa[26:3]} 
                                  : ({1'b0, mantisa[26:3]} + 1'b1)) : {1'b0, mantisa[26:3]};
  assign {rmm_overflow, rmm} = mantisa[2] ? ({1'b0, mantisa[26:3]} + 1'b1) : {1'b0, mantisa[26:3]};

  assign rounded_mantisa     = ({24{round_mode == 3'b000}} & rne) |
                               ({24{round_mode == 3'b001}} & rtz) |
                               ({24{round_mode == 3'b010}} & rdn) |
                               ({24{round_mode == 3'b011}} & rup) |
                               ({24{round_mode == 3'b100}} & rmm);

  assign rounding_overflow   = ((round_mode == 3'b000) & rne_overflow) |
                               ((round_mode == 3'b001) & rtz_overflow) |
                               ((round_mode == 3'b010) & rdn_overflow) |
                               ((round_mode == 3'b011) & rup_overflow) |
                               ((round_mode == 3'b100) & rmm_overflow);

endmodule

module leading_zero
(
  input  wire [23:0] in,

  output wire [4:0] out
);
  assign out[4:0]       = ({5{(in[22]  & (&(~(in[23]))))}}    & 5'd1)  |			 
 		                      ({5{(in[21]  & (&(~(in[23:22]))))}} & 5'd2)  |
 		                      ({5{(in[20]  & (&(~(in[23:21]))))}} & 5'd3)  |
 		                      ({5{(in[19]  & (&(~(in[23:20]))))}} & 5'd4)  |
 		                      ({5{(in[18]  & (&(~(in[23:19]))))}} & 5'd5)  |
 		                      ({5{(in[17]  & (&(~(in[23:18]))))}} & 5'd6)  |
 		                      ({5{(in[16]  & (&(~(in[23:17]))))}} & 5'd7)  |
 		                      ({5{(in[15]  & (&(~(in[23:16]))))}} & 5'd8)  |
 		                      ({5{(in[14]  & (&(~(in[23:15]))))}} & 5'd9)  |
 		                      ({5{(in[13]  & (&(~(in[23:14]))))}} & 5'd10) |
 		                      ({5{(in[12]  & (&(~(in[23:13]))))}} & 5'd11) |
 		                      ({5{(in[11]  & (&(~(in[23:12]))))}} & 5'd12) |
 		                      ({5{(in[10]  & (&(~(in[23:11]))))}} & 5'd13) |
 		                      ({5{(in[9]   & (&(~(in[23:10]))))}} & 5'd14) |
 		                      ({5{(in[8]   & (&(~(in[23: 9]))))}} & 5'd15) |
 		                      ({5{(in[7]   & (&(~(in[23: 8]))))}} & 5'd16) |
 		                      ({5{(in[6]   & (&(~(in[23: 7]))))}} & 5'd17) |
 		                      ({5{(in[5]   & (&(~(in[23: 6]))))}} & 5'd18) |
 		                      ({5{(in[4]   & (&(~(in[23: 5]))))}} & 5'd19) |
 		                      ({5{(in[3]   & (&(~(in[23: 4]))))}} & 5'd20) |
 		                      ({5{(in[2]   & (&(~(in[23: 3]))))}} & 5'd21) |
 		                      ({5{(in[1]   & (&(~(in[23: 2]))))}} & 5'd22) |
 		                      ({5{(in[0]   & (&(~(in[23: 1]))))}} & 5'd23);

endmodule

module special_check #(parameter  exp_width = 8, parameter mant_width = 24) 
(
  input  wire [(exp_width + mant_width-1):0] in,

  output wire [9:0] result
);

  wire is_pos_zero;
  wire is_neg_zero;
  wire is_pos_inf;
  wire is_neg_inf;
  wire is_pos_subnorm;
  wire is_neg_subnorm;
  wire is_pos_norm;
  wire is_neg_norm;
  wire is_qNaN;
  wire is_sNaN;

  wire                    sign;
  wire [exp_width-1:0]    exp;
  wire [(mant_width-2):0] sig;

  wire exp_zero, exp_one, sig_zero; 


  assign {sign, exp, sig} = in;

  assign exp_zero         = |exp ? 1'b0 : 1'b1;
  assign sig_zero         = |sig ? 1'b0 : 1'b1;     
  assign exp_one          = &exp ? 1'b1 : 1'b0;

  assign is_pos_zero      = !sign     & exp_zero  & sig_zero;
  assign is_neg_zero      =  sign     & exp_zero  & sig_zero;
  assign is_pos_subnorm   = !sign     & exp_zero  & !sig_zero;
  assign is_neg_subnorm   =  sign     & exp_zero  & !sig_zero;
  assign is_pos_inf       = !sign     & exp_one   & sig_zero; 
  assign is_neg_inf       =  sign     & exp_one   & sig_zero; 
  assign is_qNaN          =  exp_one  & !sig_zero & sig[22];
  assign is_sNaN          =  exp_one  & !sig_zero & !sig[22];

  assign is_pos_norm      = (is_pos_zero | is_neg_zero | is_pos_subnorm | is_neg_subnorm | is_pos_inf | is_neg_inf | 
			                      is_qNaN | is_sNaN) ? 1'b0 : ~sign ? 1'b1 : 1'b0;
 
  assign is_neg_norm      = (is_pos_zero | is_neg_zero | is_pos_subnorm | is_neg_subnorm | is_pos_inf | is_neg_inf | 
			                      is_qNaN | is_sNaN) ? 1'b0 : sign ? 1'b1 : 1'b0; 

  assign result           = {is_qNaN, is_sNaN, is_pos_inf, is_pos_norm, is_pos_subnorm, is_pos_zero, is_neg_zero, 
                            is_neg_subnorm, is_neg_norm, is_neg_inf};
endmodule


// The following module was generated by GPT-4o. Prompt:
// 
// ```
// module fp_multiply (
//     input wire [31:0] a_operand,
//     input wire [31:0] b_operand,
//     output reg o_exception,
//     output reg o_overflow,
//     output reg o_underflow,
//     output reg [31:0] o_result
// );
// 
// Implement IEEE-754 floating point multiplication.
// ```

`default_nettype none

module fp_multiply (
    input wire [31:0] a_operand,
    input wire [31:0] b_operand,
    output reg o_exception,
    output reg o_overflow,
    output reg o_underflow,
    output reg [31:0] o_result
);

  // Split the inputs into sign, exponent, and mantissa
  wire sign_a, sign_b, sign_result;
  wire [7:0] exponent_a, exponent_b, exponent_result;
  wire [23:0] mantissa_a, mantissa_b;

  assign sign_a = a_operand[31];
  assign sign_b = b_operand[31];
  assign exponent_a = a_operand[30:23];
  assign exponent_b = b_operand[30:23];
  assign mantissa_a = {1'b1, a_operand[22:0]};
  assign mantissa_b = {1'b1, b_operand[22:0]};

  // Calculate the result sign
  assign sign_result = sign_a ^ sign_b;

  // Calculate the result exponent
  assign exponent_result = exponent_a + exponent_b - 8'd127;

  // Multiply the mantissas
  wire [47:0] product_mantissa;
  assign product_mantissa = mantissa_a * mantissa_b;

  // Normalize the result mantissa and adjust the exponent if necessary
  wire [22:0] normalized_mantissa;
  wire [ 7:0] adjusted_exponent;

  assign adjusted_exponent = (product_mantissa[47]) ? (exponent_result + 1) : exponent_result;
  assign normalized_mantissa = (product_mantissa[47]) ? product_mantissa[46:24] : product_mantissa[45:23];

  // Handle special cases
  always @(*) begin
    o_exception = 0;
    o_overflow = 0;
    o_underflow = 0;
    o_result = 32'd0;

    // Check for NaN and Infinity
    if ((exponent_a == 8'd255 && mantissa_a[22:0] != 0) || (exponent_b == 8'd255 && mantissa_b[22:0] != 0)) begin
      // NaN
      o_exception = 1;
      o_result = 32'h7FC00000;  // Quiet NaN
    end else if (exponent_a == 8'd255 || exponent_b == 8'd255) begin
      // Infinity
      o_result = {sign_result, 8'd255, 23'd0};
    end else if (exponent_a == 0 || exponent_b == 0) begin
      // Zero
      o_result = {sign_result, 8'd0, 23'd0};
    end else begin
      // Normal case
      if (adjusted_exponent >= 8'd255) begin
        // Overflow
        o_overflow = 1;
        o_result   = {sign_result, 8'd255, 23'd0};
      end else if (adjusted_exponent <= 8'd0) begin
        // Underflow
        o_underflow = 1;
        o_result = {sign_result, 8'd0, 23'd0};
      end else begin
        o_result = {sign_result, adjusted_exponent[7:0], normalized_mantissa[22:0]};
      end
    end
  end

endmodule


/*
 * Copyright (c) 2024 Uri Shaked
 * SPDX-License-Identifier: Apache-2.0
 */

`default_nettype none

/** 
 * This module calculates one iteration of the Mandelbrot set function:
 * R = Z^2 + C
 * 
 * In addition, it checks if the given input Z is not a member of the Mandelbrot set, setting
 * unbounded to 1 when |Z| > 2.
 */
module mandelbrot_func (
    input wire [31:0] Ci,
    input wire [31:0] Cr,
    input wire [31:0] Zr,
    input wire [31:0] Zi,
    output wire [31:0] Rr,
    output wire [31:0] Ri,
    output wire unbounded
);

  // ZrZi = Zr * Zi
  wire [31:0] ZrZi;
  fp_multiply m1 (
      .a_operand(Zr),
      .b_operand(Zi),
      .o_result(ZrZi),
      .o_exception(),
      .o_overflow(),
      .o_underflow()
  );

  // Zr_squared = Zr * Zr
  wire [31:0] Zr_squared;
  fp_multiply m2 (
      .a_operand(Zr),
      .b_operand(Zr),
      .o_result(Zr_squared),
      .o_exception(),
      .o_overflow(),
      .o_underflow()
  );

  // Zi_squared = Zi * Zi
  wire [31:0] Zi_squared;
  fp_multiply m3 (
      .a_operand(Zi),
      .b_operand(Zi),
      .o_result(Zi_squared),
      .o_exception(),
      .o_overflow(),
      .o_underflow()
  );


  wire [31:0] Z2r;
  wire [31:0] Z2i;

  // Z2r = Zr_squared - Zi_squared
  fp_add_sub sub1 (
      .a_operand(Zr_squared),
      .b_operand(Zi_squared),
      .op_subtract(1'b1),
      .o_result(Z2r)
  );

  // Z2i = 2 * Zr * Zi
  fp_add_sub add1 (
      .a_operand(ZrZi),
      .b_operand(ZrZi),
      .op_subtract(1'b0),
      .o_result(Z2i)
  );

  // Rr = Z2r + Cr
  fp_add_sub add2 (
      .a_operand(Z2r),
      .b_operand(Cr),
      .op_subtract(1'b0),
      .o_result(Rr)
  );

  // Ri = Z2i + Ci
  fp_add_sub add3 (
      .a_operand(Z2i),
      .b_operand(Ci),
      .op_subtract(1'b0),
      .o_result(Ri)
  );

  wire [31:0] Z_abs_squared;
  wire [31:0] four_ieee754 = 32'h40800020;  // ~4.0

  // |Z|^2 = Zr^2 + Zi^2
  fp_add_sub add4 (
      .a_operand(Zr_squared),
      .b_operand(Zi_squared),
      .op_subtract(1'b0),
      .o_result(Z_abs_squared)
  );

  wire [31:0] Z_minus_four;
  // calculate |Z|^2 - 4
  fp_add_sub sub3 (
      .a_operand(Z_abs_squared),
      .b_operand(four_ieee754),
      .op_subtract(1'b1),
      .o_result(Z_minus_four)
  );

  assign unbounded = ~Z_minus_four[31];  // |Z| > 2
endmodule


Reference solution:
rtl/generated.v: 
  assign uo_out  = {o_iter, o_unbounded};
  assign uio_oe  = 0;
  assign uio_out = 0;

  wire i_start = ui_in[0];
  wire i_load_Cr = ui_in[1];
  wire i_load_Ci = ui_in[2];
  wire [7:0] data_in = uio_in;

  reg o_unbounded;
  reg [6:0] o_iter;

  reg [23:0] data_in_reg;
  wire [31:0] data_in_word = {data_in, data_in_reg};

  reg [31:0] Cr_next;
  reg [31:0] Ci_next;

  reg [31:0] Zr;
  reg [31:0] Zi;
  reg [31:0] Cr;
  reg [31:0] Ci;
  wire [31:0] Rr;
  wire [31:0] Ri;
  wire unbounded;

  mandelbrot_func mandelbrot (
      .Ci(Ci),
      .Cr(Cr),
      .Zr(Zr),
      .Zi(Zi),
      .Rr(Rr),
      .Ri(Ri),
      .unbounded(unbounded)
  );

  always @(posedge clk or negedge rst_n)
    if (~rst_n) begin
      Zr <= 0;
      Zi <= 0;
      Cr <= 0;
      Ci <= 0;
      Cr_next <= 0;
      Ci_next <= 0;
      o_unbounded <= 0;
      data_in_reg <= 0;
      o_iter <= 0;
    end else begin
      if (i_load_Cr) begin
        Cr_next <= data_in_word;
      end
      if (i_load_Ci) begin
        Ci_next <= data_in_word;
      end
      if (i_start) begin
        Zr <= i_load_Cr ? data_in_word : Cr_next;
        Zi <= i_load_Ci ? data_in_word : Ci_next;
        Cr <= i_load_Cr ? data_in_word : Cr_next;
        Ci <= i_load_Ci ? data_in_word : Ci_next;
        o_unbounded <= 0;
        o_iter <= 1;
      end else begin
        Zr <= Rr;
        Zi <= Ri;
        data_in_reg <= {data_in, data_in_reg[23:8]};
        if (unbounded) begin
          o_unbounded <= 1;
        end else if (!o_unbounded) begin
          o_iter <= o_iter + 1;
        end
      end
    end

  // List all unused inputs to prevent warnings
  wire _unused = &{ena, ui_in[7:3], 1'b0};