module frac_mult_18x18
(
	input   wire [0:17] a,
	input   wire [0:17] b,
	output  wire [0:35] out,
  input   wire [0:0]  mode  
);

wire [0:17] mult_ll_out;
wire [0:17] mult_lh_out;
wire [0:17] mult_hl_out;
wire [0:17] mult_hh_out;

wire [0:18] sub_result1;  // carry included
wire [0:17] sub_result2;
wire [0:35] result;

  assign sub_result1 = mult_lh_out + mult_hl_out + {9'd0, mult_ll_out[0:8]};
  assign sub_result2 = mult_hh_out + {8'd0, sub_result1[0:9]};

  assign result[27:35] = mult_ll_out[9:17];
  assign result[18:26] = sub_result1[10:18];
  assign result[0:17]  = sub_result2;

  assign out[18:35] = (mode == 1'b1) ? mult_ll_out : result[18:35];
  assign out[0:17]  = (mode == 1'b1) ? mult_hh_out : result[0:17];

  multiplier #(9) mult_ll (.a(a[9:17]), .b(b[9:17]), .out(mult_ll_out) ); // A_low*B_low
  multiplier #(9) mult_lh (.a(a[9:17]), .b(b[0:8]), .out(mult_lh_out) ); // A_low*B_high
  multiplier #(9) mult_hl (.a(a[0:8]), .b(b[9:17]), .out(mult_hl_out) ); // A_high*B_low
  multiplier #(9) mult_hh (.a(a[0:8]), .b(b[0:8]), .out(mult_hh_out) ); // A_high*B_high

endmodule