//------------------------------------------------------------------------------
//
//  dp_sink_aux_rx.v : displaport sink aux-ch rx module
//
//  LICENSE : "as-is"
//  TakeshiNagashima(T.NG) caramelgete@gmail.com
//------------------------------------------------------------------------------
//  2009/nov/30 release 0.0  
//  2010/jan/28 release 0.1  display timinig generate test
//
//------------------------------------------------------------------------------


module dp_sink_aux_rx(
	input			aux_rx,			// in    [AUX] dp aux_rx
	input			aux_oe,			// in    [AUX] dp aux send/#recieve
	output	[3:0]	aux_cmd,		// out   [AUX] recieve ack
	output	[19:0]	aux_addr,		// out   [AUX] recieve addr
	output	[7:0]	aux_data,		// out   [AUX] recieve data
	output			aux_cmd_ack,	// out   [AUX] recieve cmd acknowredge
	output			aux_addr_ack,	// out   [AUX] recieve addr acknowredge
	output			aux_data_ack,	// out   [AUX] recieve data acknowredge
	output			aux_sync,		// out   [AUX] recieve sync
	output			aux_stop,		// out   [AUX] recieve stop
	output			aux_done,		// out   [AUX] recieve done
	input			clk27,			// in    [AUX] clk 27MHz
	input			rst_n			// in    [AUX] #reset
);


	localparam auxst00=3'b000;	// idle
	localparam auxst01=3'b001;	// sync 00000000
	localparam auxst02=3'b011;	// sync HHLL
	localparam auxst03=3'b010;	// cmd
	localparam auxst04=3'b100;	// data
	localparam auxst05=3'b101;	// 
	localparam auxst06=3'b111;	// 
	localparam auxst07=3'b110;	// 

	// ---- sync ----

	wire	aux_rx_in;
	wire	aux_rx_zero;
	wire	aux_rx_one;

	reg		[3:0] aux_rx_in_r;
	reg		aux_rx_edge_r;
	reg		aux_rx_zero_r;
	reg		aux_rx_one_r;

	// ---- recieve ----

	wire	aux_clk_sync;
	wire	aux_clk_over;

	wire	aux_clk_window;

	reg		[5:0] aux_clk_r;
	reg		aux_clk8_r;
	wire	[5:0] aux_clk_w;
	wire	aux_clk8_w;

	reg		[2:0] aux_state_r;
	wire	[2:0] aux_state_w;

	reg		[3:0] aux_sync_count_r;
	reg		aux_sync_count10_r;
	reg		[3:0] aux_sync_r;
	reg		aux_sync4_r;
	reg		aux_sync_err_r;
	reg		[4:0] aux_count_r;
	reg		aux_cmd4_r;
	reg		aux_addr20_r;
	reg		aux_data8_r;
	reg		[3:0] aux_cmd_r;
	reg		[19:0] aux_addr_r;
	reg		[7:0] aux_data_r;
	reg		[3:0] aux_stop_r;
	reg		aux_stop4_r;
	reg		aux_cmd_ack_r;
	reg		aux_addr_ack_r;
	reg		aux_data_ack_r;
	reg		aux_done_r;
	wire	[3:0] aux_sync_count_w;
	wire	aux_sync_count10_w;
	wire	[3:0] aux_sync_w;
	wire	aux_sync4_w;
	wire	aux_sync_err_w;
	wire	[4:0] aux_count_w;
	wire	aux_cmd4_w;
	wire	aux_addr20_w;
	wire	aux_data8_w;
	wire	[3:0] aux_cmd_w;
	wire	[19:0] aux_addr_w;
	wire	[7:0] aux_data_w;
	wire	[3:0] aux_stop_w;
	wire	aux_stop4_w;
	wire	aux_cmd_ack_w;
	wire	aux_addr_ack_w;
	wire	aux_data_ack_w;
	wire	aux_done_w;

//

	// ---- recieve signal sync ----

	assign aux_rx_in=aux_rx_in_r[2];
	assign aux_rx_zero=aux_rx_zero_r;
	assign aux_rx_one=aux_rx_one_r;

	always @(posedge clk27 or negedge rst_n)
	begin
		if (rst_n==1'b0)
			begin
				aux_rx_in_r[3:0] <= 4'b0;
				aux_rx_edge_r <= 1'b0;
				aux_rx_zero_r <= 1'b0;
				aux_rx_one_r <= 1'b0;
			end
		else
			begin
				aux_rx_in_r[0] <= (aux_oe==1'b0) ? aux_rx : 1'b0;
				aux_rx_in_r[1] <= aux_rx_in_r[0];
				aux_rx_in_r[2] <= aux_rx_in_r[1];
				aux_rx_in_r[3] <= aux_rx_in_r[2];
				aux_rx_edge_r <= (aux_rx_in_r[2:1]==2'b01) | (aux_rx_in_r[2:1]==2'b10) ? 1'b1 :1'b0;
				aux_rx_zero_r <= (aux_rx_in_r[2:1]==2'b01) ? 1'b1 :1'b0;
				aux_rx_one_r  <= (aux_rx_in_r[2:1]==2'b10) ? 1'b1 :1'b0;
			end
	end

	// ---- aux-ch recieve ----

	assign aux_clk_sync=aux_sync4_r;
	assign aux_clk_over=aux_clk_r[5];

	assign aux_cmd[3:0]=aux_cmd_r[3:0];
	assign aux_addr[19:0]=aux_addr_r[19:0];
	assign aux_data[7:0]=aux_data_r[7:0];
	assign aux_cmd_ack=aux_cmd_ack_r;
	assign aux_addr_ack=aux_addr_ack_r;
	assign aux_data_ack=aux_data_ack_r;
	assign aux_sync=aux_sync4_r;
	assign aux_stop=aux_stop4_r;
	assign aux_done=aux_done_r;

	always @(posedge clk27 or negedge rst_n)
	begin
		if (rst_n==1'b0)
			begin
				aux_clk_r[5:0] <= 6'b0;
				aux_clk8_r <= 1'b0;
				aux_state_r <= auxst00;
				aux_sync_count_r[3:0] <= 4'b0;
				aux_sync_count10_r <= 1'b0;
				aux_sync_r[3:0] <= 4'b0;
				aux_sync4_r <= 1'b0;
				aux_sync_err_r <= 1'b0;
				aux_count_r[4:0] <= 5'b0;
				aux_cmd4_r <= 1'b0;
				aux_addr20_r <= 1'b0;
				aux_data8_r <= 1'b0;
				aux_cmd_r[3:0] <= 4'b0;
				aux_addr_r[19:0] <= 20'b0;
				aux_data_r[7:0] <= 8'b0;
				aux_stop_r[3:0] <= 4'b0;
				aux_stop4_r <= 1'b0;
				aux_cmd_ack_r <= 1'b0;
				aux_addr_ack_r <= 1'b0;
				aux_data_ack_r <= 1'b0;
				aux_done_r <= 1'b0;
			end
		else
			begin
				aux_clk_r[5:0] <= aux_clk_w[5:0];
				aux_clk8_r <= aux_clk8_w;
				aux_state_r <= aux_state_w;
				aux_sync_count_r[3:0] <= aux_sync_count_w[3:0];
				aux_sync_count10_r <= aux_sync_count10_w;
				aux_sync_r[3:0] <= aux_sync_w[3:0];
				aux_sync4_r <= aux_sync4_w;
				aux_sync_err_r <= aux_sync_err_w;
				aux_count_r[4:0] <= aux_count_w[4:0];
				aux_cmd4_r <= aux_cmd4_w;
				aux_addr20_r <= aux_addr20_w;
				aux_data8_r <= aux_data8_w;
				aux_cmd_r[3:0] <= aux_cmd_w[3:0];
				aux_addr_r[19:0] <= aux_addr_w[19:0];
				aux_data_r[7:0] <= aux_data_w[7:0];
				aux_stop_r[3:0] <= aux_stop_w[3:0];
				aux_stop4_r <= aux_stop4_w;
				aux_cmd_ack_r <= aux_cmd_ack_w;
				aux_addr_ack_r <= aux_addr_ack_w;
				aux_data_ack_r <= aux_data_ack_w;
				aux_done_r <= aux_done_w;
			end
	end

	assign aux_clk_window=((aux_clk_r[4:3]==2'b11) | (aux_clk_r[4:2]==3'b101) | (aux_clk_r[4:3]==2'b00)) ? 1'b 1 : 1'b0;

	wire	aux_clk_sync_req;

	assign aux_clk_sync_req=
			(aux_clk_r[4:0]==5'd26) ? 1'b1 :
			(aux_clk_r[4:0]!=5'd26) & ({aux_clk_window,aux_rx_edge_r}==2'b11) ? 1'b1 :
			1'b0;

	assign aux_clk_w[5]=
			(aux_clk_sync==1'b0) & (aux_rx_zero_r==1'b1) ? 1'b0 :
			(aux_clk_sync==1'b0) & (aux_rx_zero_r==1'b0) & (aux_clk_r[4:0]==5'd26) ? 1'b1 :
			(aux_clk_sync==1'b0) & (aux_rx_zero_r==1'b0) & (aux_clk_r[4:0]!=5'd26) ? aux_clk_r[5] :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}==2'b11) ? 1'b0 :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}!=2'b11) & (aux_clk_r[4:0]==5'd26) ? 1'b1 :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}!=2'b11) & (aux_clk_r[4:0]!=5'd26) ? aux_clk_r[5] :
			1'b0;

	assign aux_clk_w[4:0]=
			(aux_clk_sync==1'b0) &  ((aux_clk_r[4:0]==5'd26) | (aux_rx_zero_r==1'b1)) ? 5'b0 :
			(aux_clk_sync==1'b0) & !((aux_clk_r[4:0]==5'd26) | (aux_rx_zero_r==1'b1)) ? aux_clk_r[4:0]+4'b01 :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}==2'b11) ? 4'b0 :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}!=2'b11) & (aux_clk_r[4:0]==5'd26) ? 4'b00 :
			(aux_clk_sync==1'b1) & ({aux_clk_window,aux_rx_edge_r}!=2'b11) & (aux_clk_r[4:0]!=5'd26) ? aux_clk_r[4:0]+4'b01 :
			5'b0;

	assign aux_clk8_w=(aux_clk_r[4:0]==5'd7) ? 1'b1 : 1'b0;

	assign aux_state_w=
			(aux_state_r==auxst00) & (aux_rx_zero==1'b0) ? auxst00 :
			(aux_state_r==auxst00) & (aux_rx_zero==1'b1) ? auxst01 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b1) & (aux_clk_over==1'b1) ? auxst00 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b1) & (aux_clk_over==1'b0) & (aux_sync_count10_r==1'b1) ? auxst02 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b1) & (aux_clk_over==1'b0) & (aux_sync_count10_r==1'b0) ? auxst01 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b0) ? auxst01 :
			(aux_state_r==auxst02) & (aux_clk8_r==1'b1) & (aux_sync_err_r==1'b1) ? auxst00 :
			(aux_state_r==auxst02) & (aux_clk8_r==1'b1) & (aux_sync_err_r==1'b0) & ({aux_sync4_r,aux_rx_in}==2'b10) ? auxst03 :
			(aux_state_r==auxst02) & (aux_clk8_r==1'b1) & (aux_sync_err_r==1'b0) & ({aux_sync4_r,aux_rx_in}!=2'b10) ? auxst02 :
			(aux_state_r==auxst02) & (aux_clk8_r==1'b0) ? auxst02 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b1) & (aux_cmd4_r==1'b0) ? auxst03 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b1) & (aux_cmd4_r==1'b1) ? auxst04 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b0) ? auxst03 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b1) & (aux_addr20_r==1'b0) ? auxst04 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b1) & (aux_addr20_r==1'b1) ? auxst05 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b0) ? auxst04 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_stop4_r==1'b1) ? auxst00 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_stop4_r==1'b0) ? auxst05 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b0) ? auxst05 :
			auxst00;

	assign aux_sync_count_w[3:0]=
			(aux_state_r==auxst00) ? 4'b0 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b0) ? aux_sync_count_r[3:0] :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b1) & (aux_rx_in==1'b1) ? aux_sync_count_r[3:0]+4'b01 :
			(aux_state_r==auxst01) & (aux_clk8_r==1'b1) & (aux_rx_in==1'b0) ? 4'b0 :
			4'b0;

	assign aux_sync_count10_w=(aux_sync_count_r[3:0]==4'h8) ? 1'b1 : 1'b0;

	assign aux_sync_w[3:0]=
			(aux_clk_over==1'b0) ? 4'b0 :
			(aux_clk_over==1'b1) & (aux_clk8_r==1'b1) ? {aux_sync_r[2:0],aux_rx_in} :
			(aux_clk_over==1'b1) & (aux_clk8_r==1'b0) ? aux_sync_r[3:0] :
			4'b0;

	assign aux_sync4_w=
			(aux_state_r==auxst00) ? 1'b0 :
			(aux_state_r==auxst01) ? 1'b0 :
			(aux_state_r==auxst02) & (aux_sync_r[2:0]==3'b110) ? 1'b1 :
			(aux_state_r==auxst02) & (aux_sync_r[2:0]!=3'b110) ? aux_sync4_r :
			(aux_state_r==auxst03) ? 1'b1 :
			(aux_state_r==auxst04) ? 1'b1 :
			(aux_state_r==auxst05) ? 1'b1 :
			(aux_state_r==auxst06) ? 1'b1 :
			(aux_state_r==auxst07) ? 1'b1 :
			1'b0;

	assign aux_sync_err_w=
			(aux_sync_r[2:0]==3'b111) ? 1'b1 :
			(aux_sync_r[2:0]==3'b101) ? 1'b1 :
			1'b0;

	assign aux_count_w[4:0]=
			(aux_state_r==auxst00) ? 5'b0 :
			(aux_state_r==auxst01) ? 5'b0 :
			(aux_state_r==auxst02) ? 5'b0 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b1) & (aux_cmd4_r==1'b0) ? aux_count_r[4:0]+5'b01 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b1) & (aux_cmd4_r==1'b1) ? 5'b0 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b0) ? aux_count_r[4:0] :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b1) & (aux_addr20_r==1'b0) ? aux_count_r[4:0]+5'b01 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b1) & (aux_addr20_r==1'b1) ? 5'b0 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b0) ? aux_count_r[4:0] :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_data8_r==1'b0) ? aux_count_r[4:0]+5'b01 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_data8_r==1'b1) ? 5'b0 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b0) ? aux_count_r[4:0] :
			5'b0;

	assign aux_cmd4_w=
			(aux_state_r==auxst00) ? 1'b0 :
			(aux_state_r==auxst01) ? 1'b0 :
			(aux_state_r==auxst02) ? 1'b0 :
			(aux_state_r==auxst03) & (aux_count_r[1:0]==2'b11) ? 1'b1 :
			(aux_state_r==auxst03) & (aux_count_r[1:0]!=2'b11) ? aux_cmd4_r :
			1'b0;

	assign aux_addr20_w=
			(aux_state_r==auxst00) ? 1'b0 :
			(aux_state_r==auxst01) ? 1'b0 :
			(aux_state_r==auxst02) ? 1'b0 :
			(aux_state_r==auxst03) ? 1'b0 :
			(aux_state_r==auxst04) & (aux_count_r[4:0]==5'd19) ? 1'b1 :
			(aux_state_r==auxst04) & (aux_count_r[4:0]!=5'd19) ? aux_addr20_r :
			1'b0;

	assign aux_data8_w=
			(aux_state_r==auxst00) ? 1'b0 :
			(aux_state_r==auxst01) ? 1'b0 :
			(aux_state_r==auxst02) ? 1'b0 :
			(aux_state_r==auxst03) ? 1'b0 :
			(aux_state_r==auxst04) ? 1'b0 :
			(aux_state_r==auxst05) & (aux_count_r[2:0]==3'b111) ? 1'b1 :
			(aux_state_r==auxst05) & (aux_count_r[2:0]!=3'b111) ? 1'b0 :
			1'b0;

	assign aux_cmd_w[3:0]=
			(aux_state_r==auxst00) ? 4'b0 :
			(aux_state_r==auxst01) ? 4'b0 :
			(aux_state_r==auxst02) ? 4'b0 :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b1) ? {aux_cmd_r[2:0],!aux_rx_in} :
			(aux_state_r==auxst03) & (aux_clk8_r==1'b0) ? aux_cmd_r[3:0] :
			(aux_state_r==auxst04) ? aux_cmd_r[3:0] :
			(aux_state_r==auxst05) ? aux_cmd_r[3:0] :
			(aux_state_r==auxst06) ? aux_cmd_r[3:0] :
			(aux_state_r==auxst07) ? aux_cmd_r[3:0] :
			4'b0;

	assign aux_addr_w[19:0]=
			(aux_state_r==auxst00) ? 20'b0 :
			(aux_state_r==auxst01) ? 20'b0 :
			(aux_state_r==auxst02) ? 20'b0 :
			(aux_state_r==auxst03) ? 20'b0 :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b1) ? {aux_addr_r[18:0],!aux_rx_in} :
			(aux_state_r==auxst04) & (aux_clk8_r==1'b0) ? aux_addr_r[19:0] :
			(aux_state_r==auxst05) ? aux_addr_r[19:0] :
			(aux_state_r==auxst06) ? aux_addr_r[19:0] :
			(aux_state_r==auxst07) ? aux_addr_r[19:0] :
			20'b0;

	assign aux_data_w[7:0]=
			(aux_state_r==auxst00) ? 8'b0 :
			(aux_state_r==auxst01) ? 8'b0 :
			(aux_state_r==auxst02) ? 8'b0 :
			(aux_state_r==auxst03) ? 8'b0 :
			(aux_state_r==auxst04) ? 8'b0 :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b1) ? {aux_data_r[6:0],!aux_rx_in} :
			(aux_state_r==auxst05) & (aux_clk8_r==1'b0) ? aux_data_r[7:0] :
			(aux_state_r==auxst06) ? aux_data_r[7:0] :
			(aux_state_r==auxst07) ? aux_data_r[7:0] :
			8'b0;

	assign aux_stop_w[3:0]=
			(aux_sync4_r==1'b1) & (aux_clk_over==1'b0) ? 4'b0 :
		//	(aux_sync4_r==1'b1) & (aux_clk_over==1'b1) & (aux_clk8_r==1'b1) ? {aux_stop_r[2:0],aux_rx_in} :
			(aux_sync4_r==1'b1) & (aux_clk_over==1'b1) & (aux_clk8_r==1'b1) ? {aux_stop_r[2:0],1'b1} :
			(aux_sync4_r==1'b1) & (aux_clk_over==1'b1) & (aux_clk8_r==1'b0) ? aux_stop_r[3:0] :
			4'b0;

	assign aux_stop4_w=
			(aux_sync4_r==1'b0) ? 1'b0 :
		//	(aux_sync4_r==1'b1) & (aux_stop_r[3:0]==4'b1100) ? 1'b1 :
		//	(aux_sync4_r==1'b1) & (aux_stop_r[3:0]!=4'b1100) ? aux_stop4_r :
			(aux_sync4_r==1'b1) & (aux_stop_r[3]==1'b1) ? 1'b1 :
			(aux_sync4_r==1'b1) & (aux_stop_r[3]==1'b0) ? aux_stop4_r :
			1'b0;

	assign aux_cmd_ack_w=(aux_state_r==auxst03) & (aux_clk8_r==1'b1) & (aux_cmd4_r==1'b1) ? 1'b1 : 1'b0;
	assign aux_addr_ack_w=(aux_state_r==auxst04) & (aux_clk8_r==1'b1) & (aux_addr20_r==1'b1) ? 1'b1 : 1'b0;
	assign aux_data_ack_w=(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_data8_r==1'b1) ? 1'b1 : 1'b0;

	assign aux_done_w=(aux_state_r==auxst05) & (aux_clk8_r==1'b1) & (aux_stop4_r==1'b1) ? 1'b1 : 1'b0;

endmodule
