module frac_mult_36x36 
(
	input   wire [0:35] a,
	input   wire [0:35] b,
	output  wire [0:71] out,
  input   wire [0:1]  mode  
);

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

wire [0:36] sub_result1; // carry included
wire [0:35] sub_result2;
wire [0:71] result;

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

  assign result[54:71]   = mult_ll_out[18:35];
  assign result[36:53]  = sub_result1[19:36];
  assign result[0:35]  = sub_result2;

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

  frac_mult_18x18 mult_ll (.a(a[18:35]), .b(b[18:35]), .out(mult_ll_out), .mode(mode[1]) ); // A_low*B_low
  frac_mult_18x18 mult_lh (.a(a[18:35]), .b(b[0:17]), .out(mult_lh_out), .mode(1'b0) ); // A_low*B_high
  frac_mult_18x18 mult_hl (.a(a[0:17]), .b(b[18:35]), .out(mult_hl_out), .mode(1'b0) ); // A_high*B_low
  frac_mult_18x18 mult_hh (.a(a[0:17]), .b(b[0:17]),  .out(mult_hh_out), .mode(mode[1])); // A_high*B_high

endmodule