// ***************************************************************************/
//Actel Corporation Proprietary and Confidential
//Copyright 2009 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.
//
//Description:  CoreFFT
//              State Machine and Control modules
//
//Revision Information:
//Date         Description
//05Nov2009    Initial Release
//
//SVN Revision Information:
//SVN $Revision: $
//SVN $Data: $
//
//Resolved SARs
//SAR     Date    Who         Description
//
//Notes:
//

`timescale 1 ns/100 ps

/***********************************  SM TOP  *********************************/
module sm_top (clk, clkEn,
  slowClk,
  nGrst,
  ifiD_valid,
  ifiRead_y,
  ldA, wEn_even, wEn_odd,  // out; inBuf loading group
  rA, wA, inBuf_wEn, inBuf_rdValid, // out; inBuf processing group
  tA, twid_wA, twid_wEn,
  outBuf_wA, outBuf_wEn, outBuf_rA,
  preSwCross,     // out; pre-bfly switch control
  smPong,
  wLastStage,     // out; write back to in-place RAM: last stage
  fftRd_done_tick,
  smStartFFT,     // out; SM starts FFTing after clearing all conditions
  smStartLoad,    // out; inBuf is ready for another data load
  ifoLoad,        // out; inBuf can accept fresh data
  ifoY_valid,     // out; FFT'ed data sample valid
  ifoY_rdy);      // out; FFT results are ready
  parameter PTS       = 256;
  parameter HALFPTS   = 128;
  parameter LOGPTS    = 8;
  parameter LOGLOGPTS = 3;
  parameter RW_DLY    = 12;
  parameter MEMBUF    = 0;

  input clk, clkEn, slowClk;
  input nGrst;
  input ifiD_valid, ifiRead_y;

  output [LOGPTS-2:0] ldA, rA, wA, tA, twid_wA;
  output [LOGPTS-2:0] outBuf_wA;
  output [LOGPTS-1:0] outBuf_rA;
  output wEn_even, wEn_odd;
  output preSwCross;
  output twid_wEn;
  output inBuf_wEn, outBuf_wEn, smPong;
  output inBuf_rdValid, wLastStage;
  output smStartFFT;
  output smStartLoad;
  output ifoLoad, ifoY_valid, ifoY_rdy;
  output fftRd_done_tick;
  reg    fftRd_done_tick;
  reg    inBuf_wEn, outBuf_wEn, smStartLoad;
  reg    smPong /*synthesis syn_repicate = 1 */ ; 

  wire [LOGPTS+1:0] rTimer;
  wire [LOGPTS+1:0] rTimer_t2;                                      //g4
  wire [LOGPTS-2:0] wTimer_w;
  wire [LOGPTS-2:0] wTimer_t2;                                      //g4
  wire [LOGLOGPTS+1:0] rStage_w;
  wire [LOGLOGPTS+1:0] rStage_t2;                                   //g4
  reg  [LOGLOGPTS-1:0] wStage_r;
  wire [LOGLOGPTS-1:0] wStage_t2;                                   //g4
//g4  wire rLastStage_w;
  wire smStartLoad_w;
  wire rLastStage_t2;                                               //g4
  wire load_done_w, sync_rAwA_w, fftRd_done_w;
  reg preInBuf_wEn, preOutBuf_wEn, trueRst;
  reg smBuf_full;   // inBuf is full: FFT processing session can start
  reg smFft_rdy;    // FFT engine is idle = available for processing
  reg smFft_run;    // FFT engine is busy

//g4  reg sync_rAwA;
  wire sync_rAwA, pre2_sync_rAwA;                                   //g4
  reg outBuf_wEn_frEdge;
  // Reset logic:
  // - On external nGrst start one-time loading twidLUT
  // - While doing so, keep global async rst nGrst active
  // - After load is over, assert short rstAfterInit
  wire nGrsti = nGrst & (!twid_wEn);
  wire rstAfterInit;
  wire trueRst_w;

  wire Y_rdy_rearEdge, rst_rTimer;
  wire [LOGPTS-2:0] rAi;
  wire outBuf_rA_valid;

  reg rTimerTC_tick;
  wire rTimerTC;
  wire smStartFFT_g4;                                       //g4

  // ----------------------  Upper SM  ------------------------
  // ------------ Start FFTing when inBuf full AND fft engine is idle
  assign smStartFFT = MEMBUF ? (smBuf_full & smFft_rdy) : load_done_w;

  kitDelay_bit_reg # (.DELAY(2)) startFFT_g4_dly_0          //g4
//9/30/2011    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),    //g4
    (.nGrst(nGrst), .rst(1'b0), .clk(clk), .clkEn(clkEn),   //g4
      .inp(smStartFFT),                                     //g4
      .outp(smStartFFT_g4) );                               //g4

  // ------------ Start loading fresh data depending on buffer scheme
  assign smStartLoad_w = MEMBUF ? (trueRst_w | smStartFFT) :
                                  (trueRst_w | Y_rdy_rearEdge) ;

  // rear edge of the ifoY_rdy
  kitEdge # (.FRONT_EDGE(0)) edge_detect_0 (
     .nGrst(1'b1), .rst(1'b0), .clk(clk),
     .inp(ifoY_rdy),
     .outp(Y_rdy_rearEdge) );

  // FFT read inBuf timer
  assign rst_rTimer = MEMBUF ? trueRst : (trueRst | ifoLoad);
  rdFFTtimer # (.HALFPTS(HALFPTS), .LOGPTS(LOGPTS),
                .LOGLOGPTS(LOGLOGPTS), .RW_DLY(RW_DLY),
                .MEMBUF(MEMBUF) ) rdFFTtimer_0
         (.clk(clk), .nGrst(nGrsti),
          .rst(rst_rTimer),
          .smStartFFT(smStartFFT),
          .smFft_run(smFft_run),
          .rTimer(rTimer),
          .timerTC(rTimerTC),
          .rStage(rStage_w), 
          //g4  .rLastStage(rLastStage_w), 
          .rLastStage(rLastStage_t2),                                 //g4
          .fftRd_done(fftRd_done_w),
          .rValid(inBuf_rdValid));


  kitDelay_reg # (.BITWIDTH(LOGPTS+2), .DELAY(2) ) rTimer_dly2 (      //g4
    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),                //g4
    .inp(rTimer), .outp(rTimer_t2)  );                                //g4


  kitDelay_reg # (.BITWIDTH(LOGLOGPTS+2), .DELAY(2) ) rStage_dly2 (   //g4
    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),                //g4
    .inp(rStage_w), .outp(rStage_t2)  );                              //g4
  
  assign sync_rAwA_w = (rTimer == RW_DLY-1);                        //g4--

  kitDelay_bit_reg # (.DELAY(1)) pre2_sync_rw_0             //g4
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),    //g
      .inp(sync_rAwA_w),                                    //g
      .outp(pre2_sync_rAwA) );                              //g

  kitDelay_bit_reg # (.DELAY(2)) sync_rw_1                  //g4
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),    //g
      .inp(pre2_sync_rAwA),                                 //g
      .outp(sync_rAwA) );                                   //g

//g4  kitDelay_bit_reg # (.DELAY(2)) rLastStage_0               //g4
//g4    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),    //g
//g4      .inp(rLastStage_w),                                   //g
//g4      .outp(rLastStage_t2) );                               //g


//SPEED    counter #(.WIDTH(LOGPTS-1), .TC(HALFPTS-1)) wTimer_0 (
//SPEED      .clk(clk), .nGrst(nGrsti),
//SPEED  //g4    .rst(sync_rAwA | smStartFFT),
//SPEED      .rst(pre2_sync_rAwA | smStartFFT),        //g4
//SPEED      .cntEn(1'b1),
//SPEED      .tc(),
//SPEED      .Q(wTimer_w));

  //SPEED
  inplace_kitCountS # ( .WIDTH(LOGPTS-1), .BUILD_DC(0) ) wTimer_0 (
    .nGrst(nGrsti), .rst(pre2_sync_rAwA | smStartFFT), .clk(clk), 
    .clkEn(1'b1), .cntEn(1'b1), .Q(wTimer_w), .dc() );
  



    
  kitDelay_reg # (.BITWIDTH(LOGPTS-1), .DELAY(2) ) wTimer_dly_2 (     //g4
    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),                //g4
    .inp(wTimer_w), .outp(wTimer_t2)  );                              //g4
    

  kitDelay_reg #(.BITWIDTH(1), .DELAY(RW_DLY)) rw_dly_lastStage (
    .nGrst(nGrsti), .rst(trueRst), .clk(clk), .clkEn(clkEn),
    .inp(rLastStage_t2), .outp(wLastStage)  );                        //g4

  inBuf_ldA #(.PTS(PTS), .LOGPTS(LOGPTS))
    inBuf_ldA_0 (.clk(clk), .clkEn(clkEn), .nGrst(nGrsti),
                    .startLoad(smStartLoad),
                    //inData strobe
                    .ifiD_valid(ifiD_valid),
                    //out; inBuf is ready for new data (PTS new samples)
                    .ifoLoad(ifoLoad),
  //out; tells topSM the buffer is fully loaded and ready for FFTing
                    .load_done(load_done_w),
                    .ldA(ldA), .wEn_even(wEn_even), .wEn_odd(wEn_odd) );

//g4  inBuf_fftA #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) ) inBuf_rA_1
//g4   (.clk(clk), .clkEn(clkEn),
//g4    .timer(rTimer_t2[LOGPTS-2:0]),                                    //g4
//g4    .stage(rStage_t2[LOGLOGPTS-1:0]),                                 //g4
//g4    .lastStage(rLastStage_t2),                                        //g4
//g4    .bflyA(rAi_temp),
//g4    .swCross(preSwCross_temp));

  inBuf_fftA_pipe #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) ) inBuf_rA_0   //g4
   (.clk(clk), .clkEn(clkEn),
    .timer(rTimer[LOGPTS-2:0]),                             
    .stage(rStage_w[LOGLOGPTS-1:0]),                        
    .lastStage(rLastStage_t2),                              
    .bflyA(rAi),
    .swCross(preSwCross));

  assign rA = MEMBUF ? rAi : (
                   (outBuf_rA_valid==1'b0) ? rAi : outBuf_rA[LOGPTS-2:0] );

  twid_rA #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) ) twid_rA_0  (
      .clk(clk),
      .timer(rTimer_t2[LOGPTS-2:0]),                                //g4
      .stage(rStage_t2[LOGLOGPTS-1:0]),                             //g4      
      .tA(tA));

  // Twiddle LUT initialization
  twid_wA_gen #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) ) twid_wA_0
      ( .slowClk(slowClk), .ifiNreset(nGrst),
        .twid_wA(twid_wA), .twid_wEn(twid_wEn),
        .rstAfterInit(rstAfterInit));

  kitEdge # (.FRONT_EDGE(0)) init_rear_0 (
     .nGrst(nGrst), .rst(1'b0), .clk(clk),
     .inp(rstAfterInit),
     .outp(trueRst_w) );


  kitDelay_reg # (.BITWIDTH(LOGLOGPTS), .DELAY(2) ) wStage_dly_2 (    //g4
    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),                //g4
    .inp(wStage_r), .outp(wStage_t2)  );                              //g4

  // wA generator.  On the last stage the fftRd_done comes before the last
  // FFT results get written back to the inBuf, but it is not necessary since
  // the results get written into the output buffer.
//g4  inBuf_fftA #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) )
//g4    inBuf_wA_1 (.clk(clk), .clkEn(clkEn),
//g4    .timer(wTimer_t2), .stage(wStage_t2),                             //g4
//g4    .lastStage(1'b0),
//g4    .bflyA(wA_temp), .swCross());

  inBuf_fftA_pipe #(.LOGPTS(LOGPTS), .LOGLOGPTS(LOGLOGPTS) ) inBuf_wA_0   //g4
   (.clk(clk), .clkEn(clkEn),
    .timer(wTimer_w),                                  
    .stage(wStage_r),                                 
    .lastStage(1'b0),                                 
    .bflyA(wA),
    .swCross());

  outBufA #(.PTS(PTS), .LOGPTS(LOGPTS), .MEMBUF(MEMBUF) ) outBufA_0
   (.clk(clk), .clkEn(clkEn), .nGrst(nGrsti), .rst(trueRst),
    .timer(wTimer_t2),                                                    //g4
    .outBuf_wEn_frEdge(outBuf_wEn_frEdge),
    .ifiRead_y(ifiRead_y),
    .outBuf_wA(outBuf_wA), .outBuf_rA(outBuf_rA),
    .outBuf_rA_valid(outBuf_rA_valid),
    .rTimerTC_tick(rTimerTC_tick),
    .fftRd_done(fftRd_done_w),
    .ifoY_rdy(ifoY_rdy), .ifoY_valid(ifoY_valid));

  always @ (posedge clk) begin    // pipes
    trueRst       <= trueRst_w;
    smStartLoad   <= smStartLoad_w;
    inBuf_wEn     <= preInBuf_wEn;
    outBuf_wEn    <= preOutBuf_wEn;
    rTimerTC_tick <= rTimerTC;
    fftRd_done_tick <= fftRd_done_w;
  end

  always @ (posedge clk or negedge nGrsti) begin
    if(!nGrsti) begin
      smBuf_full    <= 0;
      smFft_rdy     <= 0;
      smFft_run     <= 0;
      smPong        <= 1;
      preInBuf_wEn  <= 0;
      preOutBuf_wEn <= 0;
      wStage_r      <= 'b0;
//g4      sync_rAwA <= 1'b0;
      outBuf_wEn_frEdge <= 1'b0;
    end
    else begin  //mark A
//g4      sync_rAwA <= sync_rAwA_w;
      if (trueRst) begin
        smBuf_full <= 0;
        smFft_rdy  <= 1;
        smFft_run <= 0;
        smPong <= 1;
        preInBuf_wEn  <= 0;
        preOutBuf_wEn <= 0;
        wStage_r    <= 'b0;
        outBuf_wEn_frEdge <= 1'b0;
      end
      else begin  // mark B
        outBuf_wEn_frEdge <= sync_rAwA & rLastStage_t2;             //g4

        if (load_done_w) smBuf_full <= 1;

        if (fftRd_done_w) begin
          smFft_rdy <= 1;
          smFft_run <= 0;
        end

        if (smStartFFT) begin
          smBuf_full  <= 0;
          smFft_rdy   <= 0;
//g4          smFft_run  <= 1;
          if(MEMBUF)  smPong <= ~smPong;
          else        smPong <= 1'b1;
        end

        if (smStartFFT_g4) begin                                    //g4
          smFft_run  <= 1;
        end

        if(pre2_sync_rAwA)                                          //g4    
          wStage_r    <= rStage_t2[LOGLOGPTS-1:0];                  //g4

        if(sync_rAwA) begin
          if(rLastStage_t2)      preOutBuf_wEn <= 1;                //g4
          if( (MEMBUF && (!rLastStage_t2)) || (!MEMBUF) )           //g4
            if(smFft_run)   preInBuf_wEn <= 1;
//g4          wStage_r    <= rStage_t2[LOGLOGPTS-1:0];                  //g4
        end
        else begin
          if(rTimerTC_tick) begin
            preInBuf_wEn <= 0;
            preOutBuf_wEn <= 0;
          end
        end
      end  // mark B
    end // mark A
  end  // always

endmodule

//     _______          __  _______ _
//    |  __ \ \        / / |__   __(_)
//    | |__) \ \  /\  / /     | |   _ _ __ ___   ___ _ __ ___
//    |  _  / \ \/  \/ /      | |  | | '_ ` _ \ / _ \ '__/ __|
//    | | \ \  \  /\  /       | |  | | | | | | |  __/ |  \__ \
//    |_|  \_\  \/  \/        |_|  |_|_| |_| |_|\___|_|  |___/

/**************************  READ inBuf SEQUENCER  ****************************/
// Once FFT computation starts, it runs for a number of stages.  Every stage
// takes HALFPTS + RW_DLY clk for the inBuf to write Bfly results back
// in-place before a next stage starts (RW_DLY - datapath delay thru
// bfly and switch.  Cannot start another stage until current results are back
// to the in-place RAM.
module rdFFTtimer (nGrst, rst, clk,
  smStartFFT,   // in; comes from topSm when it concludes the way is cleared
  smFft_run,    // in; from topSM: FFT processing in progress
  fftRd_done,
  rLastStage,
  rStage,
  rTimer,
  timerTC,
  rValid);
  parameter HALFPTS   = 128;
  parameter LOGPTS  = 8;
  parameter LOGLOGPTS  = 3;
  parameter RW_DLY = 12;
  parameter MEMBUF = 0;

  input clk, rst, nGrst;
  input smStartFFT, smFft_run;
  output rLastStage;  // terminal counts of rA and stage
  output[LOGLOGPTS+1:0] rStage;
  output[LOGPTS+1:0] rTimer;
  output timerTC;
  output fftRd_done, rValid;
  reg fftRd_done_r;
  reg [LOGLOGPTS+1:0] rStage_r;

  wire fftDone_w;
  reg preRdValid;     //r-s flop
  wire timerTCi, rLastStage_w, ce_rTimer;
  wire [LOGLOGPTS+1:0] rStage_w;
  reg rLastStage_r;
  
  wire [LOGPTS+1:0] rTimeri;      //g4
  wire timerTC_r, rValid_r;       //g4
  
  wire startFFT_tick2;    //26/04/13

  assign rStage = rStage_r;
//g4  assign fftRd_done = fftRd_done_r;
//g4  assign rLastStage = rLastStage_r;
  assign rTimer = rTimeri;
//g4  assign timerTC = timerTC_r;
//g4  assign rValid = rValid_r;
  //g4 Delays
//2  kitDelay_reg # (.BITWIDTH(LOGLOGPTS+2), .DELAY(2) ) dly_0 (
//2    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
//2    .inp(rStage_r), .outp(rStage)  );

//  kitDelay_reg # (.BITWIDTH(LOGPTS+2), .DELAY(2) ) dly_1 (
//    .nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
//    .inp(rTimeri), .outp(rTimer)  );
    
  kitDelay_bit_reg # (.DELAY(2)) bit_dly_2
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
    .inp(rLastStage_r),
    .outp(rLastStage) );
  kitDelay_bit_reg # (.DELAY(2)) bit_dly_3
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
    .inp(timerTC_r),
    .outp(timerTC) );
  kitDelay_bit_reg # (.DELAY(2)) bit_dly_4
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
    .inp(fftRd_done_r),
    .outp(fftRd_done) );
  kitDelay_bit_reg # (.DELAY(2)) bit_dly_5
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
    .inp(rValid_r),
    .outp(rValid) );
  
  //26/04/13
  kitDelay_bit_reg # (.DELAY(2)) startFFT_dly_0
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(1'b1),
    .inp(smStartFFT),
    .outp(startFFT_tick2) );
  //26/04/13

  // To prevent fake ifoY_rdy and ifoY_valid caused by fftRd_done,
  // do not let rdFFTTimer run outside smFft_run
  assign ce_rTimer = smFft_run | smStartFFT;

  // counts pair of samples read.  There are PTS/2 pairs
  counter_w #(.WIDTH(LOGPTS+2), .TC(HALFPTS+RW_DLY-1)) rA_timer (.clk(clk),
    .nGrst(nGrst), .rst(rst|smStartFFT), .cntEn(ce_rTimer), .tc_r(timerTC_r), .tc(timerTCi), .Q(rTimeri) );

  // counts stages
  counter #(.WIDTH(LOGLOGPTS+2), .TC(LOGPTS-1)) stage_timer (.clk(clk),
    .nGrst(nGrst),.rst(rst|smStartFFT),.cntEn(timerTCi),.tc(rLastStage_w),.Q(rStage_w));

  assign fftDone_w = rLastStage_r & timerTC_r;

  always @ (posedge clk or negedge nGrst) begin
    if(!nGrst) begin
      preRdValid    <= 1'b0;
      fftRd_done_r  <= 1'b0;
      rStage_r      <= 'b0;
      rLastStage_r  <= 1'b0;
    end
    else begin
      rStage_r      <= rStage_w;
      rLastStage_r  <= rLastStage_w;
      fftRd_done_r  <= fftDone_w;
      if (rst)
        preRdValid <= 1'b0;
      else begin                                    //26/04/13 
        // on startFFT the valid reading session always starts
        if (startFFT_tick2) preRdValid <= 1'b1;     //26/04/13
      
        else if(ce_rTimer) begin
          if (rTimeri==HALFPTS-1) preRdValid <= 1'b0;
  //26/04/13        if (smStartFFT) preRdValid <= 1'b1;
          // reading session starts on rTimerTC except after the lastStage
          if ((!rLastStage_r) & timerTC_r & smFft_run) preRdValid <= 1'b1;
        end
      end
    end
  end

  kitDelay_bit_reg # (.DELAY(3)) bit_dly_0
    (.nGrst(1'b1), .rst(1'b0), .clk(clk), .clkEn(1'b1),
     .inp(preRdValid),
     .outp(rValid_r) );
endmodule

//                 _     _         _____
//        /\      | |   | |       / ____|
//       /  \   __| | __| |_ __  | |  __  ___ _ __
//      / /\ \ / _` |/ _` | '__| | | |_ |/ _ \ '_ \
//     / ____ \ (_| | (_| | |    | |__| |  __/ | | |
//    /_/    \_\__,_|\__,_|_|     \_____|\___|_| |_|

//********************** inBuf LOAD ADDRESS GENERATOR **********************/
module inBuf_ldA (nGrst, clk, clkEn,
  startLoad,    // comes from topSM to start another loading cycle
  ifiD_valid,   // input data valid
  ifoLoad,      // tells user it is OK to keep loading: inBuf isn't full
  load_done,    // tells topSm the inbuf is full and ready for FFTing
  ldA,          // inBuf wA
  wEn_even,     // inBuf has two RAM's: even & odd as bfly takes 2 samples/clock
  wEn_odd );

  parameter PTS   = 256;
  parameter LOGPTS  = 8;

  input nGrst, clk, clkEn;
  input startLoad, ifiD_valid;
  output[LOGPTS-1:1] ldA;
  output ifoLoad, load_done, wEn_even, wEn_odd;
  reg ifoLoad;
  reg load_done;

  wire ldCountLsb;  // mark even/odd samples
  wire closeLoad_w, loadOver_w;
  wire load_over;       //g4
  wire ldValid;

  assign loadOver_w = closeLoad_w & ifiD_valid;
  
//g4  kitDelay_bit_reg # (.DELAY(4)) bit_dly_0              //g4
//g4  (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),  //g4
//g4   .inp(loadOver_w),                                    //g4
//g4   .outp(loadOver) );                                   //g4
  
  assign ldValid    = ifoLoad & ifiD_valid;
  assign wEn_even   = ~ldCountLsb & ldValid;
  assign wEn_odd    =  ldCountLsb & ldValid;

  // Count samples loaded.  There is PTS samples to load, not PTS/2
  counter #(.WIDTH(LOGPTS), .TC(PTS-1)) ldCount (.clk(clk),
    .nGrst(nGrst), .rst(startLoad), .cntEn(ifiD_valid), .tc(closeLoad_w),
    .Q({ldA, ldCountLsb}));

  always @ (posedge clk or negedge nGrst)
    if(!nGrst) begin
      ifoLoad   <= 1'b0;
      load_done <= 1'b0;
    end
    else begin
      load_done <= loadOver_w;
      if (loadOver_w)   ifoLoad <= 1'b0;
//g4      load_done <= loadOver;            //g4
//g4      if (loadOver)   ifoLoad <= 1'b0;  //g4
      else
        if (startLoad)  ifoLoad <= 1'b1;
    end
endmodule


/*************************  outBuf ADDRESS GENERATOR  *************************/
// Writes data in normal order, reads in bit-reversed.
// Write address is based on the same timer as inBuf wA
module outBufA (nGrst, rst, clk, clkEn,
  timer,      // topSM counter synchronizes addr gens
  outBuf_wEn_frEdge,  // topSM supplies the signal
  ifoY_rdy,   // goes active after writing session
  outBuf_rA_valid,  // in min config, use outBuf rA to read in-place RAM
  ifiRead_y,        // host can slow down reading outBuf by lowering it
  outBuf_wA, outBuf_rA,
  rTimerTC_tick,
  fftRd_done,
  ifoY_valid);     // marks valid read data
  parameter PTS   = 256;
  parameter LOGPTS  = 8;
  parameter MEMBUF  = 0;

  input nGrst, rst, clk, clkEn;
  input[LOGPTS-2:0] timer;
  input outBuf_wEn_frEdge, ifiRead_y;
  input rTimerTC_tick;
  input fftRd_done;
  output [LOGPTS-2:0] outBuf_wA;
  output [LOGPTS-1:0] outBuf_rA;
  output ifoY_rdy, ifoY_valid;
  output outBuf_rA_valid;
  reg[LOGPTS-2:0] outBuf_wA;
  reg outBuf_rA_valid;                       //FF

  wire last_readout;
  wire count_tc;
  reg rdCtl_reg;
  wire [LOGPTS-1:0] rA_straight;
  wire rstRdA_tick;

  kitDelay_bit_reg # (.DELAY(1)) bit_dly_2
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),
     .inp(fftRd_done),      // Reset outBuf_rA after write session
     .outp(rstRdA_tick) );

  // Read addr counter
  counter #(.WIDTH(LOGPTS), .TC(PTS-1)) outBuf_rA_0 (.clk(clk), .nGrst(nGrst),
    .rst(rst|rstRdA_tick),
    .cntEn(rdCtl_reg),
    .tc(count_tc),
    .Q(rA_straight));
  assign outBuf_rA = {rA_straight[LOGPTS-1], reverse(rA_straight[LOGPTS-2:0])};

  kitDelay_bit_reg # (.DELAY(3)) bit_dly_0
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),
     .inp(outBuf_rA_valid),
     .outp(ifoY_rdy) );

  kitDelay_bit_reg # (.DELAY(3)) bit_dly_1
    (.nGrst(nGrst), .rst(rst), .clk(clk), .clkEn(clkEn),
     .inp(outBuf_rA_valid & rdCtl_reg),
     .outp(ifoY_valid) );

  // If READ_OUTP (ifiRead_y) isn't permanently asserted, last_readout must be
  // as follows to assure all output samples are accompanied by ifoY_valid.
  assign last_readout = count_tc & rdCtl_reg;

  always @ (posedge clk or negedge nGrst) begin
    if(!nGrst) begin
      outBuf_rA_valid   <= 1'b0;
      outBuf_wA         <= 'b0;
      rdCtl_reg         <= 1'b0;
    end
    else begin
      // reset flop on write session and after reading
      // In buffered mode stop outBuf_rA_valid and consequently ifoY_rdy and
      // ifoY_valid on the last stage (when engine writes results in outp
      // buffer).  The engine has priority so it writes over the older results
      if (rst||fftRd_done||(last_readout&&outBuf_rA_valid)||
          (outBuf_wEn_frEdge && MEMBUF) )  outBuf_rA_valid <= 1'b0;
      else // set it after write session
        if (rstRdA_tick)      outBuf_rA_valid <= 1'b1;
      outBuf_wA <= timer;
      rdCtl_reg <= ifiRead_y;
    end
  end

  function[LOGPTS-2:0] reverse;
    input [LOGPTS-2:0] in;
    integer i;
    begin
      for (i=0; i<LOGPTS-1; i=i+1)  reverse[i] = in[LOGPTS-2-i];
    end
  endfunction
endmodule


/**************  inBuf ADDR GEN WHEN PROCESSING DATA vs LOADING  **************/
// The core utilizes in-place algorithm, thus wA is a delayed copy of rA
module inBuf_fftA_pipe (clk, clkEn,
  timer,  // topSM counter synchronizes addr gens
  stage,  // stage number
  lastStage,
  /*Out. fftOn is on when fft is running. fftDone = fall edge of fftOn.
  It tells topSM a FFT cycle is (almost)over, inBuf has been fully
  read/written out.  Use fftOn as wEn for the inBuf  */
  bflyA,      // read or write address
  swCross);   // switch control
  parameter LOGPTS  = 8;
  parameter LOGLOGPTS  = 3;

  input clk, clkEn, lastStage;
  input[LOGPTS-2:0] timer;
  input[LOGLOGPTS-1:0] stage;
  output swCross;
  output[LOGPTS-2:0] bflyA;
  reg[LOGPTS-2:0] bflyA;

  reg swCross;

  wire swCross_w;
  wire[LOGPTS-2:0] bflyA_w;
  wire[LOGPTS-1:0] addrP_w, offsetPQ_w;

  wire[LOGPTS+1:0] addrMask2 = {1'b0, {LOGPTS{1'b1}}};
  wire[LOGPTS-1:0] addrMask1 = {(LOGPTS-1){1'b1} };
  
  reg [LOGPTS-2:0] addrP_r2, offsetPQ_r1, offsetPQ_r2;               
  reg [LOGPTS-2:0] mask2_r, mask1_r, timer_r, timer1_r;                       
  reg timer_bit0_r2;
  wire[LOGPTS-1:0] timer_shft_up, mask1_shft_stage;                            
  wire[LOGPTS:0] mask2_shft_stage;                                            

  // addrP = (timer<<1) & (addrMask2>>stage) | timer & (addrMask1>>stage);
  assign timer_shft_up = timer<<1;                                            
  assign mask1_shft_stage = addrMask1 >> stage;
  assign mask2_shft_stage = addrMask2 >> stage;
  
  assign addrP_w = ( timer1_r & mask2_r ) | ({1'b0, timer_r[LOGPTS-2:1]} & mask1_r);

  // address offset between P and Q
	// offsetPQ = (1<<(NumberOfStages-1-stage));
  assign offsetPQ_w = ( 1<<(LOGPTS-1) ) >> stage;
  /* rA takes either Paddr or Qaddr value (Qaddr=Paddr+offsetPQ) per clock, i.e.
  at even clk rA=Paddr, at odd clk rA=Qaddr. (Every addr has a pair of data
  samples).  Timer LSB controls which clk is happening now.  The same timer LSB
  controls switch(es). */
  assign bflyA_w = timer_bit0_r2 ? (addrP_r2+offsetPQ_r2) : addrP_r2;

  assign swCross_w = lastStage ? 0 : timer_bit0_r2;

  always @ (posedge clk) begin
    if (clkEn) begin
      offsetPQ_r1 <= offsetPQ_w[LOGPTS-1:1];                    
      timer_r     <= timer;
      timer1_r    <= timer_shft_up[LOGPTS-1:1];
      mask1_r     <= mask1_shft_stage[LOGPTS-1:1];
      mask2_r     <= ~(mask2_shft_stage[LOGPTS-1:1]);

      addrP_r2    <= addrP_w;
      offsetPQ_r2 <= offsetPQ_r1;                               
      timer_bit0_r2 <= timer_r[0];

      bflyA <= bflyA_w;
      swCross <= swCross_w;
    end
  end
endmodule

/*
module inBuf_fftA (clk, clkEn,
  timer,  // topSM counter synchronizes addr gens
  stage,  // stage number
  lastStage,
  //Out. fftOn is on when fft is running. fftDone = fall edge of fftOn.
  //It tells topSM a FFT cycle is (almost)over, inBuf has been fully
  //read/written out.  Use fftOn as wEn for the inBuf
  bflyA,      // read or write address
  swCross);   // switch control
  parameter LOGPTS  = 8;
  parameter LOGLOGPTS  = 3;

  input clk, clkEn, lastStage;
  input[LOGPTS-2:0] timer;
  input[LOGLOGPTS-1:0] stage;
  output swCross;
  output[LOGPTS-2:0] bflyA;
  reg[LOGPTS-2:0] bflyA;

  reg swCross;

  wire swCross_w;
  wire[LOGPTS-2:0] bflyA_w;
  wire[LOGPTS-1:0] addrP_w, offsetPQ_w;

  wire[LOGPTS+1:0] addrMask2 = {1'b0, {LOGPTS{1'b1}}};
  wire[LOGPTS-1:0] addrMask1 = {(LOGPTS-1){1'b1} };
  
  reg [LOGPTS-2:0] addrP_r, offsetPQ_r;      //g4

  // calculate addrP:
  //  addrP = (count<<1) & (addrMask2>>stage) | count & (addrMask1>>stage);
  assign addrP_w = ( (timer<<1) & ~(addrMask2>>stage) ) |
              (timer & (addrMask1>>stage));

  // address offset between P and Q
	// offsetPQ = (1<<(NumberOfStages-1-stage));
  assign offsetPQ_w = ( 1<<(LOGPTS-1) ) >> stage;
  // rA takes either Paddr or Qaddr value (Qaddr=Paddr+offsetPQ) per clock, i.e.
  //at even clk rA=Paddr, at odd clk rA=Qaddr. (Every addr has a pair of data
  //samples).  Timer LSB controls which clk is happening now.  The same timer LSB
  //controls switch(es)
  assign bflyA_w = timer[0] ? (addrP_w[LOGPTS-1:1]+offsetPQ_w[LOGPTS-1:1]) : addrP_w[LOGPTS-1:1];
//g4  assign bflyA_w = timer[0] ? (addrP_r + offsetPQ_r) : addrP_r;           //g4


  assign swCross_w = lastStage ? 0 : timer[0];

  always @ (posedge clk) begin
    if (clkEn) begin
      bflyA <= bflyA_w;
      swCross <= swCross_w;
      addrP_r <= addrP_w[LOGPTS-1:1];                                     //g4
      offsetPQ_r  <= offsetPQ_w[LOGPTS-1:1];                              //g4
    end
  end
endmodule
*/

/***************************  TWIDDLE rA GENERATOR  ***************************/
module twid_rA (clk, timer, stage, tA);
  parameter LOGPTS  = 8;
  parameter LOGLOGPTS  = 3;

  input clk;
  input[LOGPTS-2:0] timer;
  input[LOGLOGPTS-1:0] stage;
  output reg[LOGPTS-2:0] tA;
  //twiddleMask = ~(0xFFFFFFFF<<(NumberOfStages-1));
  //addrTwiddle =
  //    (reverseBits(count, NumberOfStages-1))<<(NumberOfStages-1-stage);
  // mask out extra left bits
  //addrTwiddle = addrTwiddle & twiddleMask;

  wire[2*LOGPTS-2:0] tA_w;
  reg [LOGPTS-2:0] timer_tick;
  reg [LOGLOGPTS-1:0] stage_tick, stage_tick2;

  wire [2*LOGPTS-1:0] tA_const;

  assign tA_const = reverse(timer_tick)<<(LOGPTS-1);
  assign tA_w = tA_const>>stage_tick2;

  always @ (posedge clk) begin
    tA          <= tA_w[LOGPTS-2:0];
    timer_tick  <= timer;
    stage_tick2 <= stage_tick;
    stage_tick  <= stage;
  end

  function[LOGPTS-2:0] reverse;
    input [LOGPTS-2:0] in;
    integer i;
    begin
      for (i=0; i<LOGPTS-1; i=i+1)
        reverse[i] = in[LOGPTS-2-i];
    end
  endfunction

endmodule


module twid_wA_gen (slowClk, ifiNreset, twid_wA, twid_wEn, rstAfterInit);
  parameter LOGPTS  = 8;
  parameter LOGLOGPTS  = 3;

  input slowClk, ifiNreset;   // async global reset
  output [LOGPTS-2:0] twid_wA;
  output rstAfterInit, twid_wEn;
  reg rstAfterInit, twid_wEn;

  reg preRstAfterInit;

  bcounter #(.WIDTH(LOGPTS-1)) slowTimer (.clk(slowClk),
    .nGrst(ifiNreset), .rst(1'b0), .cntEn(twid_wEn), .Q(twid_wA) );

  always @ (posedge slowClk or negedge ifiNreset) begin
    if (!ifiNreset)  begin
      twid_wEn <= 1'b1;
      rstAfterInit    <= 1'b0;
      preRstAfterInit <= 1'b0;
    end
    else begin
      rstAfterInit <= preRstAfterInit;
      if ( twid_wA == {(LOGPTS-1){1'b1}}) twid_wEn <= 1'b0;
      preRstAfterInit <= ( twid_wA == {(LOGPTS-1){1'b1}});
    end
  end
endmodule