///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------
//-- Title      : Device Srial Number
//-------------------------------------------------------------------------------
//-- File       : Serial_Num.v
//-- Author     : Corporate Applications Engineering
//-- Company    : Microsemi Corporation
//-- Device     : SmartFusion2
//-- Standard   : Verilog
//-------------------------------------------------------------------------------
//-- Description: This code implementes the logic to read the Device serial number using   
//--              	CORESYSSERVICES IP and writes the same to LSRAM.
//-------------------------------------------------------------------------------
//-- Copyright (c) 2013   Microsemi Corporation
//--                      All rights reserved.
//-------------------------------------------------------------------------------
//-- Revisions  : V1.0
//-------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////////////////////////// 

module Serial_Num( 

input 						RESET_N,
input 						CLK,
input 						GET_SER_NUM,
output 		reg 			SER_NUM_DONE,

input 						SERV_BUSY,
input 						SERV_DATA_RVALID,
input 				[31:0] 	SERV_READ_DATA,
input 				[7:0] 	SERV_STATUS_RESP,
input 						SERV_STATUS_VALID,
output 		reg 		  	SERV_ENABLE_REQ,
output 		reg		[7:0] 	SERV_CMDBYTE_REQ,

// AHB Side Interfacing with FIC
output     	reg   	[31:0] 	HADDR,
output    	reg   	[1:0]  	HTRANS,
output     	reg          	HWRITE,
output     	wire  	[2:0] 	HSIZE,
output     	wire  	[2:0]  	HBURST,
output     	wire  	[3:0] 	HPROT,
output     	reg   	[31:0] 	HWDATA,
input      	wire  	[31:0] 	HRDATA,
input      	wire         	HREADY,
input      	wire  	[1:0]  	HRESP
	);

wire	 	[7:0] 	serv_command_reg;
reg		 	[31:0]  serial_number[3:0];
reg 	 	[1:0] 	count;
wire 				get_ser_num_redge;
reg 				get_ser_num_int;

reg 	 	[31:0] 	HADDR_int;
reg 	 	[2:0] 	ahb_state;
parameter 	[2:0] 	idle = 3'b000, ser_num = 3'b001, rd_ser_num = 3'b010, wr_ser_num_0 = 3'b011, wr_ser_num_1 = 3'b100, valid_gen = 3'b101;

assign 	HBURST = 3'b000;
assign 	HPROT  = 4'b0011;
assign 	HSIZE  = 3'b010; // 32 Bit Mode

assign serv_command_reg = 1; // service command to get device serial number
assign get_ser_num_redge = GET_SER_NUM & (~get_ser_num_int);

always @ ( posedge CLK, negedge RESET_N )
begin
	if(RESET_N ==  1'b0)
	begin
		SERV_ENABLE_REQ 		<= 	0;
		SERV_CMDBYTE_REQ 		<= 	0;
		count					<=  0;
		SER_NUM_DONE 			<= 	1'b0;
		HADDR               	<=  32'h00000000;
	    HTRANS              	<=  2'b00;  
	    HWRITE              	<=  1'b0;
	    HWDATA              	<=  32'h00000000;
		HADDR_int				<=  32'h20008040; //LSRAM address - allocated for device serial number
	    ahb_state   			<=  idle;
	end
	else
	begin
		case(ahb_state)

		idle:
		begin
			if(get_ser_num_redge == 1'b1)
			begin
				SER_NUM_DONE 	<= 1'b0;
				HADDR_int		<=  32'h20008040; //LSRAM address - allocated for device serial number
				ahb_state 		<= ser_num;
			end
			else
				ahb_state 		<= idle;
		end
		
		ser_num:
		begin
			if (SERV_BUSY == 1'b0)
			begin
			SERV_ENABLE_REQ 	<= 1'b1;
			SERV_CMDBYTE_REQ 	<=serv_command_reg;
			ahb_state 			<= rd_ser_num;
			end		
		end

		rd_ser_num:
		begin
			SERV_ENABLE_REQ 			<= 1'b0;
			if (SERV_DATA_RVALID == 1'b1)
			begin
				serial_number[count] 	<= SERV_READ_DATA;	
				count 					<= count + 1;				
				if (count == 2'b11)
				begin				
					ahb_state 			<= wr_ser_num_0;
				end
				else
				begin				
					ahb_state 			<= rd_ser_num;
				end
			end
		end	

		wr_ser_num_0:
		begin
			if (SERV_STATUS_VALID == 1'b1)
			begin
				if (SERV_STATUS_RESP == 0)
				begin
					HTRANS  			<=  2'b10;
    				HWRITE  			<=  1'b1;
					HADDR   			<=  HADDR_int;
					HADDR_int 			<= HADDR_int + 4;
					ahb_state 			<= wr_ser_num_1;
				end
				else
				begin
					ahb_state 			<= ser_num;	
				end
			end
			else
			begin
				ahb_state 				<= wr_ser_num_0;
			end
		end

		wr_ser_num_1:
		begin
			if ( HREADY  == 1'b1)
			begin
				HWDATA 					<= serial_number[count];
				HADDR 					<=  HADDR_int;
				HADDR_int 				<= HADDR_int + 4;
				count 					<= count + 1;
				if (count == 2'b11)
				begin
					HTRANS  			<=  2'b00;
    				HWRITE  			<=  1'b0;
					ahb_state 			<= valid_gen;
				end
				else
					ahb_state 			<= wr_ser_num_1;
			end
			else
				ahb_state 				<= wr_ser_num_1;	
		end

        valid_gen:
		begin
			if ( HREADY  == 1'b1)
			begin
				SER_NUM_DONE 			<= 1'b1;
				ahb_state 				<= idle;
			end
		end
		endcase	
	end
end	  

always @ ( posedge CLK, negedge RESET_N )
begin
	if(RESET_N ==  1'b0)	
		get_ser_num_int 				<= 1'b0;	
	else	
		get_ser_num_int 				<= GET_SER_NUM;	
end

endmodule

