///////////////////////////////////////////////////////////////////////////////////////////////////
// Company: Microsemi Corporation
//
// File: DATAHANDLE_FSM.v
// File history:
//      1.0 Date: 7 Feb 2013 : Initial release
//      2.0 Date: 29 july 2013 : 11.1 SP1 Update
//      <Revision number>: <Date>: <Comments>
//      <Revision number>: <Date>: <Comments>
//
// Description: Implements and controls operations like loading the filter input data to the
// corresponding input data buffer and loading filter coefficients to the corresponding coefficient
// memory buffers. An APB bus slave is implemented to communicate with the MSS APB master.
//
// SmartFusion2: FIR FILTER DEMO
//
// Targeted device: <Family::SmartFusion2> <Die::M2S050T> <Package::896 FBGA>
// Author: Applications Engineering 
//
/////////////////////////////////////////////////////////////////////////////////////////////////// 


`timescale 1 ns/100 ps
module DATAHANDLE_FSM(
  PCLK,
  PENABLE,
  PSEL,
  PRESETN,
  PWRITE,
  PREADY,
  PSLVERR,
  PADDR,
  PWDATA,
  PRDATA,
  FILTER_COMPLETE,
  FIR_FFT_RD_ENABLE, 
  FIR_WR_ENABLE,
  WCLK, 
  RCLK,
  FFT_RE_RADDR,
  FIR_WADDR,
  SEL,
  FIR_DATA_OUT,
  FIR_RADDR,
  FIR_ENABLE,
  FFT_IM_DATA,
  FFT_IM_RADDR,
  COEF_WADDR,
  COEF_LOAD,
  COEF_WR_EN, 
  FIR_COEF_DATA_IN,
  FFT_RE_DATA
  );

parameter DATA_WIDTH = 16;                 // data width 
parameter ADDR_WIDTH = 16;                 // address width 

input  FILTER_COMPLETE;    
input  PCLK,PENABLE, PSEL, PRESETN, PWRITE;
input  [ADDR_WIDTH-1:0] PADDR;
input  [DATA_WIDTH-1:0] PWDATA;
input  [DATA_WIDTH-1:0] FFT_RE_DATA;
input  [15:0] FFT_IM_DATA;
input  [15:0] FIR_DATA_OUT;
input  [1:0] FIR_ENABLE;
input  COEF_LOAD;


output [DATA_WIDTH-1:0] PRDATA;
output PREADY, PSLVERR;
output FIR_FFT_RD_ENABLE;
output FIR_WR_ENABLE;
output WCLK,RCLK;
output [ADDR_WIDTH-7:0]  FFT_RE_RADDR,  FIR_WADDR;
output [DATA_WIDTH-1:0] FIR_COEF_DATA_IN;
output [9:0] FIR_RADDR;
output [9:0] FFT_IM_RADDR;
output [5:0] COEF_WADDR;
output COEF_WR_EN;
output SEL; 

reg SEL; 
reg [ADDR_WIDTH-7:0]  FFT_RE_RADDR, FIR_RADDR,FFT_IM_RADDR;
reg FIR_FFT_RD_ENABLE;
reg FIR_WR_ENABLE;
reg COEF_WR_EN;
reg PREADY;
reg [DATA_WIDTH-1:0] PRDATA;
reg  [1:0]   fsm;                       //state machine register


wire WCLK,RCLK;
wire [ADDR_WIDTH-7:0]  FIR_WADDR;
wire [5:0] COEF_WADDR;
wire FILTER_COMPLETE; 
wire [DATA_WIDTH-1:0] FIR_COEF_DATA_IN;
wire [DATA_WIDTH-1:0] FFT_RE_DATA;
wire [DATA_WIDTH-1:0] FIR_DATA_OUT,FFT_IM_DATA;

assign PSLVERR = 1'b0;
assign FIR_COEF_DATA_IN = PWDATA;
assign WCLK = PCLK;
assign RCLK = PCLK;
assign FIR_WADDR[ADDR_WIDTH-7:0] = PADDR[ADDR_WIDTH-5:2];

assign COEF_WADDR  = PADDR[7:2];


always@(PADDR)
begin
      if(FIR_ENABLE == 2'b00)
       begin
          FIR_RADDR[ADDR_WIDTH-7:0] = PADDR[ADDR_WIDTH-5:2];
          PRDATA = FIR_DATA_OUT;
       end
      else if(FIR_ENABLE == 2'b01)
        begin
          FFT_RE_RADDR[ADDR_WIDTH-7:0] = PADDR[ADDR_WIDTH-5:2];
          PRDATA = FFT_RE_DATA;
        end
      else if(FIR_ENABLE == 2'b10)
        begin
          FFT_IM_RADDR[ADDR_WIDTH-7:0] = PADDR[ADDR_WIDTH-5:2];
          PRDATA = FFT_IM_DATA;
        end
end

always@(posedge PCLK or negedge PRESETN)
if(~PRESETN)
  begin
      fsm <= 2'b00;
      FIR_FFT_RD_ENABLE <= 1'b0;
      FIR_WR_ENABLE <= 1'b0;
      PREADY <= 1'b1;
	  SEL <= 1'b0;
  end
else
  begin
  
  case (fsm)
     2'b00 :  begin
                  if (~PSEL)
                        begin
                          fsm <= 2'b00;                          
                        end
                  else        
                        begin
                          fsm <= 2'b01;
                          if (PWRITE)
                                begin
                                    if (COEF_LOAD) 
                                     begin
                                       COEF_WR_EN <= 1'b1;
                                       FIR_WR_ENABLE <= 1'b0;
                                      end
                                    else
                                      begin
                                       COEF_WR_EN <= 1'b0;
                                       FIR_WR_ENABLE <= 1'b1;
                                       end
                                    PREADY <= 1'b1;
                                end
                        end
               end

     2'b01 :  begin    
                          if (PWRITE)
                            begin 
                                FIR_FFT_RD_ENABLE <= 1'b0;
                                fsm <= 2'b00;
                               if (PADDR[ADDR_WIDTH-5:2] == 10'b1111111111 )
									begin
										SEL <= 1'b1;
                                        fsm<=2'b11;
									end
                             end
                          else
                             begin      
                                FIR_WR_ENABLE <= 1'b0;
								COEF_WR_EN <= 1'b0;
                                FIR_FFT_RD_ENABLE <= 1'b1;
                                PREADY <= 1'b1;
                                fsm <= 2'b10; 
                             end
              end

     2'b10 :  begin            
                          fsm <= 2'b11;
                               
              end

     2'b11 :  begin     
                          fsm <= 2'b00;
                          SEL <= 1'b0;     

              end

    default : fsm <= 2'b00;
  endcase
end
   
endmodule