dakies/OSS_Verilog huggingface dataset:
module sub_sample( // Mean pooling
  input clock,
  input reset,
  input [`NH_VECTOR_BITWIDTH:0] nh_vector, // ` indicates a difined macro
  output [`POOL_OUT_BITWIDTH:0] pool_out
);

// parameter declarations

// wire declarations
wire [`POOL_OUT_BITWIDTH:0] adder_tree_wire [(`NEIGHBORHOOD_SIZE*2)-1-1:0]; // use n-1:0 notation to appease modelsim

// reg declarations

// assign statments
assign pool_out = adder_tree_wire[0] / `NEIGHBORHOOD_SIZE; 

genvar i;
generate
for(i=(`NEIGHBORHOOD_SIZE*2)-2; i >=1; i=i-2) begin : adder_tree
  pool_add2 pool_add2_inst(
    .clock(clock),
    .reset(reset),
    .operand_a(adder_tree_wire[i-1]),
    .operand_b(adder_tree_wire[i]),
    .sum(adder_tree_wire[(i/2)-1])
  );
end // for
endgenerate

genvar j;
generate
for(j=0; j < `NEIGHBORHOOD_SIZE; j=j+1) begin : connect_input_to_adder_tree
  assign adder_tree_wire[j+`NEIGHBORHOOD_SIZE-1] = {`POOL_TREE_PAD'd0, nh_vector[(`NN_WIDTH*j)+`NN_BITWIDTH:`NN_WIDTH*j] };
end // for
endgenerate

endmodule
module pool_add2(
  input clock,
  input reset,

  input [`POOL_OUT_BITWIDTH:0] operand_a,
  input [`POOL_OUT_BITWIDTH:0] operand_b,
  output reg[`POOL_OUT_BITWIDTH:0] sum 
);

`ifdef POOL_RESET
  always@(posedge clock or negedge reset) begin
    if(reset == 1'b0) 
      sum <= `POOL_OUT_BITWIDTH'd0;
    else  
      sum <= operand_a + operand_b;
  end // always
`else
  always@(posedge clock) begin
    sum <= operand_a + operand_b;
  end // always
`endif
endmodule
module mult_adder_ctrl(
  input clock,
  input reset,
  
  input start,
  output [`X_COORD_BITWIDTH:0] x_coord,
  output [`Y_COORD_BITWIDTH:0] y_coord,

  output pixel_rdy // indicates valid data at end of tree/pipeline
);

// wire declarations

// reg declarations
reg buffer_rdy;
reg rdy_shift_reg [`RDY_SHIFT_REG_SIZE-1:0];
reg [`X_COORD_BITWIDTH:0] x_counter;
reg [`Y_COORD_BITWIDTH:0] y_counter;


// assign statments
assign pixel_rdy = rdy_shift_reg[0];

assign x_coord = x_counter;
assign y_coord = y_counter;

// set enable when buffer_rdy strobes, unset at x/y max
always@(posedge clock or negedge reset) begin
  if(reset == 1'b0) begin
    buffer_rdy <= 1'b0; 
  end else begin
    if(start) begin 
      buffer_rdy <= 1'b1; 
		                                         // extra - 1 to prevent counter overflow from being latched
    end else if (x_counter == `X_COORD_MAX - 1 - 1 &
                 y_counter == `Y_COORD_MAX - 1) begin
      buffer_rdy <= 1'b0;
    end else begin
      buffer_rdy <= buffer_rdy;
    end
  end // reset
end // always

// x and y counters for window selectors
always@(posedge clock or negedge reset) begin
  if (reset == 1'b0) begin
    x_counter <= `X_COORD_WIDTH'd0;
    y_counter <= `Y_COORD_WIDTH'd0;
  end else if(buffer_rdy) begin
    if(x_counter < `X_COORD_MAX - 1) begin
      x_counter <= x_counter +`X_COORD_WIDTH'd1;
      y_counter <= y_counter;
    end else begin
      x_counter <= `X_COORD_WIDTH'd0;
      if(y_counter < `Y_COORD_MAX - 1)
        y_counter <= y_counter + `Y_COORD_WIDTH'd1;
      else
        y_counter <= `Y_COORD_WIDTH'd0;
    end
  end else begin // buffer is not ready
    x_counter <= `X_COORD_WIDTH'd0;
    y_counter <= `Y_COORD_WIDTH'd0;
  end // reset
end // always


// shift register to hold ready signal
genvar i;
generate
for (i=0; i < `RDY_SHIFT_REG_SIZE-1; i=i+1) begin : shift_reg_loop
  always@(posedge clock) begin
    rdy_shift_reg[i] <= rdy_shift_reg[i+1];
  end // always
end // for
endgenerate
// connect input to shift reg
always@(posedge clock) begin
  rdy_shift_reg[`RDY_SHIFT_REG_SIZE-1] <= buffer_rdy;
end

endmodule
module top_tb();
reg clock;
reg reset;

reg [`SCREEN_X_BITWIDTH:0] screen_x;
reg [`SCREEN_Y_BITWIDTH:0] screen_y;

wire [`CAMERA_PIXEL_BITWIDTH:0] pixel;

wire [`FFN_OUT_BITWIDTH:0] n0;
wire [`FFN_OUT_BITWIDTH:0] n1;

wire prdy;
parameter X_RES_MAX = 600;
parameter Y_RES_MAX = 800;

// DUT
top top_inst(
  .clock(clock),
  .reset(reset),
  .screen_x_pos(screen_x),
  .screen_y_pos(screen_y),
  .test_pixel(pixel),
  .n0(n0),
  .n1(n1),
  .product_rdy(prdy)
);

always begin
  #5 clock <= ~clock;
end

//always begin
//  #10
//  pixel = 9'b100000000;
//  #10
//  pixel = 9'b011111111;
//end
assign pixel = screen_x;

initial begin
  clock = 1'b0;
  reset = 1'b1;
  #10 reset = 1'b0;
  #10 reset = 1'b1;
  //pixel = 9'b001000000; // 0.25
  
  #300000 $stop;
end


always@(posedge clock or negedge reset) begin
  if (reset == 1'b0) begin
    screen_x <= 0;
	 screen_y <= 0;
  end else if(screen_x < X_RES_MAX) begin
    screen_x <= screen_x + 1;
  end else begin
    screen_x <= 0;
    if (screen_y < Y_RES_MAX)
      screen_y <= screen_y+1;
    else 
      screen_y <= 0;
  end // reset
end // always

endmodule
module sub_sample_tb;
 reg clock;
 reg reset;
 reg [`NH_VECTOR_BITWIDTH:0] sub_in;
 wire [`POOL_OUT_BITWIDTH:0] sub_out;
 wire [`POOL_OUT_BITWIDTH:0] element[`NEIGHBORHOOD_SIZE-1:0];
 reg [`POOL_OUT_BITWIDTH:0] tb_mean;

sub_sample dut(
  .clock(clock),
  .reset(reset),
  .nh_vector(sub_in),
  .pool_out(sub_out)
);

initial begin
  clock = 1'b0;
  reset = 1'b0;
  sub_in = 1'b0;
  tb_mean = `NN_WIDTH'd0;
end

always 
  #5 clock = !clock;

// loop ints
//integer i;
integer j;

genvar i;
generate
	for(i=0; i < `NEIGHBORHOOD_SIZE; i=i+1) begin : nh_assignment
		assign element[i] = sub_in[(`NN_WIDTH*i)+`NN_BITWIDTH:i*`NN_WIDTH];
	end  
endgenerate


initial begin
  #20 reset = 1'b1;

  #20 reset = 1'b0;

  #20 
  reset = 1'b1;
  sub_in = {$random, $random};
  
  #30
  for(j=0; j < `NEIGHBORHOOD_SIZE; j=j+1) begin 
	  $display ("Element %d = %d", j, element[j]);
		tb_mean = tb_mean +element[j];
		$display("element %d = %d",j,element[j]);
  end
	$display ("tb_mean %d sum = %d", j, tb_mean);
  tb_mean = tb_mean/`NEIGHBORHOOD_SIZE;
  $display ("tb_mean %d", tb_mean);	
  $display ("dut mean: %d", sub_out);

  if(tb_mean == sub_out) begin
    $display("PASS!");
  end else begin
    $display("FAIL!");
  end


 # 100
   $stop;
	
end
endmodule
module rect_linear_tb;
 reg clock;
 reg reset;
 reg [`NN_BITWIDTH:0] rect_in;
 wire [`NN_BITWIDTH:0] rect_out;

rect_linear dut(
  .clock(clock),
  .reset(reset),
  .rect_in(rect_in),
  .rect_out(rect_out)
);

initial begin
  clock = 1'b0;
  reset = 1'b0;
  rect_in = 1'b0;
end

always 
  #5 clock = !clock;

initial begin
  #20 reset = 1'b1;

  #20 reset = 1'b0;

  #20 
  reset = 1'b1;
  rect_in = $random;
  
  # 10
  if(rect_in[`NN_BITWIDTH] == 1'b1 && rect_out == `NN_WIDTH'd0) begin
    $display ("Pass");
  end else if(rect_in[`NN_BITWIDTH] == 1'b0 && rect_out == rect_in) begin
    $display ("Pass");
  end else begin
    $display ("Fail!!!");
    $display ("rect_in: %d", rect_in);
    $display ("rect_out: %d", rect_out); 
  end 
 
  #20 
  rect_in = $random;
  
  # 10
  if(rect_in[`NN_BITWIDTH] == 1'b1 && rect_out == `NN_WIDTH'd0) begin
    $display ("Pass");
  end else if(rect_in[`NN_BITWIDTH] == 1'b0 && rect_out == rect_in) begin
    $display ("Pass");
  end else begin
    $display ("Fail!!!");
    $display ("rect_in: %d", rect_in);
    $display ("rect_out: %d", rect_out); 
  end 
 
   #20 
  rect_in = $random;
  
  # 10
  if(rect_in[`NN_BITWIDTH] == 1'b1 && rect_out == `NN_WIDTH'd0) begin
    $display ("Pass");
  end else if(rect_in[`NN_BITWIDTH] == 1'b0 && rect_out == rect_in) begin
    $display ("Pass");
  end else begin
    $display ("Fail!!!");
    $display ("rect_in: %d", rect_in);
    $display ("rect_out: %d", rect_out); 
  end 
  
 # 100
   $finish;
	
end
endmodule
module pipeline_tb();
reg clock;
reg reset;

reg [`SCREEN_X_BITWIDTH:0] screen_x;
reg [`SCREEN_Y_BITWIDTH:0] screen_y;

wire [`CAMERA_PIXEL_BITWIDTH:0] pixel;

wire [`RECT_OUT_BITWIDTH:0] rect1;
wire [`RECT_OUT_BITWIDTH:0] rect2;
wire [`RECT_OUT_BITWIDTH:0] rect3;
wire [`RECT_OUT_BITWIDTH:0] rect4;
wire [`RECT_OUT_BITWIDTH:0] rect5;
wire [`RECT_OUT_BITWIDTH:0] rect6;
wire [`RECT_OUT_BITWIDTH:0] rect7;
wire [`RECT_OUT_BITWIDTH:0] rect0;

parameter X_RES_MAX = 600;
parameter Y_RES_MAX = 800;

// DUT
top top_inst(
  .clock(clock),
  .reset(reset),
  .screen_x_pos(screen_x),
  .screen_y_pos(screen_y),
  .test_pixel(pixel),
  .rect1(rect1),
  .rect2(rect2),
  .rect3(rect3),
  .rect4(rect4),
  .rect5(rect5),
  .rect6(rect6),
  .rect7(rect7),
  .rect0(rect0)
);

always begin
  #5 clock <= ~clock;
end

initial begin
  clock = 1'b0;
  reset = 1'b1;
  //pixel = 9'b001000000; // 0.25
  
  #1000000 $stop;
end

assign pixel = screen_x;

always@(posedge clock) begin
  if(screen_x < X_RES_MAX) begin
    screen_x <= screen_x + 1;
  end else begin
    screen_x <= 0;
    if (screen_y < Y_RES_MAX)
      screen_y <= screen_y+1;
    else 
      screen_y <= 0;
  end // reset
end // always

endmodule
module hex_out_tb;
   reg clock;
   reg reset;
   reg [(`FFN_OUT_WIDTH*`NUM_CLASSES)-1:0] test_in;
   wire [6:0] 				   test_out;
   
	reg [`FFN_OUT_BITWIDTH:0] 		   in0;
   reg [`FFN_OUT_BITWIDTH:0] 		   in1;
   reg [`FFN_OUT_BITWIDTH:0] 		   in2;
   reg [`FFN_OUT_BITWIDTH:0] 		   in3;
   reg [`FFN_OUT_BITWIDTH:0] 		   in4;
   reg [`FFN_OUT_BITWIDTH:0] 		   in5;
   reg [`FFN_OUT_BITWIDTH:0] 		   in6;
   reg [`FFN_OUT_BITWIDTH:0] 		   in7;
   reg [`FFN_OUT_BITWIDTH:0] 		   in8;
   reg [`FFN_OUT_BITWIDTH:0] 		   in9;
   wire [(`FFN_OUT_WIDTH*`NUM_CLASSES)-1:0] in_vec;
   assign in_vec = {in9,in8,in7,in6,in5,in4,in3,in2,in1,in0};
	
   hex_out_final dut(
		   .clock(clock),
		   .reset(reset),
		   .data(in_vec),
		   .hex(test_out)
		   );
   

   

initial begin
   clock = 1'b0;
   reset = 1'b0;
end
   
   always 
     #5 clock = !clock;
   
   initial begin
      in0 = 5;
      in1 = 5;
      in2 = 5;
      in3 = 5;
      in4 = 5;
      in5 = 5;
      in6 = 5;
      in7 = 5;
      in8 = 5;
      in9 = 5;
      #20 reset = 1'b1;
      
      #20 reset = 1'b0;
      
      #20 reset = 1'b1;
      
      # 10
	if(test_out == 7'b1110111) begin
	   $display ("Pass");
	end else begin
	   $display ("Fail!!!");
	   $display ("test_in: %d", in_vec);
	   $display ("test_out: %d", test_out); 
	end 
      
      #20 in0 = 10;
      # 10
	if(test_out == 7'b1000000) begin
	   $display ("Pass");
	end else begin
	   $display ("Fail!!!");
	   $display ("rect_in: %d", in_vec);
	   $display ("test_out: %d", test_out); 
	end 
      #20 in1= `FFN_OUT_WIDTH'hffffffffffffffff;
		# 10
	if(test_out == 7'b1000000) begin
	   $display ("Pass");
	end else begin
	   $display ("Fail!!!");
	   $display ("rect_in: %d", in_vec);
	   $display ("test_out: %d", test_out); 
	end 
		
		
      # 100
	$stop;
      
   end
endmodule
module np_matrix_mult_ctrl(
  input clock,
  input reset,

  input start,
  
  output reg [`FM_ADDR_BITWIDTH:0] addr,
  output reg [`RAM_SELECT_BITWIDTH:0] ram_select,
  output reg mult_en,
  output reg product_rdy
);

always @(posedge clock or negedge reset) begin
  if (reset == 1'b0) begin
    addr <= `FM_ADDR_WIDTH'd0;
    ram_select <= `RAM_SELECT_WIDTH'd0;
  end else begin
    if (start) begin
      addr <= `FM_ADDR_WIDTH'd0;
      ram_select <= `RAM_SELECT_WIDTH'd0;
    end else if( addr == `ADDR_MAX - 1) begin
      ram_select <= ram_select + `RAM_SELECT_WIDTH'd1;
      addr <= `FM_ADDR_WIDTH'd0;
    end else begin
      addr <= addr + `FM_ADDR_WIDTH'd1;
      ram_select <= ram_select;
    end 
  end // reset
end // always


// ready signal logic
always@(posedge clock or negedge reset) begin
  if(reset == 1'b0) begin
    product_rdy <= 1'b0;
  end else begin
    if(ram_select == `NUM_KERNELS - 1 & addr == `ADDR_MAX - 2 & mult_en) begin
      product_rdy <= 1'b1;
    end else begin
      product_rdy <= 1'b0;
    end // select max
  end // reset
end // always


// enable signal logic multipler module
always@(posedge clock or negedge reset) begin
	if (reset == 1'b0)
	  mult_en <= 1'b0;
	else if (start)
	  mult_en <= 1'b1;
	else if (ram_select == `NUM_KERNELS -1 & addr == `ADDR_MAX - 1)
	  mult_en <= 1'b0;
	else
	  mult_en <= mult_en;
end // always

endmodule
module np_matrix_mult(
  input clock,
  input reset,
 
   
  input [`FFN_IN_BITWIDTH:0] feature_pixel,
  input [`FFN_IN_BITWIDTH:0] weight,
  input [`FFN_OUT_BITWIDTH:0] bias,
  input en,
//  input [`NUM_MM_BUFFER-1:0] frame_rdy, assume frame is ready
  //output reg [`NUM_MM_BUFFER-1:0] reading_frame, // a vector of boolean signals. one signal per frame/feature buffer

  output [`FFN_OUT_BITWIDTH:0] sum_b
//  output reg d_val,

//  output [`FM_ADDR_BITWIDTH:0] buf_addr
);

// parameter declaration

// wire declaration
wire [`FFN_OUT_BITWIDTH:0] sum_prelatch;
//wire overflow_wire;
wire [`FFN_IN_BITWIDTH:0] fp;
wire [`FFN_IN_BITWIDTH:0] w;
wire [`FFN_OUT_BITWIDTH:0] s;
wire [`FFN_OUT_BITWIDTH:0] product;

// reg declaration
reg [`FFN_OUT_BITWIDTH:0] sum;

// assign statments
// assign buf_addr = count;
assign fp = en ? feature_pixel : `FFN_IN_WIDTH'd0;
assign w = en ? weight : `FFN_IN_WIDTH'd0;
assign s = en ? sum : `FFN_OUT_WIDTH'd0;
assign sum_b = sum + bias;

// instantiate multiplyer
// there should be no registers in mult module
mult_np_mm mult_inst(
  .clock(clock),
  .reset(reset),
  .operand_a(fp),
  .operand_b(w),
  .product(product)
);

// instantiate adder with feedback
// there should be no registers in adder
add_np_mm add_inst(
  .clock(clock), 
  .reset(reset),
  .operand_a(product),
  .operand_b(s),
  .sum(sum_prelatch)
  //.overflow(overflow_wire)
);


always@(posedge clock or negedge reset) begin
  if( reset == 1'b0) begin
    sum <= `FFN_OUT_WIDTH'd0;
  end else begin 
    sum <= sum_prelatch; // output current sum
  end
end // always


/*
// counter and data valid logic
always@(posedge clock or negedge reset) begin
  if( reset == 1'b0) begin
//    d_val <= 1'd0;
//    count <= `NP_COUNT_WIDTH'd0;
    sum <= `FFN_OUT_WIDTH'd0;
  end else if( count == `NP_COUNT_WIDTH'd`NP_MAX_COUNT) begin
//    d_val <= 1'd1;
//    count <= `NP_COUNT_WIDTH'd0;
    sum <= `FFN_OUT_WIDTH'd0; 
  end else begin 
//    d_val <= 1'd0;
//    count <= count + `NP_COUNT_WIDTH'd1;
    sum <= sum_prelatch; // output current sum
  end
end // always
*/

/*
// buffer select logic
always@(posedge clock or negedge reset) begin
  if(reset == 1'b0) begin
    reading_frame <= `NUM_MM_BUFFER'd1; // always start reading first frame buffer
  end else if( count == `NP_COUNT_WIDTH'd`NP_MAX_COUNT) begin
    reading_frame <= { reading_frame[`NUM_MM_BUFFER-2:0], reading_frame[`NUM_MM_BUFFER-1] };
  end 
end // always
*/

endmodule
module normalize(
  input clock,
  input reset,
  input [(`NN_WIDTH*`NUM_CLASSES)-1:0] in_vector,
  output [(`NORM_OUT_WIDTH*`NUM_CLASSES)-1:0] out_vector
);

//parameter declarations
//parameter `NUM_NORM_LAYERS = `LOG2(`NUM_CLASSES);
//parameter `FFN_OUT_WIDTH = `FFN_WIDTH * 2 + `LOG2(`NUM_INPUT_N);

// wire declarations
wire [`NORM_IN_BITWIDTH:0] in_vector_wire [`NUM_CLASSES];
wire [`NORM_OUT_BITWIDTH:0] adder_tree_wire [((`NUM_CLASSES)*2)-1];

// reg declarations
reg [`NORM_OUT_BITWIDTH:0] out_vector_wire [`NUM_CLASSES];


// connect input vector to wire array
genvar i;
generate
for(i = 0; i < `NUM_CLASSES; i=i+1) begin : connect_in_vector
    assign in_vector_wire[i] = in_vector[(`NN_WIDTH*i)+`NN_BITWIDTH:`NN_WIDTH*i];
    assign adder_tree_wire[i+`NUM_CLASSES-1] = { `ADDER_TREE_PAD'd0, in_vector[(`NN_WIDTH*i)+`NN_BITWIDTH:`NN_WIDTH*i] };
  end
endgenerate

// sum inputs
genvar j;
generate
for(j= (`NUM_CLASSES*2)-2 ; j >=1 ; j=j-2) begin : sum_inputs
  norm_add2 add2_inst(
    .clock(clock),
    .reset(reset),
    .operand_a(adder_tree_wire[j-1]),
    .operand_b(adder_tree_wire[j]),
    .sum(adder_tree_wire[(j/2)-1])
  );  
//assign adder_tree_wire[(j/2)-1] = adder_tree_wire[j] + adder_tree_wire[j-1];
end // for
endgenerate

// normalize inputs
genvar k;
generate
for (k=0; k < `NUM_CLASSES; k=k+1) begin : divide_by_sum
/*
  always@(posedge clock or negedge reset) begin
    if(reset == 1'b0) begin
      out_vector_wire[k] <= `NORM_OUT_BITWIDTH'd0;
    end else begin 
      out_vector_wire[k] <= in_vector_wire[k] / adder_tree_wire[0];
    end
  end // always
*/
  always@(posedge clock) begin
    out_vector_wire[k] <= in_vector_wire[k] / adder_tree_wire[0];
    end
end // for
endgenerate

// wire up output vector
genvar m;
generate
for(m=0; m < `NUM_CLASSES; m=m+1) begin : connect_out_vector
  assign out_vector[ (`NORM_OUT_WIDTH*m) + `NORM_OUT_BITWIDTH : `NORM_OUT_WIDTH * m ] = out_vector_wire[m];
end
endgenerate


endmodule
module norm_add2(
  input clock,
  input reset,

  input [`NORM_OUT_BITWIDTH:0] operand_a,
  input [`NORM_OUT_BITWIDTH:0] operand_b,
  output reg[`NORM_OUT_BITWIDTH:0] sum 
);

`ifdef NORM_RESET
always@(posedge clock or negedge reset) begin
  if(reset == 1'b0) 
    sum <= `NORM_OUT_WIDTH'd0;
  else 
    sum <= operand_a + operand_b;
end // always
`else
always@(posedge clock) begin
  sum <= operand_a + operand_b;
end // always
`endif
endmodule
module matrix_multiply( // a matrix multiply implementaion of a single layer feed forward network
  input clock,
  input reset,

  input [(`FFN_WIDTH*`NUM_INPUT_N)-1:0] input_neurons,
  input [(`FFN_WIDTH*`NUM_INPUT_N*`NUM_OUTPUT_N)-1:0] weight_matrix,
  output [(`FFN_WIDTH*2*`NUM_OUTPUT_N)-1:0] output_neurons

);

// parameter declarations

// wire declarations
wire [`FFN_BITWIDTH:0] input_n_wire [`NUM_INPUT_N];
wire [`FFN_OUT_BITWIDTH:0] output_n_wire [`NUM_OUTPUT_N];
wire [`FFN_OUT_BITWIDTH:0] product_wire [`NUM_INPUT_N][`NUM_OUTPUT_N]; // Connects to the output of the multiplieres
wire [`FFN_OUT_BITWIDTH:0] weight_matrix_wire [`NUM_INPUT_N][`NUM_OUTPUT_N];
wire [`FFN_OUT_BITWIDTH:0] sum_wire [`SUM_WIRE_LEN][`NUM_OUTPUT_N]; 

// reg declarations

genvar i;
genvar j;
generate 
  for(i=0; i < `NUM_INPUT_N; i=i+1) begin : loop_a // rename to virticlle /horizontal after weitgh matrex wire is created
    for(j=0; j < `NUM_OUTPUT_N; j=j+1) begin : loop_b
      mult2 mult2_inst(
        .clock(clock),
        .reset(reset),
        .operand_a(input_n_wire[i]),
        .operand_b(weight_matrix_wire[i][j]),
        .product(product_wire[i][j])
      );
    end // for j (output dim)
  end // for i (input dim)
endgenerate

genvar x;
generate
  for(x=0; x < `NUM_INPUT_N; x=x+1) begin : connect_input_neurons
    assign input_n_wire[x] = input_neurons[(`FFN_WIDTH*x)+`FFN_BITWIDTH:`FFN_WIDTH*x];
  end
endgenerate

genvar y;
generate
  for(y=0; y < `NUM_OUTPUT_N; y=y+1) begin : connect_sums_to_outputs
    // connect the top of the adder tree to the output 
    assign sum_wire[1][y] = output_neurons[(`FFN_WIDTH*y)+`FFN_BITWIDTH:`FFN_WIDTH*y];
  end
endgenerate

genvar z;
genvar w;
generate
  for(z=`SUM_WIRE_LEN-2 ; z <= 2; z=z-2) begin : loop_c
    for(w=0; w < `NUM_OUTPUT_N; w=w+1) begin :loop_d
      sum2 sum2_inst(
        .clock(clock),
        .reset(reset),
        .opperand_a(sum_wire[z][w]),
        .opperand_b(sum_wire[z+1][w]),
        .sum(sum_wire[z/2][w])
      );
    end
  end
endgenerate

endmodule
module add_np_mm(
  input clock,
  input reset,

  input [`FFN_OUT_BITWIDTH:0] operand_a,
  input [`FFN_OUT_BITWIDTH:0] operand_b,
  output [`FFN_OUT_BITWIDTH:0] sum
);

//wire [`FFN_OUT_BITWIDTH+1:0] sum_c; // sum with carry
//assign sum_c = operand_a + operand_b;
//assign overflow = sum_c[`FFN_OUT_BITWIDTH+1];
assign sum = operand_a + operand_b;
//assign sum = sum_c[`FFN_OUT_BITWIDTH:0];
endmodule
module add2(
  input clock,
  input reset,

  input [`FFN_OUT_BITWIDTH:0] operand_a,
  input [`FFN_OUT_BITWIDTH:0] operand_b,
  output reg[`FFN_OUT_BITWIDTH:0] sum
);

always@(posedge clock or negedge reset) begin
  if(reset == 1'b0) 
    sum <= `FFN_OUT_WIDTH'd0;
  else 
    sum <= operand_a + operand_b;
end // always

endmodule
module mult_np_mm( // Multiply 2 fixed point numbers
  input clock,
  input reset,

  input signed [`FFN_IN_BITWIDTH:0] operand_a,
  input signed [`FFN_IN_BITWIDTH:0] operand_b,

  output signed [`FFN_OUT_BITWIDTH:0] product
);

//assign product = {`CLOG(`NUM_INPUT_N)'d0, operand_a * operand_b} ;
assign product =  operand_a * operand_b ;

endmodule
module vgaHdmi(
  // **input**
  input clock, clock50, reset,
  input switchR, switchG, switchB,

  // **output**
  output reg hsync, vsync,
  output reg dataEnable,
  output reg vgaClock,
  output [23:0] RGBchannel
);

reg [9:0]pixelH, pixelV; // estado interno de pixeles del modulo

initial begin
  hsync      = 1;
  vsync      = 1;
  pixelH     = 0;
  pixelV     = 0;
  dataEnable = 0;
  vgaClock   = 0;
end

// Manejo de Pixeles y Sincronizacion

always @(posedge clock or posedge reset) begin
  if(reset) begin
    hsync  <= 1;
    vsync  <= 1;
    pixelH <= 0;
    pixelV <= 0;
  end
  else begin
    // Display Horizontal
    if(pixelH==0 && pixelV!=524) begin
      pixelH<=pixelH+1'b1;
      pixelV<=pixelV+1'b1;
    end
    else if(pixelH==0 && pixelV==524) begin
      pixelH <= pixelH + 1'b1;
      pixelV <= 0; // pixel 525
    end
    else if(pixelH<=640) pixelH <= pixelH + 1'b1;
    // Front Porch
    else if(pixelH<=656) pixelH <= pixelH + 1'b1;
    // Sync Pulse
    else if(pixelH<=752) begin
      pixelH <= pixelH + 1'b1;
      hsync  <= 0;
    end
    // Back Porch
    else if(pixelH<799) begin
      pixelH <= pixelH+1'b1;
      hsync  <= 1;
    end
    else pixelH<=0; // pixel 800

    // Manejo Senal Vertical
    // Sync Pulse
    if(pixelV == 491 || pixelV == 492)
      vsync <= 0;
    else
      vsync <= 1;
  end
end

// dataEnable signal
always @(posedge clock or posedge reset) begin
  if(reset) dataEnable<= 0;

  else begin
    if(pixelH >= 0 && pixelH <640 && pixelV >= 0 && pixelV < 480)
      dataEnable <= 1;
    else
      dataEnable <= 0;
  end
end

// VGA pixeClock signal
// Los clocks no deben manejar salidas directas, se debe usar un truco
initial vgaClock = 0;

always @(posedge clock50 or posedge reset) begin
  if(reset) vgaClock <= 0;
  else      vgaClock <= ~vgaClock;
end

// **************************************************************
// Screen colors using de10nano switches for test

assign RGBchannel[23:16] = (switchR)? 8'd255 : 8'd0;
assign RGBchannel [15:8] = (switchG)? 8'd255 : 8'd0;
assign RGBchannel  [7:0] = (switchB)? 8'd255 : 8'd0;

endmodule
module I2C_Controller (
	input  CLOCK,
	input  [23:0]I2C_DATA,	
	input  GO,
	input  RESET,	
	input  W_R,
 	inout  I2C_SDAT,	
	output I2C_SCLK,
	output END,	
	output ACK
);

wire SDAO ; 

assign I2C_SDAT = SDAO?1'bz : 1'b0  ; 

I2C_WRITE_WDATA  wrd(
   .RESET_N  ( RESET),
	.PT_CK    ( CLOCK),
	.GO       ( GO   ),
	.END_OK   ( END  ),
	.ACK_OK   ( ACK  ),
	.BYTE_NUM ( 2    ),  //2byte	
	.SDAI     ( I2C_SDAT ),//IN
	.SDAO     ( SDAO     ),//OUT
	.SCLO     ( I2C_SCLK ),	
	.SLAVE_ADDRESS( I2C_DATA[23:16] ),
	.REG_DATA     ( I2C_DATA[15:0]  )	
);	
	
	

endmodule
module I2C_WRITE_WDATA  (
   input  				RESET_N ,
	input      		  	PT_CK,
	input      		  	GO,
	input      [15:0] REG_DATA,
	input      [7:0] 	SLAVE_ADDRESS,	
	input            	SDAI,
	output reg       	SDAO,
	output reg       	SCLO,
	output reg       	END_OK,
	
	//--for test 
	output reg [7:0] 	ST ,
	output reg [7:0] 	CNT,
	output reg [7:0] 	BYTE,
	output reg       	ACK_OK,
   input      [7:0]  BYTE_NUM  // 4 : 4 byte 	
);

//===reg/wire  
reg   [8:0]A ;
reg   [7:0]DELY ;

always @( negedge RESET_N or posedge  PT_CK )begin
if (!RESET_N  ) ST <=0;
else 
	  case (ST)
	    0: begin  //start 		      
		      SDAO   <=1; 
	         SCLO   <=1;
	         ACK_OK <=0;
	         CNT    <=0;
	         END_OK <=1;
	         BYTE   <=0;	
	         if (GO) ST  <=30 ; // inital 							
		    end	  
	    1: begin  //start 
		      ST <=2 ; 
			   { SDAO,  SCLO } <= 2'b01; 
				A <= {SLAVE_ADDRESS ,1'b1 };//WRITE COMMAND
		    end
	    2: begin  //start 
		      ST <=3 ; 
			   { SDAO,  SCLO } <= 2'b00; 
		    end
			 
	    3: begin  
		      ST <=4 ; 
			   { SDAO, A } <= { A ,1'b0 }; 
		    end
	    4: begin  
		      ST <=5 ; 
			   SCLO <= 1'b1 ; 
				CNT <= CNT +1'b1 ;
		    end
			 
	    5: begin  
			   SCLO <= 1'b0 ; 
			   if (CNT==9) begin
				     if ( BYTE == BYTE_NUM )  ST <= 6 ; 
					  else  begin 
					           CNT <=0 ; 
					           ST <= 2 ;
					                if ( BYTE ==0 ) begin BYTE <=1  ; A <= {REG_DATA[15:8] ,1'b1 }; end 
					           else if ( BYTE ==1 ) begin BYTE <=2  ; A <= {REG_DATA[7:0] ,1'b1 }; end 
							  end
					  if (SDAI ) ACK_OK <=1 ; 
				 end
				 else ST <= 2;
		    end

	    6: begin          //stop
		      ST <=7 ; 
			   { SDAO,  SCLO } <= 2'b00; 
         end

	    7: begin          //stop
		      ST <=8 ; 
			   { SDAO,  SCLO } <= 2'b01; 
         end
	    8: begin          //stop
		      ST <=9 ; 
			   { SDAO,  SCLO } <= 2'b11; 
						
         end 
		9:	begin
		      ST     <= 30; 
				SDAO   <=1; 
	         SCLO   <=1;
	         CNT    <=0;
	         END_OK <=1;
	         BYTE   <=0;
		     end
		//--- END ---
		   30: begin
            if (!GO) ST  <=31;
          end			
		   31: begin  //
		      END_OK<=0;
				ACK_OK<=0;
				ST    <=1;	
			end	
	  endcase 
 end
 
endmodule
module pll_25 (
		input  wire  refclk,   //  refclk.clk
		input  wire  rst,      //   reset.reset
		output wire  outclk_0, // outclk0.clk
		output wire  locked    //  locked.export
	);

	pll_25_0002 pll_25_inst (
		.refclk   (refclk),   //  refclk.clk
		.rst      (rst),      //   reset.reset
		.outclk_0 (outclk_0), // outclk0.clk
		.locked   (locked)    //  locked.export
	);

endmodule
module  pll_25_0002(

	// interface 'refclk'
	input wire refclk,

	// interface 'reset'
	input wire rst,

	// interface 'outclk0'
	output wire outclk_0,

	// interface 'locked'
	output wire locked
);

	altera_pll #(
		.fractional_vco_multiplier("false"),
		.reference_clock_frequency("50.0 MHz"),
		.operation_mode("direct"),
		.number_of_clocks(1),
		.output_clock_frequency0("25.000000 MHz"),
		.phase_shift0("0 ps"),
		.duty_cycle0(50),
		.output_clock_frequency1("0 MHz"),
		.phase_shift1("0 ps"),
		.duty_cycle1(50),
		.output_clock_frequency2("0 MHz"),
		.phase_shift2("0 ps"),
		.duty_cycle2(50),
		.output_clock_frequency3("0 MHz"),
		.phase_shift3("0 ps"),
		.duty_cycle3(50),
		.output_clock_frequency4("0 MHz"),
		.phase_shift4("0 ps"),
		.duty_cycle4(50),
		.output_clock_frequency5("0 MHz"),
		.phase_shift5("0 ps"),
		.duty_cycle5(50),
		.output_clock_frequency6("0 MHz"),
		.phase_shift6("0 ps"),
		.duty_cycle6(50),
		.output_clock_frequency7("0 MHz"),
		.phase_shift7("0 ps"),
		.duty_cycle7(50),
		.output_clock_frequency8("0 MHz"),
		.phase_shift8("0 ps"),
		.duty_cycle8(50),
		.output_clock_frequency9("0 MHz"),
		.phase_shift9("0 ps"),
		.duty_cycle9(50),
		.output_clock_frequency10("0 MHz"),
		.phase_shift10("0 ps"),
		.duty_cycle10(50),
		.output_clock_frequency11("0 MHz"),
		.phase_shift11("0 ps"),
		.duty_cycle11(50),
		.output_clock_frequency12("0 MHz"),
		.phase_shift12("0 ps"),
		.duty_cycle12(50),
		.output_clock_frequency13("0 MHz"),
		.phase_shift13("0 ps"),
		.duty_cycle13(50),
		.output_clock_frequency14("0 MHz"),
		.phase_shift14("0 ps"),
		.duty_cycle14(50),
		.output_clock_frequency15("0 MHz"),
		.phase_shift15("0 ps"),
		.duty_cycle15(50),
		.output_clock_frequency16("0 MHz"),
		.phase_shift16("0 ps"),
		.duty_cycle16(50),
		.output_clock_frequency17("0 MHz"),
		.phase_shift17("0 ps"),
		.duty_cycle17(50),
		.pll_type("General"),
		.pll_subtype("General")
	) altera_pll_i (
		.rst	(rst),
		.outclk	({outclk_0}),
		.locked	(locked),
		.fboutclk	( ),
		.fbclk	(1'b0),
		.refclk	(refclk)
	);
endmodule
module vgaHdmi_tb;

//Internal signals declarations:
reg clock, clock50;
reg reset;
reg switchR, switchG, switchB;
wire hsync;
wire vsync;
wire dataEnable;
wire vgaClock;
wire [23:0] RGBchannel;

// Unit Under Test port map
vgaHdmi UUT (
  // input
  .clock  (clock),
  .clock50(clock50),
	.reset  (reset),
	.hsync  (hsync),
	.vsync  (vsync),

  // output
  .switchR   (switchR),
  .switchG   (switchG),
  .switchB   (switchB),
	.dataEnable(dataEnable),
  .vgaClock  (vgaClock),
  .RGBchannel(RGBchannel)
  );

initial begin
  clock   = 0;
  reset   = 1;
  switchR = 0;
  switchG = 0;
  switchB = 0;
  #10;
  reset = 0;
  forever begin
    clock = ~clock;
    #10;
  end
end

initial begin
  clock50 = 0;
  #10;
  forever begin
    clock50 = ~clock50;
    #5;
  end
end

endmodule
module mac_top
(
	input                    clk, 
	input                    rst_n,        // asynchronous reset
	input					 enable,
	input 					 valid,
	input 					 read,   // read:1 == read behave  ;  read:0 == write behave
	input                    mode,   // 1:fp16,0:int8
	input					 cfg,
	input             [15:0] in_a, 
	input             [15:0] in_b, 
	output            [15:0] mac_out,
	output					 error
);

	reg [15:0] a_reg, b_reg, c_reg;
	reg mode_reg;

	wire [15:0] a,b,c,mac_out_tmp;
	wire float_int;

	assign a         = a_reg;
	assign b         = b_reg;
	assign c         = c_reg;
	assign float_int = mode_reg;
	assign mac_out   = (read && enable && ~valid) ? mac_out_tmp : 16'b0 ; // read out mac_out with condition

//---------------------------------------------------------
//   MAC
//---------------------------------------------------------	
	always @ ( posedge clk or negedge rst_n ) begin
		if ( ! rst_n ) begin
			a_reg    <= 16'b0 ;
			b_reg    <= 16'b0 ;
			c_reg    <= 16'b0;
			mode_reg <= 1'b0;
		end else if(enable) begin

			if (valid) begin 
				a_reg   <= in_a ;
				b_reg   <= in_b ;
				c_reg   <= mac_out_tmp;
			end
			else if (read) begin // reset data after read operation
				c_reg <= 16'b0;
				a_reg <= 16'b0;
				b_reg <= 16'b0;
			end

		end else if (cfg) begin
			mode_reg <= mode;
		end 
	end 

	mac_unit u_mac (
	`ifdef PIPLINE
		 .clk     (clk        ),
		 .rst_n   (rst_n      ),
	`endif
		 .in_a    (a          ),
		 .in_b    (b          ),
		 .in_c    (c          ),
		 .mode    (float_int  ),
		 .mac_out (mac_out_tmp),
		 .error	  (error      )
	);

endmodule
module mac_unit
(
`ifdef PIPLINE
	input            clk,
	input            rst_n,
`endif
	input     [15:0] in_a, // multiplier input1
	input     [15:0] in_b, // multiplier input2
	input     [15:0] in_c, // adder input2 ; adder input1 = in_a*in_b
	input 	     	 mode,
	output    [15:0] mac_out,
	output 		     error
);

	wire [15:0] mul_out;

	int_fp_add add(
	`ifdef PIPLINE
		.clk   (clk    ),
		.rst_n (rst_n  ),
	`endif 
		.mode  ( mode  ) ,
		.a     (mul_out) ,
		.b     ( in_c  ) ,
		.c     (mac_out)
	);


	int_fp_mul mul(
	`ifdef PIPLINE
		.clk   (clk    ),
		.rst_n (rst_n  ),
	`endif 
		.mode  ( mode  ) ,
		.a     ( in_a  ) ,
		.b     ( in_b  ) ,
		.c     (mul_out),
		.error (error  )
	);

endmodule
module mul_normalizer (
	input  [ 4:0] exponent,
	input  [21:0] mantissa_prod,
	output [14:0] result
);

	wire [4:0] result_exponent;
	wire [9:0] result_mantissa;

	assign result_exponent = (mantissa_prod[21]) ? (exponent + 1'b1): exponent;
	assign result_mantissa = (mantissa_prod[21]) ? mantissa_prod[20:11]:mantissa_prod[19:10];
	assign result 		   = {result_exponent,result_mantissa};

// No rounding and No overflow/underflow detection

endmodule
module int_fp_mul (
`ifdef PIPLINE
    input         clk,
    input         rst_n,
`endif
    input         mode,
    input  [15:0] a,
    input  [15:0] b,
    output [15:0] c,
    output        error // valid in fp16 mode 
    );

    wire [15:0] c_tmp;
    wire        c_sign,a_zero,b_zero;
    wire [4:0] sum_exponent, biased_sum_exponent;
    wire [15:0] multiplier_input1,multiplier_input2;

    wire [31:0] multiplier_output;
    wire [14:0] normalized_out;
    wire [21:0] mantissa_prod;
    wire c1,c2,underflow,overflow;

    assign overflow = (c1 && c2 && ~biased_sum_exponent[4]) ? 1'b1 :1'b0;
    assign underflow = (~c1 && ~c2 && biased_sum_exponent[4]) ? 1'b1:1'b0;

    assign a_zero = ~(|a);
    assign b_zero = ~(|b);
    assign c_sign = a[15] ^ b[15];
    assign multiplier_input1 = mode ? {5'b0,1'b1,a[9:0]} : ((a[7]==1'b0) ? {9'b0,a[6:0]} : {9'b0,~a[6:0]+1'b1});
    assign multiplier_input2 = mode ? {5'b0,1'b1,b[9:0]} : ((b[7]==1'b0) ? {9'b0,b[6:0]} : {9'b0,~b[6:0]+1'b1});
    
    assign c = mode ? ((a_zero | b_zero) ? 16'b0 : c_tmp) : ((a[7]^b[7] == 1'b0) ? multiplier_output[15:0] : {1'b1,~multiplier_output[14:0]+1'b1});
    //error detect
    assign c_tmp = (~error) ? {c_sign,normalized_out} : (underflow ? {c_sign,15'b0000_0000_0000_000} : {c_sign,5'b1111_1,10'b0000_0000_00});
    
    assign error = overflow | underflow; 

    
`ifdef PIPLINE

    reg [31:0] multiplier_output_tmp;
    
    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            multiplier_output_tmp <= 32'b0;
        end else begin
            multiplier_output_tmp <= multiplier_output;
        end
    end
    
    assign mantissa_prod = multiplier_output_tmp[21:0];
    mul16x16 u1(clk,rst_n,multiplier_input1,multiplier_input2,multiplier_output);

`else 

    assign mantissa_prod = multiplier_output[21:0];
    mul16x16 u1(multiplier_input1,multiplier_input2,multiplier_output);

`endif
    
    cla_nbit #(.n(5)) u2(a[14:10],b[14:10],1'b0,sum_exponent,c1); // add exponent
    cla_nbit #(.n(5)) u3(sum_exponent, 5'b10001,1'b0,biased_sum_exponent,c2); // minus bias
    mul_normalizer u4(biased_sum_exponent,mantissa_prod,normalized_out);

endmodule
module mul4x4(
	input  [3:0] a,
	input  [3:0] b,
	output [7:0] c
	);

	wire [15:0] tmp1;
	wire [ 5:0] result1;
	wire [ 5:0] result2;
	wire 		co1,co2,co3;

	mul2x2 u1(a[3:2],b[3:2],tmp1[15:12]);
	mul2x2 u2(a[1:0],b[3:2],tmp1[11:8]);
	mul2x2 u3(a[3:2],b[1:0],tmp1[7:4]);
	mul2x2 u4(a[1:0],b[1:0],tmp1[3:0]);

	cla_nbit #(.n(6)) u5({tmp1[15:12],2'b0},{2'b0,tmp1[11:8]},1'b0	,result1	,co1);
	cla_nbit #(.n(6)) u6({2'b0,tmp1[7:4]}  ,{4'b0,tmp1[3:2]} ,co1 	,result2	,co2);
	cla_nbit #(.n(6)) u7(result1		   ,result2			 ,co2 	,c[7:2] 	,co3);

	assign c[1:0] = tmp1[1:0];

endmodule
module mul8x8(
	input  [ 7:0] a,
	input  [ 7:0] b,
	output [15:0] c
);

	wire [31:0] tmp1;
	wire [11:0] result1;
	wire [11:0] result2;
	wire co1,co2,co3;

	mul4x4 u1(a[7:4],b[7:4],tmp1[31:24]);
	mul4x4 u2(a[3:0],b[7:4],tmp1[23:16]);
	mul4x4 u3(a[7:4],b[3:0],tmp1[15:8]);
	mul4x4 u4(a[3:0],b[3:0],tmp1[7:0]);

	cla_nbit #(.n(12)) u5({tmp1[31:24],4'b0} ,{4'b0,tmp1[23:16]} ,1'b0 ,result1 ,co1);
	cla_nbit #(.n(12)) u6({4'b0,tmp1[15:8]}  ,{8'b0,tmp1[7:4]}   ,co1  ,result2 ,co2);
	cla_nbit #(.n(12)) u7(result1			 ,result2			 ,co2  ,c[15:4] ,co3);

	assign c[3:0] = tmp1[3:0];

endmodule
module mul2x2(
	input  [1:0] a,
	input  [1:0] b,
	output [3:0] c
	);

	wire [3:0] tmp;
	
	assign tmp[0] = a[0] & b[0];
	assign tmp[1] = (a[1]&b[0]) ^ (a[0]&b[1]);
	assign tmp[2] = (a[0]&b[1]) & (a[1]&b[0]) ^ (a[1]&b[1]);
	assign tmp[3] = (a[0]&b[1]) & (a[1]&b[0]) & (a[1]&b[1]);
	assign c 	  = {tmp[3],tmp[2],tmp[1],tmp[0]};

endmodule
module mul16x16(
`ifdef PIPLINE
    input clk,
    input rst_n,
`endif
    input  [15:0] a,
    input  [15:0] b,
    output [31:0] c);

    wire [63:0] tmp1,tmp2;
    wire [23:0] result1;
    wire [23:0] result2;
    wire co1,co2,co3;

`ifdef PIPLINE
	// one stage pipline
	reg [63:0] tmp1_reg;
    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            tmp1_reg <= 64'b0;
        end else begin
            tmp1_reg <= tmp1;
        end
    end
    assign tmp2 = tmp1_reg;

`else 
	assign tmp2 = tmp1;

`endif

    mul8x8 u1(a[15:8],b[15:8],tmp1[63:48]);
    mul8x8 u2(a[7:0] ,b[15:8],tmp1[47:32]);
    mul8x8 u3(a[15:8],b[ 7:0],tmp1[31:16]);
    mul8x8 u4(a[7:0] ,b[ 7:0],tmp1[15:0]);

    cla_nbit #(.n(24)) u5({tmp2[63:48],8'b0} ,{8'b0,tmp2[47:32]} ,1'b0 ,result1 ,co1);
    cla_nbit #(.n(24)) u6({8'b0,tmp2[31:16]} ,{16'b0,tmp2[15:8]} ,co1  ,result2 ,co2);
    cla_nbit #(.n(24)) u7(result1            ,result2            ,co2  ,c[31:8] ,co3);

    assign c[7:0] = tmp2[7:0];

endmodule
module add_normalizer (
    input             sign,
    input      [ 4:0] exponent,
    input      [10:0] mantissa_add,
    output reg [15:0] result,
    input             if_carray,
    input             if_sub
    );

    reg [4:0] number_of_zero_lead;
    reg [10:0] norm_mantissa_add;
    reg [9:0] mantissa_tmp;

    wire [4:0] shift_left_exp;
    wire c1;

    always @ (*) begin
        if (mantissa_add[10:4] == 7'b0000_001) begin
            number_of_zero_lead = 5'd6;
            norm_mantissa_add   = (mantissa_add << 4'd6);
        end else if (mantissa_add[10:5] == 6'b0000_01) begin 
            number_of_zero_lead = 5'd5;
            norm_mantissa_add   = (mantissa_add << 4'd5);
        end else if (mantissa_add[10:6] == 5'b0000_1) begin
            number_of_zero_lead = 5'd4;
            norm_mantissa_add   = (mantissa_add << 4'd4);
        end else if (mantissa_add[10:7] == 4'b0001) begin
            number_of_zero_lead = 5'd3;
            norm_mantissa_add   = (mantissa_add << 4'd3);
        end else if (mantissa_add[10:8] == 3'b001) begin
            number_of_zero_lead = 5'd2;
            norm_mantissa_add   = (mantissa_add << 4'd2);
        end else if (mantissa_add[10:9] == 2'b01) begin
            number_of_zero_lead = 5'd1;
            norm_mantissa_add   = (mantissa_add << 4'd1);
        end else begin 
            number_of_zero_lead = 5'd0;
            norm_mantissa_add   = mantissa_add[10:0];
        end 
    end

    always @(*) begin
        result[15]        = sign;
        if (!if_sub) begin 
            result[14:10] = if_carray ? exponent + 1'b1 : exponent;
            result[9:0]   = if_carray ? mantissa_add[10:1] : mantissa_add[9:0];
        end else begin 
            result[14:10] = shift_left_exp;
            result[9:0]   = norm_mantissa_add[9:0];
        end 
    end

    cla_nbit #(.n(5)) u1(exponent,~number_of_zero_lead+1'b1,1'b0,shift_left_exp,c1);


endmodule
module int_fp_add (
`ifdef PIPLINE
    input         clk,
    input         rst_n,
`endif
    input         mode,
    input  [15:0] a,
    input  [15:0] b,
    output [15:0] c
    );

    wire [10:0] adder_input_1,adder_input_2,aligned_small,adder_output;
    wire if_sub,a_sign, b_sign, c_sign,c1;
    wire [15:0] normalized_out;

    // only used in INT8 MAC mode
    wire [4:0] higher_add,higher_a,higher_b;

    wire [15:0] result;
    reg [14:0] bigger, smaller;
    reg a_larger_b;

`ifdef PIPLINE
    reg [14:0] bigger_reg, smaller_reg;
    reg [10:0] adder_output_reg;
    wire [14:0] bigger_tmp, smaller_tmp;
    wire [10:0] adder_output_tmp;
`endif  


    assign a_sign        = a[15];
    assign b_sign        = b[15];
    assign if_sub        = (a_sign == b_sign) ? 1'b0 : 1'b1;
    assign c_sign        = a_larger_b ? a_sign : b_sign;
    assign higher_a      = (mode == 1'b0) ? a[15:11] : 5'b0;
    assign higher_b      = (mode == 1'b0) ? b[15:11] : 5'b0;
    assign adder_input_1 = (mode==1'b0) ? a[10:0] :{1'b1,bigger[9:0]};
    assign adder_input_2 = (mode==1'b0) ? b[10:0] : (if_sub ? ~aligned_small + 1'b1 : aligned_small);
    assign c             = (mode == 1'b0) ? {higher_add,adder_output} : result;

    //compare two number regardless sign
    always @(*) begin
        if (a[14:0] > b[14:0]) begin
            bigger = a[14:0];
            smaller = b[14:0];
            a_larger_b = 1'b1;
        end else begin 
            bigger = b[14:0];
            smaller = a[14:0];
            a_larger_b = 1'b0;
        end 
    end

`ifdef PIPLINE 
    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            bigger_reg <= 15'b0;
            smaller_reg <= 15'b0;
            adder_output_reg <= 11'b0;
        end else begin
            bigger_reg <= bigger;
            smaller_reg <= smaller;
            adder_output_reg <= adder_output;
        end
    end
    assign bigger_tmp = bigger_reg[14:0];
    assign smaller_tmp = smaller_reg[14:0];
    assign adder_output_tmp = adder_output_reg[10:0];
`endif

`ifdef PIPLINE
    // align small number
    alignment u1(bigger_tmp,smaller_tmp,aligned_small);
`else 
    // align small number
    alignment u1(bigger,smaller,aligned_small);
`endif

    cla_nbit #(.n(11)) u2(adder_input_1,adder_input_2,1'b0,adder_output,c1);

    // This 5 bit adder only used in INT8 MAC mode
    cla_nbit #(.n(5)) u3(higher_a,higher_b,c1,higher_add,c2);

`ifdef PIPLINE
    add_normalizer u4(c_sign,bigger[14:10],adder_output_tmp,result,c1,if_sub);
`else 
    add_normalizer u4(c_sign,bigger[14:10],adder_output,result,c1,if_sub);
`endif

endmodule
module alignment (
	input  [14:0] bigger, 
	input  [14:0] smaller,
	output [10:0] aligned_small
	);

	wire c1;
	wire [4:0] bigger_exponent, smaller_exponent,shift_bits;

	assign bigger_exponent  = bigger  [14:10];
	assign smaller_exponent = smaller [14:10];
	assign aligned_small    = ({1'b1,smaller[9:0]} >> shift_bits);

	cla_nbit #(.n(5)) u1(bigger_exponent,~smaller_exponent+1'b1,1'b0,shift_bits,c1);

endmodule
module cla_nbit #(
    parameter n = 4
) (
  input   [n-1:0] a,
  input   [n-1:0] b,
  input           ci,
  output  [n-1:0] s,
  output          co
  );

  wire [n-1:0] g;
  wire [n-1:0] p;
  wire [  n:0] c;

  assign c[0] = ci;
  assign co   = c[n];

  genvar i;  /* i - generate index variable */

  generate
    for (i = 0; i < n; i = i + 1) begin : addbit
      assign s[i] = a[i] ^ b[i] ^ c[i];
      assign g[i] = a[i] & b[i];
      assign p[i] = a[i] | b[i];
      assign c[i + 1] = g[i] | (p[i] & c[i]);
    end
  endgenerate
  
endmodule
module int_fp_mul_tb ();

reg [15:0] input1,input2;
reg [15:0] expected;
reg mode;
reg [48:0] pattern [0:`PATTERN_NUM-1];
reg [7:0] error_cnt;
wire error;

integer i;

wire [15:0] result;
int_fp_mul u1 (mode,input1,input2,result,error);

initial begin
    error_cnt = 0;
    #30;
    for(i=0;i<`PATTERN_NUM;i=i+1) begin
        {input1,input2,expected,mode} = pattern[i];
        #10;
        $display("expected: %b actual:%b",expected,result);
        if (expected == result) begin 
            $display("Check PASSED");
            $display("--------------------");
        end else begin
            error_cnt = error_cnt + 1;
        end
    end
    #10;
    $display("Total error count: %d",error_cnt);
    #10;
    $finish;
end
    
initial begin 
    $dumpfile("int_fp_mul.vcd");
    $dumpvars;
end


initial begin 
    $readmemb(`PATTERN,pattern);
end

endmodule
module int_fp_add_tb ();

reg [15:0] input1,input2;
reg [15:0] expected;
reg mode;
reg [48:0] pattern [0:`PATTERN_NUM-1];
reg [7:0] error_cnt;

integer i;

wire [15:0] result;
int_fp_add u1 (mode,input1,input2,result);

initial begin
    error_cnt = 0;
    #30;
    for(i=0;i<`PATTERN_NUM;i=i+1) begin
        {input1,input2,expected,mode} = pattern[i];
        #40
        $display("expected: %b actual:%b",expected,result);
        if (expected == result) begin 
            $display("Check PASSED");
            $display("--------------------");
        end else begin
            error_cnt = error_cnt + 1;
        end
    end
    #10;
    $display("Total error count: %d",error_cnt);
    #10;
    $finish;
end

initial begin 
    $dumpfile("int_fp_add.vcd");
    $dumpvars;
end


initial begin 
    $readmemb(`PATTERN,pattern);
end

endmodule
module mac_tb ;
//------------------------------------------------------
// reg && wire
//------------------------------------------------------
reg  [15:0] a ,b, c                     ; 
wire [15:0] mac_out                    ;
reg [15:0] expected						;
reg mode;
reg [7:0] error_cnt;

reg [64:0] pattern [0:`PATTERN_NUM-1];
integer i;

initial begin
    error_cnt = 0;
    #30;
    for(i=0;i<`PATTERN_NUM;i=i+1) begin
        {a,b,c,expected,mode} = pattern[i];
        #10;
        $display("expected: %b actual:%b",expected,mac_out);
        if (expected == mac_out) begin 
            $display("Check PASSED");
            $display("--------------------");
        end else begin
            error_cnt = error_cnt + 1;
        end
    end
    #10;
    $display("Total error count: %d",error_cnt);
    #10;
    $finish;
end

initial begin
   $dumpfile("mac.vcd");
   $dumpvars;
end

initial begin 
    $readmemb(`PATTERN,pattern);
end

mac_unit u0_mac
(.in_a         ( a  )
,.in_b        ( b )
,.in_c			(c)
,.mode			(mode)
,.mac_out          ( mac_out   )
);


endmodule
module mul16x16_tb ();
reg  [15:0] a;
reg  [15:0] b;
wire [31:0] c;

reg [31:0] tmp;

initial begin
    a = 16'd5;
    b = 16'd4;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c); 
    #20
    a = 16'd7;
    b = 16'd3;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c); 
    #20
    a = 16'd9;
    b = 16'd8;
    tmp <= a*b;
    #100 
    $display("expected: %d actual:%d",tmp,c);
    #20
    a = 16'd256;
    b = 16'd256;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c);
    #20 
    a = 16'd1000;
    b = 16'd500;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c);
    #20 
    a = 16'd2300;
    b = 16'd3500;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c);
    #20
    a = -16'd5;
    b = 16'd4;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c); 
    #20
    a = 16'sd7;
    b = -16'sd3;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c); 
    #20
    a = -16'sd10;
    b = -16'sd20;
    tmp <= a*b;
    #100
    $display("expected: %d actual:%d",tmp,c); 
    #20
    $finish;
end 

mul16x16 u1 (a,b,c);

endmodule
module ice40_resetn(
                    input  clk, 
                    output resetn
                    );


   reg [7:0]               reset_cnt;
   initial 
     begin 
        reset_cnt = 0;
     end
   
   
   assign resetn = &reset_cnt;

   always @(posedge clk) begin
      reset_cnt <= reset_cnt + !resetn;
   end
   /*
    wire [7:0]   cnt;
    wire [7:0]   cnt_in;
    wire         cnt_en;
    wire         r_resetn;
    FD1P3XZ u_cnt_reg [7:0] (
    .D(cnt_in),
    .SP(cnt_en),
    .CK(clk),
    .SR(1'b0),
    .Q(cnt));
    defparam u_cnt_reg[7].REGSET = "RESET";
    defparam u_cnt_reg[6].REGSET = "RESET";
    defparam u_cnt_reg[5].REGSET = "RESET";
    defparam u_cnt_reg[4].REGSET = "RESET";
    defparam u_cnt_reg[3].REGSET = "RESET";
    defparam u_cnt_reg[2].REGSET = "RESET";
    defparam u_cnt_reg[1].REGSET = "RESET";
    defparam u_cnt_reg[0].REGSET = "RESET";
    defparam u_cnt_reg[7].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[6].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[5].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[4].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[3].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[2].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[1].SRMODE = "CE_OVER_LSR";
    defparam u_cnt_reg[0].SRMODE = "CE_OVER_LSR";
    
    
    FD1P3XZ u_r_resetn0 (
    .D(1'b1 ),
    .SP(!cnt_en),
    .CK(clk),
    .SR(1'b0),
    .Q(r_resetn));
    defparam u_r_resetn0.REGSET = "RESET";
    defparam u_r_resetn0.SRMODE = "CE_OVER_LSR";

    assign resetn = r_resetn;

    assign cnt_in = cnt + 8'd1;

    assign cnt_en = (cnt != 8'hff);
    */
   
endmodule
module ram_sdp #(
	parameter integer AWIDTH = 9,
	parameter integer DWIDTH = 8
)(
	input  wire [AWIDTH-1:0] wr_addr,
	input  wire [DWIDTH-1:0] wr_data,
	input  wire wr_ena,

	input  wire [AWIDTH-1:0] rd_addr,
	output reg  [DWIDTH-1:0] rd_data,
	input  wire rd_ena,

	input  wire clk
);
	// Signals
	reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];

`ifdef SIM
	integer i;
	initial
		for (i=0; i<(1<<AWIDTH); i=i+1)
			ram[i] = 0;
`endif

	always @(posedge clk)
	begin
		// Read
		if (rd_ena)
			rd_data <= ram[rd_addr];

		// Write
		if (wr_ena)
			ram[wr_addr] <= wr_data;
	end

endmodule // ram_sdp
module delay_bit #(
	parameter integer DELAY = 1
)(
	input  wire d,
	output wire q,
	input  wire clk
);

	reg [DELAY-1:0] dl;

	generate
		if (DELAY > 1)
			always @(posedge clk)
				dl <= { dl[DELAY-2:0], d };
		else
			always @(posedge clk)
				dl <= d;
	endgenerate

	assign q = dl[DELAY-1];

endmodule // delay_bit
module delay_bus #(
	parameter integer DELAY = 1,
	parameter integer WIDTH = 1
)(
	input  wire [WIDTH-1:0] d,
	output wire [WIDTH-1:0] q,
	input  wire clk
);

	genvar i;
	reg [WIDTH-1:0] dl[0:DELAY-1];

	always @(posedge clk)
		dl[0] <= d;

	generate
		for (i=1; i<DELAY; i=i+1)
			always @(posedge clk)
				dl[i] <= dl[i-1];
	endgenerate

	assign q = dl[DELAY-1];

endmodule // delay_bus
module delay_toggle #(
	parameter integer DELAY = 1
)(
	input  wire d,
	output wire q,
	input  wire clk
);

	// FIXME: TODO

endmodule // delay_toggle