/*******************************************************************************
 Copyright 2007 Actel Corporation.  All rights reserved.
 
 ANY USE OR REDISTRIBUTION IN PART OR IN WHOLE MUST BE HANDLED IN
 ACCORDANCE WITH THE ACTEL LICENSE AGREEMENT AND MUST BE APPROVED
 IN ADVANCE IN WRITING.

 Revision 3.0 April 30, 2007 : v3.0 CoreFFT Release
*******************************************************************************/
`timescale 1 ns/100 ps

`include "fftHeader.v" 

module fftTop (clk, ifiStart, ifiNreset, ifiD_valid, ifiD_im, ifiD_re,
  ifiRead_y, ifoLoad, ifoY_im, ifoY_re, ifoPong, ifoY_valid, ifoY_rdy );
  parameter WIDTH       = `WIDTH;
  parameter DWIDTH      = `DWIDTH;
  parameter TWIDTH      = `TWIDTH;
  parameter TDWIDTH     = `TDWIDTH;
  parameter LOGPTS      = `LOGPTS;
  parameter LOGLOGPTS   = `LOGLOGPTS;
  parameter RND_MODE    = `RND_MODE;
  parameter SCALE_MODE  = `SCALE_MODE;
  parameter PTS         = `PTS;
  parameter HALFPTS     = `PTS/2;
  parameter inBuf_RWDLY = `inBuf_RWDLY;

  input clk, ifiStart, ifiNreset, ifiD_valid, ifiRead_y;
  input[WIDTH-1:0] ifiD_im, ifiD_re;
  output ifoLoad, ifoPong, ifoY_valid, ifoY_rdy;
  output[WIDTH-1:0] ifoY_im, ifoY_re;

  wire[LOGPTS-2:0] ldA_w, rA_w, wA_w, tA_w, twid_wA_w, outBuf_wA_w;
  wire[LOGPTS-1:0] outBuf_rA_w;
  wire wEn_even_w, wEn_odd_w, inBuf_wEn_w, preSwCross_w, postSwCross_w, twid_wEn_w;
  wire outBuf_wEn_w, ldRiskOV_w, bflyRiskOV_w;
  wire[DWIDTH-1:0]readP_w, readQ_w, bflyInP_w, bflyInQ_w, bflyOutP_w, bflyOutQ_w;
  wire[TDWIDTH-1:0] T_w, twidData_w;
  wire[DWIDTH-1:0] outEven_w, outOdd_w;
  wire inBufValid_w, preSwValid_w, bflyValid_w, wLastStage_w;
  wire startFFTrd_w, startLoad_w, upScale_w;
  wire clkEn = 1'b1;

  // debug only
  assign displayBflyOutP = bflyOutP_w;
  assign displayBflyOutQ = bflyOutQ_w;
  assign displayInBuf_wEn = inBuf_wEn_w;

  sm_top #(.PTS(PTS), .HALFPTS(HALFPTS), .LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS),
           .inBuf_RWDLY(inBuf_RWDLY) ) smTop_0 
     (.clk(clk), .clkEn(clkEn), .ifiStart(ifiStart), .ifiNreset(ifiNreset),
      .ifiD_valid(ifiD_valid), .ifiRead_y(ifiRead_y),
      .ldA(ldA_w), .rA(rA_w), .wA(wA_w), .tA(tA_w), .twid_wA(twid_wA_w),
      .outBuf_wA(outBuf_wA_w), .outBuf_rA(outBuf_rA_w),
      .wEn_even(wEn_even_w), .wEn_odd(wEn_odd_w),
      .preSwCross(preSwCross_w),
      .twid_wEn(twid_wEn_w), 
      .inBuf_wEn(inBuf_wEn_w), .outBuf_wEn(outBuf_wEn_w), .smPong(ifoPong),
      .ldValid(ldValid_w), .inBuf_rdValid(inBufValid_w), .wLastStage(wLastStage_w),
      .smStartFFTrd(startFFTrd_w), .smStartLoad(startLoad_w),
      .ifoLoad(ifoLoad), .ifoY_valid(ifoY_valid), .ifoY_rdy(ifoY_rdy) );

  pipoBuffer #(.LOGPTS(LOGPTS), .DWIDTH(DWIDTH)) inBuf_0
     (.clk(clk), .clkEn(clkEn), 
      .rA(rA_w),
      .wA_load(ldA_w),
      .wA_bfly(wA_w),
      .ldData({ifiD_im, ifiD_re}),
      .wP_bfly(outEven_w), .wQ_bfly(outOdd_w),
      .wEn_bfly(inBuf_wEn_w),
      .wEn_even(wEn_even_w), .wEn_odd(wEn_odd_w),
      .pong(ifoPong),
      .outP(readP_w), .outQ(readQ_w));

  switch #(.DWIDTH(DWIDTH)) preBflySw_0 (.clk(clk),
      .inP(readP_w), .inQ(readQ_w),
      .sel(preSwCross_w), .outP(bflyInP_w), .outQ(bflyInQ_w),
      .validIn(inBufValid_w), .validOut(preSwValid_w));

  bfly2 #(.WIDTH(WIDTH), .TWIDTH(TWIDTH), .DWIDTH(DWIDTH),
          .TDWIDTH(TDWIDTH), .RND_MODE(RND_MODE) )
    bfly_0(.clk(clk), .upScale(upScale_w),
      .inP(bflyInP_w), .inQ(bflyInQ_w), .T(T_w),
      .outP(bflyOutP_w), .outQ(bflyOutQ_w),
      .validIn(preSwValid_w), .validOut(bflyValid_w),
      .swCrossIn(preSwCross_w), .swCrossOut(postSwCross_w)  ); 

  twiddle #(.TDWIDTH(TDWIDTH), .LOGPTS(LOGPTS)) 
                 lut_0 (.A(twid_wA_w), .T(twidData_w));
  twidLUT #(.LOGPTS(LOGPTS), .TDWIDTH(TDWIDTH)) twidLUT_1 (.clk(clk),
    .wA(twid_wA_w), .wEn(twid_wEn_w), .rA(tA_w), .D(twidData_w), .Q(T_w) );

  switch #(.DWIDTH(DWIDTH)) postBflySw_0 (.clk(clk),
      .inP(bflyOutP_w), .inQ(bflyOutQ_w),
      .sel(postSwCross_w), .outP(outEven_w), .outQ(outOdd_w), 
      .validIn(bflyValid_w), .validOut());

  outBuff #(.LOGPTS(LOGPTS), .DWIDTH(DWIDTH)) outBuff_0 (.clk(clk), .clkEn(clkEn),
    .rA(outBuf_rA_w), .wA(outBuf_wA_w), .inP(outEven_w), .inQ(outOdd_w),
    .wEn(outBuf_wEn_w), .outD({ifoY_im, ifoY_re}));

  // Autoscaling
  // monitor if input data .im and .re have MSB == sign
  assign ldRiskOV_w= ~( (ifiD_im[WIDTH-1] == ifiD_im[WIDTH-2]) &
                        (ifiD_re[WIDTH-1] == ifiD_re[WIDTH-2] )  );
  // monitor if the bfly result MSB == sign
  assign bflyRiskOV_w = ~( (bflyOutP_w[DWIDTH-1] == bflyOutP_w[DWIDTH-2]) &
                          (bflyOutP_w[WIDTH-1]  == bflyOutP_w[WIDTH-2] ) &
                          (bflyOutQ_w[DWIDTH-1] == bflyOutQ_w[DWIDTH-2]) &
                          (bflyOutQ_w[WIDTH-1]  == bflyOutQ_w[WIDTH-2] )  );

  autoScale #(.SCALE_MODE(SCALE_MODE)) autoScale_0 
   (.clk(clk), .clkEn(clkEn),
    .ldRiskOV(ldRiskOV_w), .bflyRiskOV(bflyRiskOV_w),
    .startLoad(startLoad_w), .startFFT(startFFTrd_w),
    .bflyOutValid(bflyValid_w), .wLastStage(wLastStage_w),
    .wEn_even(wEn_even_w), .wEn_odd(wEn_odd_w),
    .ifo_loadOn(ifoLoad), .upScale(upScale_w));
endmodule
