///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------
//-- Title      : SPI remapping logic 
//-------------------------------------------------------------------------------
//-- File       : Decoder.v
//-- Author     : Corporate Applications Engineering
//-- Company    : Microsemi Corporation
//-- Device     : SmartFusion2
//-- Standard   : Verilog
//-------------------------------------------------------------------------------
//-- Description: This code implementes the AHB slave logic which is connected to SMC_FIC   
//--			  path. The AHB slave path accepts the AHB read requests, initiates request 
//--			  to AHB master logic to read from SPI flash through SPI_0 and returns the  
//--              data  from SPI flash. The AHB master initializes the SPI flash on SF2 Adv 
//--			  Dev Kit in 4-byte address and XIP mode and releases the M3 reset. 
//-------------------------------------------------------------------------------
//-- Copyright (c) 2013   Microsemi Corporation
//--                      All rights reserved.
//-------------------------------------------------------------------------------
//-- Revisions  : V1.0	
//-------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////////////////////////// 

module Decoder( 
// Generic Signals
input   wire			HCLK,
input   wire    		HRESETn,

// 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  reg 	[31:0] 	HWDATA,

input   wire  	[31:0] 	HRDATA,
input   wire         	HREADY,
input	wire  	[1:0]  	HRESP,

input			[1:0]   HTRANS_S,
input			[31:0]  HADDR_S,
input			[31:0]  HWDATA_S,
output  reg        		HREADYOUT_S,
output			[1:0]   HRESP_S,
output	reg		[31:0]  HRDATA_S,
input			[2:0]   HSIZE_S,
input           		HREADY_S, 
input					HWRITE_S, 
input					HSEL_S,

output 					M3_RESET

	);




reg [2:0]  	ahb_slave_st;
reg [3:0]  	ahb_mast_st;

reg 		spi_init_done0;
reg 		spi_init_done1;
reg 		data_req;
reg 		data_ready;
reg [31:0] 	data;
reg [23:0] 	CMD;
reg [23:0] 	read_byte[3:0];
reg [27:0] 	haddr_int;
wire [27:0] block_address;

reg [3:0] 	nbytes;
reg [3:0] 	CMD_count;
reg [4:0] 	reg_count;
reg [2:0] 	init_idx;
reg [2:0] 	init_idx_cnt;

wire [31:0] SPI_Reg[30:0];
wire [31:0] SPI_Reg_add[30:0];

assign M3_RESET = spi_init_done1;
//***************************************************SPI register configuration values for initializing and activating XIP mode*********************

//********************************SPI INIT
assign	SPI_Reg[0] = 32'h27000103; 		//control reg - dummy
assign	SPI_Reg[1] = 32'h27000103; 		//control reg
assign	SPI_Reg[2] = 32'h8;				//frame size
assign	SPI_Reg[3] = 32'h1;				//clk_gen reg
assign	SPI_Reg[4] = 32'h1;				//slave select reg
assign	SPI_Reg[5] = 32'h4;				//flush rx fifo
assign	SPI_Reg[6] = 32'h6;				//write enable cmd
assign	SPI_Reg[7] = 32'hB7;			//4byte enable cmd
assign	SPI_Reg[8] = 32'h6;				//write enable cmd
//********************************XIP EN
assign	SPI_Reg[9] = 32'h27000102; 		//control reg - dummy
assign	SPI_Reg[10] = 32'h27000102; 	//control reg
assign	SPI_Reg[11] = 32'h27000203; 	//control reg
assign	SPI_Reg[12] = 32'h81;				//write enable cmd
assign	SPI_Reg[13] = 32'hF7;			//4byte enable cmd
//********************************dummy read
assign	SPI_Reg[14] = 32'h27000202; 		//control reg - dummy
assign	SPI_Reg[15] = 32'h27000202; 	//control reg
assign	SPI_Reg[16] = 32'h27000603; 	//control reg
assign	SPI_Reg[17] = 32'hB;			//txd cmd for xip
assign	SPI_Reg[18] = 32'h0;
assign	SPI_Reg[19] = 32'h0;
assign	SPI_Reg[20] = 32'h0;
assign	SPI_Reg[21] = 32'h0;
assign	SPI_Reg[22] = 32'h0;
//********************************slave deselect and select
assign	SPI_Reg[23] = 32'h0;				//slave select reg - dummy
assign	SPI_Reg[24] = 32'h0;				//slave select reg
assign	SPI_Reg[25] = 32'h1;				//slave select reg
assign	SPI_Reg[26] = 32'h18;				//frame size
//********************************actual read
assign	SPI_Reg[27] = 32'h27000602; 	//control reg - dummy
assign	SPI_Reg[28] = 32'h27000602; 	//control reg
assign	SPI_Reg[29] = 32'h27000303; 	//control reg
assign	SPI_Reg[30] = 32'h4; 			//flush rx fifo

//***************************************************SPI register address sequence for initalizing and activating XIP*********************************

//********************************SPI INIT
assign	SPI_Reg_add[0] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[1] = 32'h40001004;	//txrxdf reg address 
assign	SPI_Reg_add[2] = 32'h40001018;	//clk_gen reg address
assign	SPI_Reg_add[3] = 32'h4000101C;	//slave select reg address
assign	SPI_Reg_add[4] = 32'h4000102C;	//command reg address for rxfifo reset
assign	SPI_Reg_add[5] = 32'h40001014;	//txd reg address - for WE
assign	SPI_Reg_add[6] = 32'h40001014;	//txd reg address - for 4byte EN
assign	SPI_Reg_add[7] = 32'h40001014;	//txd reg address - for WE
//********************************XIP EN
assign	SPI_Reg_add[8] = 32'h40001000;	//control reg address - dummy
assign	SPI_Reg_add[9] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[10] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[11] = 32'h40001014;	//txd reg address - spi ctrl reg
assign	SPI_Reg_add[12] = 32'h40001014;	//txd reg address - for XIP EN
//********************************dummy read
assign	SPI_Reg_add[13] = 32'h40001000;	//control reg address - dummy
assign	SPI_Reg_add[14] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[15] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[16] = 32'h40001014;	//txd reg address
assign	SPI_Reg_add[17] = 32'h40001014;	//txd reg address
assign	SPI_Reg_add[18] = 32'h40001014;	//txd reg address
assign	SPI_Reg_add[19] = 32'h40001014;	//txd reg address
assign	SPI_Reg_add[20] = 32'h40001014;	//txd reg address
assign	SPI_Reg_add[21] = 32'h40001014;	//txd reg address
//********************************slave deselect and select
assign	SPI_Reg_add[22] = 32'h4000101C;	//slave select reg address - dummy
assign	SPI_Reg_add[23] = 32'h4000101C;	//slave select reg address
assign	SPI_Reg_add[24] = 32'h4000101C;	//slave select reg address
assign	SPI_Reg_add[25] = 32'h40001004;	//txrxdf reg address
//********************************actual read
assign	SPI_Reg_add[26] = 32'h40001000;	//control reg address - dummy
assign	SPI_Reg_add[27] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[28] = 32'h40001000;	//control reg address
assign	SPI_Reg_add[29] = 32'h4000102C;	//command reg address for rxfifo reset
assign	SPI_Reg_add[30] = 32'h4000102C;	//command reg address for rxfifo reset -dummy

assign HRESP_S	=	2'b00;
assign block_address = haddr_int;
assign HSIZE	=	3'b010;
assign HBURST	=	3'b000;

//AHB Master: accessing SPI_0
always@(posedge HCLK, negedge HRESETn)
begin	
  	if( HRESETn == 1'b0 )
  	begin
		HADDR								<=	0;
		HWDATA								<=	0;
		HWRITE								<=	0;
		HTRANS								<=	2'b00;
		spi_init_done0						<=	1'b0;
		spi_init_done1						<=	1'b0;
		data_ready							<=	1'b0;
		data								<=	0;
		init_idx 							<= 	0;
		init_idx_cnt						<=	0;
		reg_count							<=	0;
		CMD_count							<=	0;
		nbytes								<=	0;
		ahb_mast_st							<=	4'b0;
	end
	else
	begin
		case(ahb_mast_st)

		//SPI_0 init
		4'b0000: 
		begin	
			if(HREADY)
			begin		
				HADDR						<=	SPI_Reg_add[reg_count];
				HWDATA						<=	SPI_Reg[reg_count];
				HWRITE						<=	1'b1;
				reg_count					<=	reg_count + 1;
				if(reg_count == 26)										//SPI Flash init and XIP activation completed									
				begin
					HTRANS					<=	2'b00;	
					spi_init_done1			<=	1'b1;
					init_idx				<=	0;
					init_idx_cnt			<=	0;
					ahb_mast_st				<=	4'b1010;
				end
				else if(reg_count == 22)								//XIP activation step2 completed
				begin
					HTRANS					<=	2'b00;	
					init_idx				<=	0;
					init_idx_cnt			<=	6;
					ahb_mast_st				<=	4'b1011;
				end
				else if(reg_count == 13)								//XIP activation step1 completed
				begin
					HTRANS					<=	2'b00;	
					init_idx				<=	0;
					init_idx_cnt			<=	2;
					ahb_mast_st				<=	4'b1011;
				end
				else if(reg_count == 8)									//4-byte adress is enabled
				begin
					HTRANS					<=	2'b00;
					spi_init_done0			<=	1'b1;
					init_idx				<=	0;
					init_idx_cnt			<=	3;
					ahb_mast_st				<=	4'b1011;
				end
				else
					HTRANS					<=	2'b10;
			end
		end

		//clear rx fifo - SPI init stage
		4'b1011: 
		begin	
			if(HREADY)
			begin	
				if(init_idx == init_idx_cnt)
				begin
					HTRANS					<=	2'b00;
					ahb_mast_st				<=	4'b0000;
				end
				else
					ahb_mast_st				<=	4'b0100;
			end
		end

		//data reading based on data req
		4'b1010: 
		begin
			reg_count						<=	27;
			data_ready						<=	1'b0;						
			HTRANS							<=	2'b00;
			if(data_req)
			begin					
				ahb_mast_st					<=	4'b0001;
			end
		end

		//control register configuration and fifo reset
		4'b0001:
		begin			
			CMD_count						<=	0;
			if(HREADY)
			begin
				HADDR						<=	SPI_Reg_add[reg_count];
				HWDATA						<=	SPI_Reg[reg_count];
				HWRITE						<=	1'b1;
				HTRANS						<=	2'b10;
				reg_count					<=	reg_count + 1'b1;
				ahb_mast_st					<=	4'b1100;
			end
			else				
				HTRANS						<=	2'b00;
		end

		//control register configuration and fifo reset
		4'b1100:
		begin			
			if(HREADY)
			begin
				if(reg_count < 30)
				begin
					HADDR					<=	SPI_Reg_add[reg_count];
					HWDATA					<=	SPI_Reg[reg_count];
					HWRITE					<=	1'b1;
					HTRANS					<=	2'b10;
					reg_count				<=	reg_count + 1'b1;
					ahb_mast_st				<=	4'b1100;
				end
				else
				begin
					HWDATA					<=	SPI_Reg[reg_count];
					HADDR					<=	32'h40001008;//status  -- TX status
					HWRITE					<=	1'b0;
					HTRANS					<=	2'b10;
					ahb_mast_st				<=	4'b0010;	
				end
			end
		end

		//wait
		4'b0010:
		begin
			if(HREADY)
			begin
				HTRANS						<=	2'b00;
				ahb_mast_st					<=	4'b0011;
			end
		end

		//Sending Read address
		4'b0011:
		begin
			if(HREADY)
			begin
				if (CMD_count < 4'h3)
				begin
					if(HRDATA[8] == 1'b0)	//checking txfifo
					begin
						HADDR				<=	32'h40001014;//txd
						HWDATA				<=	CMD;
						HWRITE				<=	1'b1;
						HTRANS				<=	2'b10;
						CMD_count			<=	CMD_count + 1'b1;
						ahb_mast_st			<=	4'b0100;
					end
					else
					begin
						HTRANS				<=	2'b00;
						ahb_mast_st			<=	4'b0100;
					end				
				end
				else
				begin
					HTRANS					<=	2'b00;	
					ahb_mast_st				<=	4'b0100;
				end
			end
		end

		//RX status
		4'b0100:
		begin
			if(HREADY)
			begin
				HADDR						<=	32'h40001008;//status
				HWRITE						<=	1'b0;
				HTRANS						<=	2'b10;
				ahb_mast_st					<=	4'b0101;
			end
			else
				HTRANS						<=	2'b00;
		end

		//wait
		4'b0101:
		begin
			if(HREADY)
			begin
				HTRANS						<=	2'b00;
				ahb_mast_st					<=	4'b0110;
			end
		end
		
		//checking rxfifo
		4'b0110:
		begin
			if(HREADY)
			begin
				if(HRDATA[6] == 1'b0)//1'b1)//--sim	//checking rxfifo empty flag
				begin
					HADDR					<=	32'h40001010;//rxd
					HWRITE					<=	1'b0;
					HTRANS					<=	2'b10;
					if(~spi_init_done1)
					begin
						init_idx 			<= init_idx + 1;
						ahb_mast_st			<=	4'b1011;
					end
					else
					begin
						ahb_mast_st			<=	4'b0111;
					end
				end
				else
				begin	//rx fifo is empty
					if(spi_init_done1)
					begin						
						HADDR				<=	32'h40001008;//status   -- TX status
						HWRITE				<=	1'b0;
						HTRANS				<=	2'b10;
						ahb_mast_st			<=	4'b0010;
					end
					else if(spi_init_done0)
					begin
						HTRANS				<=	2'b00;
						ahb_mast_st			<=	4'b1011;						
					end
				end
			end
		end

		//wait
		4'b0111:
		begin
			if(HREADY)
			begin
				HTRANS						<=	2'b00;
				ahb_mast_st					<=	4'b1000;
			end
		end

		//reading rx data
		4'b1000:
		begin
			if(HREADY)
			begin
				read_byte[nbytes]			<=	HRDATA[23:0];
				if (nbytes == 4'h2)									//4bytes address + 1 dummy cycle + 4bytes read
				begin
					HTRANS					<=	2'b00;
					nbytes					<=	0;
					ahb_mast_st				<=	4'b1001;
				end
				else
				begin
					nbytes					<=	nbytes + 1'b1;							
					HWRITE					<=	1'b0;					
					if(spi_init_done1)
					begin
						HADDR				<=	32'h40001008;		//status   -- TX status
						HTRANS				<=	2'b10;
						ahb_mast_st			<=	4'b0010;
					end
					else
						ahb_mast_st			<=	4'b0000;
				end
			end
		end

		4'b1001:
		begin	
			HTRANS							<=	2'b00;
			data							<=	{read_byte[2][7:0],read_byte[2][15:8],read_byte[2][23:16],read_byte[1][7:0]};
			data_ready						<=	1'b1;
			ahb_mast_st						<=	4'b1010;
		end

		endcase
	end
end

//Generates commands to SPI Flash

always@(posedge HCLK, negedge HRESETn)
begin
	if(HRESETn  == 1'b0)
	begin
		CMD					<=	24'h00;
	end
	else
	begin
		case(CMD_count)

		4'b0000:
			CMD				<=	{4'b0,block_address[27:8]};		//address

		4'b0001:
			CMD				<=	{block_address[7:0],16'h0};		//address

		default:
			CMD				<=	0;

		endcase		
	end
end


//AHB slave fsm: connected to SMC_FIC 
always@(posedge HCLK, negedge HRESETn)
begin	
  	if( HRESETn == 1'b0 )
  	begin
		HREADYOUT_S				<=	1'b0;
		HRDATA_S				<=	1'b0;	
		ahb_slave_st			<=	3'b0;
		data_req				<=	1'b0;
		haddr_int				<=	0;
	end
	else
	begin
		case(ahb_slave_st)

		3'b000:
		begin
			if(HSEL_S && HTRANS_S[1] && HREADY_S && (~HWRITE_S))
			begin
				haddr_int		<=	HADDR_S[27:0];	
				data_req		<=	1'b1;
				HREADYOUT_S		<=	1'b0;
				ahb_slave_st	<=	3'b001;
			end
			else
				HREADYOUT_S		<=	1'b1;
		end

		3'b001:
		begin	//wating for data from SPI
			if(spi_init_done1)
				data_req			<=	1'b0;
			if(data_ready)
			begin
				HRDATA_S		<=	data;
				HREADYOUT_S		<=	1'b1;
				ahb_slave_st	<=	3'b000;
			end
		end
		endcase
	end
end
		
endmodule

