//********************************************************************************************
// histogramming package for radiation tests                                                                     *
// v 3.1/jb/january2022                                                                      *
//                                                                                           *
//                                                                                           *
//control signals decoder                                                                    *
//                 hist_control[21:0]   //max number of hits in histogram             or     *
//                                      //    number of histogram bins to be cleared  or     *
//                                      //    number of histogram bins to be read-out        *
//                 hist_control[25:24]  //histogram operation                                *
//                 hist_control   [26]  //former ADC data bits selection bit, now reserved   *
//                                                                                           *
//Histogram operation is started with 'start_op' pulse                                       *
//                                                                                           *
//Type of operation is defined by bits [25:24]  = 01 init histogram bins with zero           *
//                                                10 read histogram data                     *
//                                                11 perform histograming of 'h_data' inputs * 
//                                                                                           *
//********************************************************************************************
//                                                histogram multiplexer control              *
//                                                                                           *
//                                      [27:26]    histogram 1 inputs                        *
//                                          01     coluta F1                                 *
//                                          10     ch2                                       *
//                                          11     coluta F8                                 *
//                                      [29:28]    histogram 2 inputs                        *
//                                          00     coluta ch1                                *
//                                          01     coluta ch2                                *
//                                          10     coluta ch3                                *
//                                          11     coluta ch4                                *
//                                      [31:30]    histogram 2 inputs                        *
//                                          00     coluta ch5                                *
//                                          01     coluta ch6                                *
//                                          10     coluta ch7                                *
//                                          11     coluta ch8                                *
//                                                                                           *
//                                      [33:32]   histogram output multiplexer               *
//                                        01       histogram1 output selected                *
//                                        10       histogram2 output selected                *
//                                        11       histogram3 output selected                *
//********************************************************************************************
//                                      [39:34]   sampling memory input control              *
//                                                                                           *
//                                      [37:34] Coluta dual port input control               *
//                                        0000  coluta  F1                                   *
//                                        0001  coluta ch1                                   *
//                                        0010  coluta ch2                                   *
//                                        0011  coluta ch3                                   *
//                                        0100  coluta ch4                                   *
//                                        0101  coluta ch5                                   *
//                                        0110  coluta ch6                                   *
//                                        0111  coluta ch7                                   *
//                                        1000  coluta ch8                                   *
//                                        1001  coluta  F8                                   *
//                                                                                           *
//                                             9650 dual port memeory is small and not muxed *
//                                                                                           *
//                                                                                           *
//                                      [39:38] ADC121 dual port input control               *
//                                          00  ADC121/1                                     *
//                                          01  ADC121/2                                     *
//                                          10  ADC121/3                                     *
//                                          11  ADC121/4                                     *
//********************************************************************************************
//                                                                                           *
//  notes: Output bin memory is initialized with "0" during taking the histogram.            *
//         We need more h7f cycles to do so. As the result, number of hits required          *
//         for the histogtam should be more than h7f.                                        *
//                                                                                           *
//                                                                                           *
//         Histogram data memory is filled with "0" during "init histogram" command or       *
//         during "read histogram" command.                                                  *
//                                                                                           * 
//         As a consequence, right command sequence is :                                     *
//          -init histograms                                                                 *
//          -perform histogramming                                                           *
//          -read histogramm data                                                            *
//          -perform histogramming                                                           *
//          -read histogramm data                                                            *
//          -...                                                                             *
//                                                                                           *
//  note for Jaro:  do not try to debug/correct this code                                    *
//                  without the simulator. It is way too complicated for you                 *
//********************************************************************************************              


module histogram
     ( 
      input            rst,          //master reset   
      input            clk,          //160MHz clock
      input      [25:0]hist_control,
		
      input            start_op,     //pulse, hist operation start
                                 //       if init_ram=rd_hist=0, start histograming	   
      input      [15:0]h_data,       //data to be histogrammed

      input            h_rd_clk,     //read clock for histogram bins
      input       [6:0]h_rd_address, //histogram bin read address
      output     [36:0]h_data_out,   //histogram bin data (address and count)
	  output reg [21:0]ovflw_counter //overflow bit counter bin
     );

	  
	  
//register variables
reg  [14:0] ram_addr;
reg  [15:0] init_ram_cntr, rd_ram_cntr ; 
reg  [21:0] hit_cnt ;
reg         eop_i, eop_h, eop_r, wren, op_in_progress;
reg        overflow_bit_r1, overflow_bit_r2, overflow_bit_r3, overflow_bit_changed;

reg   [3:0] ph;
reg   [2:0] start_op_sr;
reg         start, start_del;
reg  [21:0] ram_data_in;

//wire variables
wire [21:0] hist_data_out;
wire [21:0] n_of_hits;
wire        init_ram, rd_hist, take_hist;   
wire        ageb_1, ageb_2;

//
//main body starts here
//


//control signals decoder********************************************************************
assign n_of_hits = hist_control[21:0];//max number of hits in histogram                     *
//                                       or                                                 *
//                                      number of histogram bins to be cleared              *
//                                       or                                                 *
//                                      number of histogram bins to be read-out             *
//                                                                                          *
//                                                                                          *
    assign init_ram  = (hist_control[25:24]==2'b01);//reset histogram memory content to zero*
    assign rd_hist   = (hist_control[25:24]==2'b10);//read the histogram data               *
//                                                  during read operation the histogram bins*
//                                                  are cleared                             *
    assign take_hist = (hist_control[25:24]==2'b11);//                                      *
//*******************************************************************************************


//start operation flag, micro cycle state machine implemented by ph[3:0] register 
always @(posedge clk)
begin
   if (rst) 
    begin
     start_op_sr <= 3'b000;
     start       <= 1'b0;
     ph          <= 4'b0000;
    end
   else
    begin
     start_op_sr[2:0] <= {start_op_sr[1:0], start_op};
     start            <= ~start_op_sr[1] & start_op_sr[0];
     start_del        <= start;  

//phase of hist read/write cycle
//ph[0] read
//ph[1] idle1   wait for dp ram output
//ph[2] idle2   wait for dp ram output
//ph[3] write	

    if (start_del )           ph[3:0] <= {ph[2:0], 1'b1 };
    else if (op_in_progress)  ph[3:0] <= {ph[2:0], ph[3]};
    else 	                  ph[3:0] <= 4'b0000;
	end
end




always @(posedge clk)
begin		
//counter for init operation
    if (rst)                            init_ram_cntr <= {15{1'b0}};
    else if (!(start | op_in_progress)) init_ram_cntr <= {15{1'b0}};
    else if (start & init_ram)          init_ram_cntr <= n_of_hits[14:0];
    else if (init_ram & op_in_progress) init_ram_cntr <= init_ram_cntr - 15'b000000000000001 ;

//read dp ram address counter
    if (rst)                            rd_ram_cntr   <= {15{1'b0}};
    else if (!(start | op_in_progress)) rd_ram_cntr   <= {15{1'b0}};	 
    else if (start & rd_hist)           rd_ram_cntr   <= n_of_hits[14:0];
    else if (rd_hist & op_in_progress)  rd_ram_cntr   <= rd_ram_cntr   - 15'b000000000000001 ;

//hit counter	
    if (rst)                            hit_cnt <= {22{1'b0}};
    else if (!op_in_progress)           hit_cnt <= {22{1'b0}};
    else if (start)                     hit_cnt <= {22{1'b0}};
    else if ((init_ram | rd_hist) &
                  op_in_progress)       hit_cnt <= hit_cnt + 22'b0000000000000000000001 ;
    else if (ph[1])                     hit_cnt <= hit_cnt + 22'b0000000000000000000001 ;
			
//dual port memory read/write address
    if      (rst )                           ram_addr <= {15{1'b0}};
    else if (!op_in_progress)                ram_addr <= {15{1'b0}};
    else if (init_ram )                      ram_addr <= init_ram_cntr[14:0];
    else if (rd_hist  )                      ram_addr <= rd_ram_cntr[14:0];
    else if (take_hist & (start_del | wren)) ram_addr <= h_data[14:0];
	 
//overflow bit counter
//detect the change
    if  (take_hist & (start_del | wren)) 
	 begin
	  overflow_bit_r1      <= h_data[15];
	  overflow_bit_r2      <= overflow_bit_r1;
	  overflow_bit_r3      <= overflow_bit_r2;
	  overflow_bit_changed <= h_data[15];//(!overflow_bit_r1 &  overflow_bit_r2 & !overflow_bit_r3); //|
	                          //( overflow_bit_r1 & !overflow_bit_r2 &  overflow_bit_r3)  ;
	 end
//count the number of changes
    if     (start & take_hist)    ovflw_counter <= 	{22{1'b0}};
	 else if (rst)                 ovflw_counter <= 	{22{1'b0}};
	 else if (op_in_progress & take_hist & overflow_bit_changed & ph[2])
	                              ovflw_counter <= ovflw_counter + 22'b0000000000000000000001 ;
	 
//end of operation for init operation
     if      (rst)                                     eop_i <= 1'b0;
     else if (start | (!op_in_progress))               eop_i <= 1'b0;
     else if (init_ram  & (init_ram_cntr=={12{1'b0}})) eop_i <= 1'b1;

	  
//end of operation for read operation
     if      (rst)                                     eop_r <= 1'b0;
     else if (start | (!op_in_progress))               eop_r <= 1'b0;
     else if (rd_hist   & (  rd_ram_cntr=={12{1'b0}})) eop_r <= 1'b1; 
	  

//end of operation for histogramming operation
     if      (rst)                                     eop_h <= 1'b0;
     else if (start | (!op_in_progress))               eop_h <= 1'b0;	 
     else if (take_hist & (ageb_1 | ageb_2))           eop_h <= 1'b1; 
	 
//operation in progress
     if      (rst)                                op_in_progress <= 1'b0;
     else if (start)                              op_in_progress <= 1'b1;
     else if (init_ram  & eop_i)                  op_in_progress <= 1'b0; 
     else if (rd_hist   & eop_r)                  op_in_progress <= 1'b0; 
     else if (take_hist & eop_h)                  op_in_progress <= 1'b0;
end



//hit comparisons
hit_compare	hit_comp_1   //number of hits is geat or equal than required number
   (
	.clock ( clk ),       //pipeline delay of 1 
	.dataa ( hit_cnt ),
	.datab ( n_of_hits ),
	.ageb  ( ageb_1 )
	);

hit_compare	hit_comp_2   //hit overflow detection
   (
	.clock ( clk ),
	.dataa ( hit_cnt ),
	.datab ( 22'b1111111111111111111100 ),
	.ageb  ( ageb_2 )
	);
	

	 
//ram write enable flag
always @(posedge clk)
begin
     if (rst)                                         wren <= 1'b0;
	  else 
	    begin
         if      (!op_in_progress)                    wren <= 1'b0;
         else if (rd_hist   & op_in_progress)         wren <= 1'b1;
         else if (init_ram  & op_in_progress)         wren <= 1'b1;
         else if (take_hist & op_in_progress & ph[2]) wren <= 1'b1; //write enable will be active at ph[3]!
         else                                         wren <= 1'b0;
       end
end


//data to be written into the histogram
always @(posedge clk)
begin
    if      (init_ram  & op_in_progress)     ram_data_in  <=  ({22{1'b0}});
    else if (rd_hist   & op_in_progress)     ram_data_in  <=  ({22{1'b0}});
    else if (take_hist & op_in_progress)     ram_data_in  <=  hist_data_out + 22'b0000000000000000000001;
end


//
//histograming memory
//
//dual port memory with read cycle 4 times faster than write cycle
//this is a specifics for Cyclone IV on chip memories
//
histogram_ram2c h1
  (
    .rdclock    (clk),	
    .wrclock    (clk),

    .rdaddress  (ram_addr),    
    .q          (hist_data_out),
	
    .wraddress  (ram_addr),  
    .data       (ram_data_in),
    .wren       (wren)
  );
 
//Histogram non-zero bin memory
//It stores only bins with non-zero bins
//for readout by PC (FTDI)

//align the bin data:
//address (bin number) is off by 2 clock
//compared to bin count
reg  [14:0] rd_a_del0, rd_a_del1, rd_a_del2;
reg  [36:0] hist_bin_data;
reg   [6:0] bin_wr_address;
reg         bin_wren;
reg  [21:0] rd_d;
reg   [3:0] op_inp_del;


//align the bin data:
//address (bin number) is off by 2 clock
//compared to bin count
//
//register data from DP memory
always @(posedge clk)
begin
  op_inp_del <= {op_inp_del[2:0],op_in_progress};

  rd_a_del0 <= ram_addr[14:0];
  rd_a_del1 <= rd_a_del0;
  rd_a_del2 <= rd_a_del1;
  
  rd_d      <= hist_data_out;

//register non-zero bin count together with bin mumber information  
// 
// data format:
// hist_bin_data[36:22]  bin address/number
// hist_bin_data[21: 0]  bin count
//
  if (!(rd_hist & op_inp_del[3])) hist_bin_data <= {37{1'b0}};
  else if (rd_d!={22{1'b0}})      hist_bin_data <= {rd_a_del2, rd_d};
  else                            hist_bin_data <= {37{1'b0}}; 
end


//bin memory write enable
always @(posedge clk)
begin
  if (rst)                                               bin_wren <= 1'b0;
  else if (rd_hist & op_inp_del[3] & (rd_d!={22{1'b0}})) bin_wren <= 1'b1;
  else if (take_hist & op_inp_del[3])                    bin_wren <= 1'b1;
  else                                                   bin_wren <= 1'b0;
end


//bin memory write address
always @(posedge clk)
begin
  if (rst)                            bin_wr_address <= 7'b0000000;
  else if (start | !op_inp_del[3])    bin_wr_address <= 7'b0000000;
  else if (take_hist & op_inp_del[3]) bin_wr_address <= bin_wr_address + 7'b0000001;
  else if (rd_hist & bin_wren)        bin_wr_address <= bin_wr_address + 7'b0000001;
end


hist_bins_ram h2
  (
	.data     (hist_bin_data),
	.wraddress(bin_wr_address),
	.wrclock  (clk),
	.wren     (bin_wren),
	
	.rdaddress(h_rd_address), //this is an interface to the FTDI readout
	.rdclock  (h_rd_clk),
	.q        (h_data_out)
  );
 
endmodule
