/*-----------------------------------------------------------------------------
 Title      : Command Decoder
-------------------------------------------------------------------------------
 File       : CMD_Decoder.v
 Author     : Corporate Applications Engineering
 Company    : Microsemi Corporation
 Device     : SmartFusion2
 Standard   : Verilog
-------------------------------------------------------------------------------
 Description: The command decoder receives the command from 
 COM Interface logic and generates write, read, write size and read size signals.
 It also generates AHB signals to read from and write into MDDR Configuration 
 Registers.
-------------------------------------------------------------------------------
 Copyright (c) 2014   Microsemi Corporation
                      All rights reserved.
-------------------------------------------------------------------------------
 Revisions  : V1.0
------------------------------------------------------------------------------- */

module CMD_Decoder(
	input 		      CLK,
	input 		      RESETn,
	input  [7:0]      command,

	output reg        write_start,
	output reg        read_start,
	output wire [9:0] w_xfer_size,
    output wire [9:0] r_xfer_size,

	output reg        AHB_WRITE,
	output reg        AHB_READ,
	output reg [31:0] AHB_ADDR,
	output reg [31:0] AHB_DATA);

wire [1:0] WR_CMD;
wire [3:0] PDM;
reg  [1:0] ahb_state;
reg  [3:0] PDM_tmp;

parameter [31:0]  MDDR_BASE_ADDRESS = 32'h40020800;

assign WR_CMD = {command[1],command[0]};
assign PDM    = {command[5],command[4],command[3],command[2]};

assign w_xfer_size   = 10'h10;
assign r_xfer_size   = 10'h10;

always@(posedge CLK, negedge RESETn)
begin	
  if( RESETn == 1'b0 )
    begin	
		write_start  <= 0;
		read_start   <= 0;
	end
  else
	begin
	  case (WR_CMD)
		2'b00:
		  begin
			write_start  <= 0;
			read_start   <= 0;
		  end
		2'b01:
		  begin
			write_start  <= 1;
			read_start   <= 0;
		  end
		2'b10:
		  begin
			write_start  <= 0;
			read_start   <= 1;
		  end
		2'b11:
		  begin
			write_start  <= 0;
			read_start   <= 0;
		  end
	  endcase
   end
end

/* Stop Clock Disable -> SC = 0 */
/* Stop Clock Enable  -> SC = 1 */

/* Self Refresh Disable -> SR = 0 */
/* Self Refresh Enable  -> SR = 1 */

/* Precharge Power Down Disable -> PPD = 0 */
/* Precharge Power Down Enable  -> PPD = 1 */

/* Deep Power Down Disable -> DPD = 0 */
/* Deep Power Down Enable  -> DPD = 1 */

always@(posedge CLK, negedge RESETn)
begin	
	if(RESETn == 1'b0 )
	  begin   
		AHB_WRITE	<= 1'b0;
		AHB_READ	<= 1'b0;
		AHB_DATA    <= 32'h0;
		AHB_ADDR    <= MDDR_BASE_ADDRESS;
		ahb_state   <= 2'b00;
	  end
	else
	   begin
		 case (ahb_state)
			2'b00:
			begin
              PDM_tmp   <= PDM;
			  if ( PDM == 4'b0001 )                           /* SC = 0 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h414;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h084 ;		 	
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0010 )                       /* SC = 1 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h415;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h084 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0011 )                       /* SR = 0 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'hc88;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h008 ;		 	
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0100 )                       /* SR = 1 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'hca8;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h008 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0101 )                       /* PPD = 0 & DPD = 0 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h0;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0110 )                        /* PPD = 0 & DPD = 1 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b0111 )                       /* PPD = 1 & DPD = 0 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h2;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1000 )                       /* PPD = 1 & DPD = 1 */
				begin
				  AHB_WRITE	  <= 1'b1;
				  AHB_DATA    <= 32'h3;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1001 )                       /* Stop Clock */
				begin
				  AHB_READ	  <= 1'b1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h084 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1010 )                       /* Self Refresh */
				begin
				  AHB_READ	  <= 1'b1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h008 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1011 )                       /* Pre-charge Power Down */
				begin
				  AHB_READ	  <= 1'b1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1100 )                       /* Deep Power Down */
				begin
				  AHB_READ	  <= 1'b1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h010 ;		 		 
		          ahb_state   <= 2'b01;
				end
			  else if ( PDM == 4'b1101 )                       /* DDRC Status register */
				begin
				  AHB_READ	  <= 1'b1;
		          AHB_ADDR    <= MDDR_BASE_ADDRESS + 12'h0E4 ;
		          ahb_state   <= 2'b01;
				end
			  else
				begin
					ahb_state   <=  2'b00;
				end
			end
			2'b01:
			begin
		      AHB_WRITE	  <= 1'b0;
		      AHB_READ	  <= 1'b0;
		      AHB_DATA    <= 32'h0;
		      AHB_ADDR    <= MDDR_BASE_ADDRESS;

	          if( PDM  == PDM_tmp ) 
                begin
		          ahb_state   <= 2'b01;
                end
              else
                begin
		          ahb_state   <= 2'b00;
                end
			end
		  endcase
		end
end

endmodule

