/******************************************************************************
* Copyright                                                                   *
* Scintillating Fibre Beam Profile Monitor Software by Michal Dziewiecki,     *
* Blake Leverington and Liqing Qin is licensed under CC BY 4.0                *
* https://creativecommons.org/licenses/by/4.0/                                *
* funded by the Deutsche Forschungsgemeinschaft                               *
* (DFG, German Research Foundation) Projektnummer 419255448                   *
* Project Leader: B.Leverington                                               *
*******************************************************************************
* Create Date - Oct 15th. 2024                                                *
* Author: L.Qin                                                               *
* Module - cluster_locate.sv                                                  *
******************************************************************************/
/*
Created by Lq.Qin on Oct 15th. 2024
CLUSTER LOCATE:
if there is continuous [equal or more than SIZE]signals above THRESHOLD, there is cluster;
The STATE_FIRST_CLUSTER find the left position of the Cluster; sig_ch_left
if there is more than one cluster, the STATE_LAST_CLUSTER determine the right position of the Cluster; sig_ch_right
When the address is 319, it goes to output state:
the has_cluster, no_cluster, sig_ch_left and sig_ch_right keep for two clocks
*/

//the interface tested  by algo_top_cl_tb.v
//the detailed math precise tested by cluster_locate_tb.v

module cluster_locate // #(parameter THRESHOLD=54, SIZE=4)
(

	input wire clk,
	input wire rst, // connect to the data_in_startofpacket; to reset for everyframe
	
	//avalon ST(Streaming) sink: 0 readlatency and 0 readallowence  320 channel
	input logic signed [15:0] data_in_data,           //  st.data
	output wire        data_in_ready,          //         .ready
	input  wire        data_in_valid,          //         .valid
	input  wire 		 data_in_empty,          //         .empty
	input  wire        data_in_endofpacket,    //         .endofpacket
	input  wire        data_in_startofpacket,  //         .startofpacket

	input wire[15:0] THRESHOLD, //range 0~255
	input wire[8:0] SIZE,	//range 0~255
	
	output wire[8:0] sig_ch_left,
	output wire[8:0] sig_ch_right,
	output wire has_cluster,
	output wire no_cluster,
	
	output wire data_in_last //.... after this, there is has_cluster of no_cluster signal
);
	
	assign data_in_last = data_in_endofpacket;
	
	localparam CHANNEL_NUM = 320;
	reg signed[15:0] REG_THRESHOLD;
	reg unsigned[8:0] REG_SIZE;
	
	reg[2:0] states;
	localparam STATE_IDLE = 3'b000;
	localparam STATE_REC = 3'b001;
	localparam STATE_FIRST_CLUSTER = 3'b011;
	localparam STATE_LAST_CLUSTER = 3'b010;
	localparam STATE_HAS_CLUSTER = 3'b110;
	localparam STATE_NO_CLUSTER = 3'b111;
	localparam STATE_HAS_CLUSTER_KEEP = 3'b101;
	localparam STATE_NO_CLUSTER_KEEP = 3'b100;
	
	reg unsigned[8:0] size_ctr; //the same as the channel
	reg[8:0] ch_left;
	reg[8:0] ch_right;
	reg[8:0] address; 
	
	
	assign sig_ch_left = (states == STATE_HAS_CLUSTER || states == STATE_HAS_CLUSTER_KEEP)? ch_left: 9'd0;
	assign sig_ch_right = (states == STATE_HAS_CLUSTER || states == STATE_HAS_CLUSTER_KEEP)? ch_right: 9'd0;
	assign has_cluster = (states==STATE_HAS_CLUSTER || states == STATE_HAS_CLUSTER_KEEP)? 1'b1: 1'b0;
	assign no_cluster = (states==STATE_NO_CLUSTER || states == STATE_NO_CLUSTER_KEEP)? 1'b1 : 1'b0;
	
	assign data_in_ready = (states == STATE_REC || states == STATE_FIRST_CLUSTER || states == STATE_LAST_CLUSTER)? 1'b1: 1'b0;
	
	wire data_over_th;  /* synthesis keep */
	assign data_over_th = (data_in_data > REG_THRESHOLD)? 1'b1: 1'b0;
	
	
	always @ (posedge clk or posedge rst)
	begin
		if (rst)
		begin
			ch_left <= 0;
			ch_right <= 0;
			address <= 0; 
			size_ctr <= 0;
			states <= STATE_IDLE;
			REG_THRESHOLD <= THRESHOLD;
			REG_SIZE <= SIZE; 
		end
		else
			case(states)
				STATE_IDLE:
				begin
					ch_left <= 0;
					ch_right <= 0;
					address <= 0; 
					size_ctr <= 0;
					REG_THRESHOLD <= THRESHOLD;
					REG_SIZE <= SIZE;
					if (data_in_startofpacket)
						states <= STATE_REC;
				end
				STATE_REC:
				begin
					if (data_in_valid)
					begin
						address <= address + 1'b1; 
						if (data_in_endofpacket) 
							states <= STATE_NO_CLUSTER;
						else if (data_over_th)
						begin
							size_ctr <= size_ctr + 1'b1;
							states <= STATE_FIRST_CLUSTER;
							ch_left <= address;
						end
					end	
				end
				STATE_FIRST_CLUSTER:
				begin
					if (data_in_valid) 
					begin
						address <= address + 1'b1; 
						if (data_in_endofpacket)
						begin
							if ((size_ctr + data_over_th) > REG_SIZE)
							begin
								states <= STATE_HAS_CLUSTER;
								ch_right <= address;
							end else
								states <= STATE_NO_CLUSTER;
						end
						else if (data_over_th)
							size_ctr <= size_ctr + 1'b1;
						else   
						begin
							size_ctr <= 0;
							if (size_ctr > REG_SIZE)
							begin
								states <= STATE_LAST_CLUSTER;
								ch_right <= address -1'b1;
							end else
							begin
								states <= STATE_REC;
								ch_left <= 0; 
							end
						end
					end
				end
				STATE_LAST_CLUSTER:
				begin	
					if (data_in_valid)
					begin
						address <= address + 1'b1; 
						if (data_in_endofpacket)
						begin
							states <= STATE_HAS_CLUSTER;
							if ((size_ctr + data_over_th) > REG_SIZE)
								ch_right <= address - ~data_over_th; //2024.09.30 ch_right <= address - ~data_over_th;
						end	
						else if (data_over_th)
							size_ctr<= size_ctr + 1'b1;
						else 
						begin
							if (size_ctr > REG_SIZE)
								ch_right <= address-1'b1;
							size_ctr <= 0;
						end
					end
				end
				STATE_HAS_CLUSTER:
				begin
					states <= STATE_HAS_CLUSTER_KEEP;
				end
				STATE_NO_CLUSTER:
				begin
					states <= STATE_NO_CLUSTER_KEEP;
				end
				STATE_HAS_CLUSTER_KEEP:
				begin
					states <= STATE_IDLE;
				end
				STATE_NO_CLUSTER_KEEP:
				begin
					states <= STATE_IDLE;
				end
				default:
					states <= STATE_IDLE;
			endcase		
	end

endmodule


