// ****************************************************************************/   
// Actel Corporation Proprietary and Confidential   
// Copyright 2010 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: CmdDec.v - Command Decoder logic block
//   
// Revision Information:   
// Date            Description   
// ----            -----------------------------------------   
// 16May13         Inital. Ports and Parameters declaration   
//   
// SVN Revision Information:   
// SVN $Revision: 11146 $   
// SVN $Date: 2009-11-21 11:44:53 -0800 (Sat, 21 Nov 2009) $   
//   
// Resolved SARs   
// SAR      Date     Who   Description   
//    
// Notes:   
// 1.    
//   
// ****************************************************************************/   
`timescale 1 ns/10 ps   
 
 
module CmdDec (   
                  clk,   
                  resetn,   
                  // From UserIF
                  uctrig_i,
                  uclatchcmd_i,   
                  uclatchoptions_i,
                  uclatchzer_i,
                  uchprior_flushreq_i,         
                  
                  uccrypto_key_i,
                  uccrypto_iv_i,    
                  uccrypto_mode_i,   
                  uccrypto_nblocks_i,
                  uccrypto_length_i,
                  
                  ucnrbg_length_i,   
                  ucnrbg_handle_i,   
                  ucnrbg_addlength_i,
                  ucnrbg_prreq_i,

                  ucdpa_key_i,
                  ucdpa_optype_i,
                  ucdpa_path_i,

                  ucspi_txreq_en_i,   
                  ucspi_txdata_i,   
                  ucspi_size_i,   
                  ucspi_frmcnt_i,

                  uccommblk_int_i,
                  
                  ucdata_wvalid_i,
                  ucdata_w_i,

                  ucvalid_cmd_i,     

                  mchready_i,
                  
                  // burstlen values from User IF
                  spilength,
                  // From FSM logic IF
                  fcdataout_i,
                  fcbusreq_i,
                  fctrans_done_i,
                  fcpop_i,
                  fcpush_i,
                  
                  idle_trigger,
                  rvalid_out_en,
                  clr_req,

                  // To UserIF
                  cuspi_rxval_o,   
                  cuspi_rxdata_o,
                  
                  cudata_wrdy_o,
                  cudata_rvalid_o,
                  cudata_r_o,
                  custatus_valid_o,
                  cutrans_done_o,
                  cubusy_o,
                  cuhprior_flushdone_o,
                  custatus_out_en,
                  
                  // To FSM logic IF
                  cfgrant_o,

                  cfwr_req_d,
                  cfrd_req_d,
                  cfwr_req_o,
                  cfrd_req_o,
                  cfrd_resp_o,
                  cfburst_len_wr_o,
                  cfburst_len_rd_o,

                  cfdatain_o,
                  cfsrc_addr_o,
                  cfdst_addr_o,
                  cfcommaccess_active,
                  cfcommaccess_resp_active

                  );   
   
   //------------------------------------------------------------------------------   
   // Parameter declarations   
   //------------------------------------------------------------------------------   
   parameter SNSERVICE        = 0;    
   parameter DSNPTR           = 0;
   parameter UCSERVICE        = 0;    
   parameter USERCODEPTR      = 0;
   parameter DCSERVICE        = 0;    
   parameter DEVICECERTPTR    = 0;
   parameter UDVSERVICE       = 0;    
   parameter DESIGNVERPTR     = 0;
 
   parameter CRYPTOAES128SERVICE    = 0;    
   parameter CRYPTOAES128DATAPTR    = 0;
   parameter CRYPTOAES256SERVICE    = 0;
   parameter CRYPTOAES256DATAPTR    = 0;
   parameter CRYPTOSHA256SERVICE    = 0;
   parameter CRYPTOSHA256DATAPTR    = 0;
   parameter CRYPTORSLTPTR          = 0;
   parameter CRYPTODATAINPPTR       = 0;
   parameter CRYPTOHMACSERVICE      = 0;
   parameter CRYPTOHMACDATAPTR      = 0;
   parameter CRYPTOSRCADPTR         = 0;
   parameter CRYPTODSTADPTR         = 0;
 
   parameter FFSERVICE              = 0;    
   
   parameter KEYTREESERVICE         = 0;
   parameter KEYTREEDATAPTR         = 0;
   parameter PPUFCHRESPSERVICE      = 0;
   parameter PPUFCHRESPPTR          = 0;
   parameter PPUFCHRESPKEYADDR      = 0;
 
   parameter NRBGSERVICE            = 0;    
   parameter NRBGINSTPTR            = 0;
   parameter NRBGPERSTRINGPTR       = 0;
   parameter NRBGGENPTR             = 0;
   parameter NRBGREQDATAPTR         = 0;
   parameter NRBGRESEEDPTR          = 0;
   parameter NRBGADDINPPTR          = 0;
 
   parameter ZERSERVICE       = 0;  
   parameter PROGIAPSERVICE   = 0;
   parameter PROGSPIADR       = 0;
   parameter PROGNVMDISERVICE = 0;    
   parameter PORDSERVICE      = 0;                                   
 
 
 
   localparam AHB_AWIDTH      = 32;   
   localparam AHB_DWIDTH      = 32;   
 
   // State Machine parameter definition
   localparam C_IDLE       = 2'b00;
   localparam C_REQ_PHASE  = 2'b01;
   localparam C_RESP_PHASE = 2'b10;

  // State Machine parameter definition
   localparam REQ_IDLE           = 6'b000000;
   localparam REQ_WAIT_MEMWR1    = 6'b000001;
   localparam REQ_MEMWR_DESC     = 6'b000010;
   localparam REQ_WAIT_MEMWR2    = 6'b000011;
   localparam REQ_MEMWR_DATA     = 6'b000100;
   localparam REQ_PHASE          = 6'b000101;
   localparam REQ_COMMWR         = 6'b000110;
   localparam REQ_FIIC_INT       = 6'b000111;
   localparam REQ_POLL_CINT1     = 6'b001000;
   localparam REQ_RDCOMM_STATUS1 = 6'b001001;
   localparam REQ_WRCOMM_CTRL    = 6'b001010;
   localparam REQ_WRCOMM_INT     = 6'b001011;
   localparam REQ_WRCOMM_FRM     = 6'b001100;
   localparam REQ_WRCOMM_DATA    = 6'b001101;
   localparam REQ_POLL_CINT2     = 6'b001110;
   localparam REQ_RDCOMM_STATUS2 = 6'b001111;
   localparam REQ_WAIT_REG1      = 6'b010000;
   localparam REQ_WAIT_REG2      = 6'b010001;
   localparam REQ_WAIT_REG3      = 6'b010010;
   localparam REQ_WAIT_REG4      = 6'b010011;
   localparam REQ_WAIT_REG5      = 6'b010100;
   localparam REQ_WAIT_REG6      = 6'b010101;
   localparam REQ_WAIT_REG7      = 6'b010110;
   localparam REQ_WAIT_REG8      = 6'b010111;
   localparam REQ_WAIT_REG9      = 6'b011000;
   localparam REQ_RD_INT         = 6'b011011;   
   localparam REQ_RDCOMM_INT     = 6'b011100;
   localparam REQ_WAIT_REG10     = 6'b100001;
   localparam REQ_WAIT_REG11     = 6'b100010;
   localparam REQ_WAIT_REG12     = 6'b100011;
   localparam REQ_WAIT_REG13     = 6'b100100;
   localparam REQ_WRCOMM_CTRL2   = 6'b100101;
   localparam REQ_WRCOMM_CTRL3   = 6'b100110;
   localparam REQ_WRCOMM_CTRL4   = 6'b100111;
   localparam REQ_WRCOMM_INT2    = 6'b101000;

   localparam RESP_IDLE           = 6'b000000;
   localparam RESP_PHASE          = 6'b000001;
   localparam RESP_COMMRD         = 6'b000010;
   localparam RESP_RDCOMM_STATUS  = 6'b000011;
   localparam RESP_RDCOMM_FRM     = 6'b000100;
   localparam RESP_RDCOMM_DESC    = 6'b000101;
   localparam RESP_RDCOMM_DATA    = 6'b000110;
   localparam RESP_WAIT_MEMRD     = 6'b000111;
   localparam RESP_MEMRD          = 6'b001000;
   localparam RESP_POLL_CINT1     = 6'b001001;
   localparam RESP_POLL_CINT2     = 6'b001010;
   localparam RESP_POLL_CINT3     = 6'b001011;
   localparam RESP_POLL_CINT4     = 6'b001100;
   localparam RESP_REG1           = 6'b001101;   
   localparam RESP_REG2           = 6'b001110;   
   localparam RESP_REG3           = 6'b001111;   
   localparam RESP_REG4           = 6'b010000;   
   localparam RESP_REG5           = 6'b010001;
   localparam RESP_REG6           = 6'b010010;
   localparam RESP_REG7           = 6'b010011;
   localparam RESP_REG8           = 6'b010100;
   localparam RESP_REG9           = 6'b010101;
   localparam RESP_WRCOMM_CTRL1   = 6'b010110;   
   localparam RESP_WAIT_REG11     = 6'b010111;
   localparam RESP_WRCOMM_CTRL2   = 6'b011000;   
   localparam RESP_WAIT_REG12     = 6'b011001;
   localparam RESP_RDCOMM_STATUS2 = 6'b011010;
   localparam RESP_RDCOMM_STATUS3 = 6'b011011;
   localparam RESP_RDCOMM_FRM2    = 6'b011100;
   localparam RESP_REG10          = 6'b011101;
   localparam RESP_REG11          = 6'b011110;
   localparam RESP_POLL_CINT5     = 6'b011111;
   localparam RESP_RDCOMM_STATUS4 = 6'b100000;
   localparam RESP_RDCOMM_FRM3    = 6'b100001;
   localparam RESP_REG12          = 6'b100010;
   localparam RESP_WRCOMM_INT2    = 6'b100011;

   localparam HPRIOR_POLL_WAIT     = 3'b000;
   localparam HPRIOR_POLL_CINT     = 3'b001;
   localparam HPRIOR_RDCOMM_STATUS = 3'b010;
   localparam HPRIOR_WRCOMM_CTRL   = 3'b011;
   localparam HPRIOR_WAIT          = 3'b100;

   localparam COMM_CTRL_REG         = 32'h40016000;
   localparam COMM_STATUS_REG       = 32'h40016004;
   localparam COMM_INTEN_REG        = 32'h40016008;
   localparam COMM_DATA8_REG        = 32'h40016010;
   localparam COMM_DATA32_REG       = 32'h40016014;
   localparam COMM_FRM8_REG         = 32'h40016018;
   localparam COMM_FRM32_REG        = 32'h4001601C;

   //------------------------------------------------------------------------------   
   // Port declarations   
   //------------------------------------------------------------------------------   
   
   // -----------   
   // Inputs   
   // -----------   
   input      clk;   
   input      resetn;   
   // User IF   
   input      uctrig_i;
   input [7:0] uclatchcmd_i;
   input [2:0] uclatchoptions_i;
   input       uclatchzer_i;   
   input       uchprior_flushreq_i;

   // Crypto inputs
   input [255:0] uccrypto_key_i;
   input [127:0] uccrypto_iv_i;
   input [7:0]   uccrypto_mode_i;
   input [15:0]  uccrypto_nblocks_i;
   input [31:0]  uccrypto_length_i;
   
   // NRBG inputs
   input [7:0]   ucnrbg_length_i;
   input [7:0]   ucnrbg_handle_i;
   input [7:0]   ucnrbg_addlength_i;
   input [7:0]   ucnrbg_prreq_i;
   

   // DPA inputs
   input [255:0] ucdpa_key_i;
   input [7:0]   ucdpa_optype_i;
   input [127:0] ucdpa_path_i;
   
   // SPI inputs
   input         ucspi_txreq_en_i;   
   input [7:0]   ucspi_txdata_i;   
   input [5:0]   ucspi_size_i;   
   input [15:0]  ucspi_frmcnt_i; 

   input         uccommblk_int_i;
   
   input         ucdata_wvalid_i;
   input [31:0]  ucdata_w_i;
   input         ucvalid_cmd_i;

   input         mchready_i;
   
   input [31:0]  fcdataout_i;   
   input         fcbusreq_i;
   input         fctrans_done_i;
   input         fcpop_i;
   input         fcpush_i;

   input         idle_trigger;
   input         rvalid_out_en;   
   input         clr_req;   

   input [31:0]  spilength;

   // -----------  
   // Outputs  
   // -----------  
   // User IF   
   output        cuspi_rxval_o;   
   output [7:0]  cuspi_rxdata_o;

   output        cudata_wrdy_o;
   output        cudata_rvalid_o;
   output [AHB_DWIDTH - 1:0] cudata_r_o;
   output                    custatus_valid_o;   
   output                    cutrans_done_o;
   output                    cubusy_o;
   output                    cuhprior_flushdone_o;
   
   
   // To FSM Control block
   output                    cfgrant_o;

   output                    cfwr_req_d;
   output                    cfrd_req_d;
   output                    cfwr_req_o;
   output                    cfrd_req_o;
   output                    cfrd_resp_o;
   output [31:0]             cfburst_len_wr_o;
   output [31:0]             cfburst_len_rd_o;
   output [31:0]             cfdatain_o;   
   output [31:0]             cfsrc_addr_o;   
   output [31:0]             cfdst_addr_o;
   output                    cfcommaccess_active;   
   output                    cfcommaccess_resp_active;   
   output                    custatus_out_en;

   //output                    FF_entry_led;    // Used only for validation
   //output                    FF_exit_led;     // Used only for validation

   // -----------------  
   // Internal signals  
   // -----------------  
   reg [5:0]                 req_curr_state;     // Command Decoder REQ S/M current State
   reg [5:0]                 req_next_state;     // Command Decoder REQ S/M next State 
   reg [5:0]                 resp_curr_state;     // Command Decoder RESP S/M current State
   reg [5:0]                 resp_next_state;     // Command Decoder RESP S/M next State 
   reg [2:0]                 hprior_curr_state;     // Command Decoder I/F S/M current State
   reg [2:0]                 hprior_next_state;     // Command Decoder I/F S/M next State 
   reg [1:0]                 main_curr_state;       // Command Decoder MAI S/M current State 
   reg [1:0]                 main_next_state;       // Command Decoder MAIN S/M next State 

   wire                      cfgrant_o;
   reg                       cfgrant_req;
   reg                       cfgrant_resp;
   reg                       cfwr_req_o;
   
   wire                       cfwr_req_int;
   reg                        cfwr_req_d;
   reg                        cfwr_req_d1;
   wire                       cfwr_req_c;

   reg                        cfrd_req_o;
   reg                        cfrd_req_d;

   reg                        cfrd_resp_o;
   reg [31:0]                 cfburst_len_wr_o;
   reg [31:0]                 cfburst_len_rd_o;
   reg [31:0]                 cfdatain_o;
   reg [31:0]                 cfdatain_d1;
   reg                        fctrans_done_d1;
   reg                        fctrans_done_d2;
   reg                        fcbusreq_d1;
   
   reg [31:0]                 cfburst_len_wr_d1;
   reg [31:0]                 cfburst_len_rd_d1;

   reg [31:0]                 cfsrc_addr_o;   
   reg [31:0]                 memrd_data_addr;
   
   reg [31:0]                 cfdst_addr_o;
   reg [31:0]                 cfsrc_addr_int;   
   reg [31:0]                 cfdst_addr_int;
   
   reg                        cubusy_o;
   reg                        req_phase_active;
   reg                        resp_phase_active;
   
   reg [15:0]                 burstlen_memwr_desc;
   reg [31:0]                 burstlen_memwr_data;
   reg [15:0]                 burstlen_memrd_data;
   reg [15:0]                 burstlen_memrd_data_d1;
   reg [479:0]                memwr_desc;
   reg [31:0]                 memwr_data;
   reg [31:0]                 memwr_desc_int;
   
   reg [31:0]                 memwr_desc_addr;
   reg [31:0]                 memwr_data_addr;   

   reg                        req_desc_done;
   reg                        resp_desc_done;   
   reg                        resp_data_done;   
   reg                        req_phase_active_pulse;
   reg                        req_phase_active_d1;   
   reg                        resp_data_done_d1;   
   reg                        resp_phase_done_d1;   
   reg                        resp_phase_done_pulse;   
   reg                        resp_phase_active_d1;
   reg                        resp_phase_active_pulse;
   reg                        custatus_out_en;
   
   reg                        resp_frm_done;

   reg                        req_phase_done;
   reg                        req_phase_done_d1;
   

   reg [31:0]                 req_dstreg_addr;
   reg [31:0]                 req_srcreg_addr;
   reg [31:0]                 req_dstreg_data;
   reg [31:0]                 req_srcreg_data;
   
   reg [31:0]                 resp_srcreg_addr;
   reg [31:0]                 resp_srcreg_data;
   reg                        cfcommaccess_active;
   reg                        cfcommaccess_resp_active;
   reg                        fiicreg_done;
   reg                        commctrlreg_done;
   reg                        resp_phase_done;   
   reg                        datawr_reqd;
   wire                       cudata_wrdy_int;
   reg                        cudata_wrdy_o;
   reg                        cudata_wrdy_d1;
   wire                       cfdata_w_o;

   wire                       cudata_rvalid_int;   
   reg                        cudata_rvalid_o;   
   wire                       cudata_rvalid_int2;   
   reg [AHB_DWIDTH - 1:0]     cudata_r_o;  
   reg [AHB_DWIDTH - 1:0]     cudata_r_int;  
   
   reg                        do_mem_wr;
   reg                        do_mem_rd;   
   integer                    desc_datasel_cntr;

   wire                       rdcommstatus_valid;   
   wire                       txtokay_c;
   reg                        txtokay;

   wire                       FF_entry_c;
   reg                        FF_entry;
   wire                       FF_entry_bit;

   wire                       FF_exit_c;
   reg                        FF_exit;
   wire                       FF_exit_bit;

   reg                        FF_entry_led;
   reg                        FF_exit_led;
   
   reg [31:0]                 resp_srcreg_addr_d1;
   reg [31:0]                 resp_srcreg_data_d1;
   
   wire                       rcvokay_c;
   wire                       cmdrcv_c;
   reg                        rcvokay;
   reg                        cmdrcv;
   wire                       rcvokay_bit;
   wire                       cmdrcv_bit;
   wire                       txtokay_bit;

   reg                        cuhprior_flushdone_o;
   reg                        cuhprior_flushdone_d1;

   reg                        fcpop_d1;
   reg                        fiicreg_done_d1;
   reg                        commctrlreg_done_d1;
   reg                        commpoll_done;
   reg                        commpoll_done_d1;
   
   reg [2:0]                  wait_count;
   
   reg [31:0]                 cfdst_addr_d1;
   reg [31:0]                 cfsrc_addr_d1;   
   reg                        custatus_valid_o;
   
   reg                        pord_d1;
   reg                        pord_d2;
   reg                        pord;
   reg                        rd_active;
   
   wire                       FF_TO_START;
   wire                       FF_DONE;

   //////////////////////////////////////////////////////////////////////////////  
   //                           Start-of-Code                                  //  
   //////////////////////////////////////////////////////////////////////////////  
         
   // --------------------------------------------------------------------------
   // Determine whether exclusive write or read to eSRAM is required for a
   // particular service.
   // For some services, data needs to be written into eSRAM memory space at the
   // location pointed by the data pointer descriptor handle during request.
   // For some services, data needs to be read from eSRAM memory space from the
   // location pointed by the data pointer descriptor handle during request.
   // do_mem_wr = 1, write to eSRAM is required.
   // do_mem_rd = 1, read to eSRAM is required.
   // --------------------------------------------------------------------------
   always @(*) begin
      do_mem_wr = 1'b0;
      do_mem_rd = 1'b0;
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h00, 8'h01, 8'h05, 8'h04 : begin  // Device and Design Information services
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b1;
           end
           8'h02 : begin                       // F*F services
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b0;
           end
           8'h03, 8'h06, 8'h0A, 8'h0C: begin   // AES128/AES256/SHA256/HMAC services
              do_mem_wr = 1'b1;
              do_mem_rd = 1'b1;
           end
           8'h09, 8'h0E: begin                 // Key Tree/PUF services
              do_mem_wr = 1'b1;
              do_mem_rd = 1'b1;
           end
           8'h28,8'h2C, 8'h2D: begin           // NRBG services
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b0;
           end
           8'h29: begin                        // NRBG Instantiate services
              do_mem_wr = 1'b1;
              do_mem_rd = 1'b1;
           end
           8'h2A: begin                        // NRBG Generate services
              do_mem_wr = 1'b1;
              do_mem_rd = 1'b1;
           end
           8'h2B: begin                        // NRBG Reseed services
              do_mem_wr = 1'b1;
              do_mem_rd = 1'b0;
           end
           8'hF0: begin                        // Zeroization service
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b0;
           end
           8'h14, 8'h17: begin                 // IAP/NVMData Integrity service
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b0;
           end

           default: begin
              do_mem_wr = 1'b0;
              do_mem_rd = 1'b0;
           end

         endcase // case (uclatchcmd_i)        
      end          
   end

   // --------------------------------------------------------------------------
   // burstlen_memwr_desc: Calculate the descriptor burstlength required for 
   // write to eSRAM memory space
   // --------------------------------------------------------------------------
   always @(*) begin
      burstlen_memwr_desc = 16'h0000;
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h03: begin   // AES128 services
              burstlen_memwr_desc = 16'h000B; //# of Word transfers
           end
           8'h06: begin   // AES256 services
              burstlen_memwr_desc = 16'h000F; //# of Word transfers
           end
           8'h0A: begin   // SHA256 services
              burstlen_memwr_desc = 16'h0003; //# of Word transfers
           end
           8'h0C: begin   // HMAC services
              burstlen_memwr_desc = 16'h000B; //# of Word transfers
           end
           8'h09: begin  // Key Tree services
              burstlen_memwr_desc = 32'h000D; //# of Word transfers
           end
           8'h0E: begin  // PUF services
              burstlen_memwr_desc = 32'h0006; //# of Word transfers
           end
           8'h29: begin  // Instantiate services
              burstlen_memwr_desc = 32'h0002; //# of Word transfers
           end
           8'h2A: begin  // Generate services
              burstlen_memwr_desc = 32'h0003; //# of Word transfers
           end
           8'h2B: begin  // Reseed services
              burstlen_memwr_desc = 32'h0002; //# of Word transfers
           end
           default: begin
              burstlen_memwr_desc = 16'h0000;
           end

         endcase // case (uclatchcmd_i)
      end // if (uctrig_i == 1'b1)     
   end


   // --------------------------------------------------------------------------
   // burstlen_memwr_data: Calculate the data burstlength required for write to 
   // eSRAM memory space
   // --------------------------------------------------------------------------
   always @(*) begin
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h03: begin   // AES128 services
              burstlen_memwr_data = uccrypto_nblocks_i*4;
           end
           8'h06: begin   // AES256 services
              burstlen_memwr_data = uccrypto_nblocks_i*4;
           end
           8'h0A: begin   // SHA256 services
    	      if(uccrypto_length_i == 32'h00000000) begin
                 burstlen_memwr_data = 32'h00000001;
	      end
	      else begin
   	         if(uccrypto_length_i[4:0] == 5'b00000) begin
                   burstlen_memwr_data = uccrypto_length_i/32;
                 end
   	         else begin
                   burstlen_memwr_data = (uccrypto_length_i/32) + 32'h00000001;
                 end
              end
           end
           8'h0C: begin   // HMAC services
    	      if(uccrypto_length_i == 32'h00000000) begin
                 burstlen_memwr_data = 32'h00000001;
	      end
	      else begin
   	         if(uccrypto_length_i[1:0] == 2'b00) begin  // TO CHECK FOR LENGTHS NOT MULTIPLES OF 4
                   burstlen_memwr_data = uccrypto_length_i/4;
                 end
   	         else begin
                   burstlen_memwr_data = (uccrypto_length_i/4) + 32'h00000001;
                 end
              end
           end
           8'h29: begin   // Instantiate 
              if(ucnrbg_length_i == 32'h00000000 )begin
                 burstlen_memwr_data = 32'h00000001 ;
              end 
              else begin
   	         if(ucnrbg_length_i[1:0] == 2'b00) begin
                   burstlen_memwr_data = ucnrbg_length_i/4;
                 end
   	         else begin
                   burstlen_memwr_data = (ucnrbg_length_i/4) + 32'h00000001;
                 end
              end
           end
           8'h2A: begin   // Generate
              if(ucnrbg_addlength_i == 32'h00000000 )begin
                 burstlen_memwr_data = 32'h00000001 ;
              end 
              else begin
   	         if(ucnrbg_addlength_i[1:0] == 2'b00) begin
                   burstlen_memwr_data = ucnrbg_addlength_i/4;
                 end
   	         else begin
                   burstlen_memwr_data = (ucnrbg_addlength_i/4) + 32'h00000001;
                 end
              end
           end
           8'h2B: begin   // Reseed
              if(ucnrbg_addlength_i == 32'h00000000 )begin
                 burstlen_memwr_data = 32'h00000001 ;
              end 
              else begin
   	         if(ucnrbg_addlength_i[1:0] == 2'b00) begin
                   burstlen_memwr_data = ucnrbg_addlength_i/4;
                 end
   	         else begin
                   burstlen_memwr_data = (ucnrbg_addlength_i/4) + 32'h00000001;
                 end
              end
             
           end
           8'h20: begin   // SPI
              burstlen_memwr_data = spilength;
           end
           default: begin
              burstlen_memwr_data = 32'h00000000;
           end

         endcase // case (uclatchcmd_i)
      end // if (ucvalid_cmd_i == 1'b1)    
      else begin
         burstlen_memwr_data = 32'h00000000;
      end  
   end

   // --------------------------------------------------------------------------
   // burstlen_memrd_data: Calculate the burstlength required for read from eSRAM 
   // memory space
   // --------------------------------------------------------------------------
   always @(*) begin
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h01 : begin  // SNS services
              burstlen_memrd_data = 16'h0004; // # of word length
           end
           8'h04 : begin  // UCS services
              burstlen_memrd_data = 16'h0001; // # of word length
           end
           8'h00 : begin  // DCS services
              burstlen_memrd_data = 16'h00C0; // # of word length
           end
           8'h05 : begin  // DVS services
              burstlen_memrd_data = 16'h0001; // # of word length
           end
           8'h03: begin   // AES128 services
              burstlen_memrd_data = uccrypto_nblocks_i*4;
           end
           8'h06: begin   // AES256 services
              burstlen_memrd_data = uccrypto_nblocks_i*4;
           end
           8'h0A: begin   // SHA256 services
              burstlen_memrd_data = 8;        // # of word length
           end
           8'h0C: begin   // HMAC services 
              burstlen_memrd_data = 8;        // # of word length
           end
           8'h09: begin   // Key Tree services 
              burstlen_memrd_data = 8;        // # of word length
           end
           8'h0E: begin   // PPUF services 
              burstlen_memrd_data = 8;        // # of word length
           end
           8'h2A: begin   // Generate services 
   	      if(ucnrbg_length_i == 8'h00) begin
                   burstlen_memrd_data = 16'h0001;
	      end
	      else begin
      	        if(ucnrbg_length_i[1:0] == 2'b00) begin
                   burstlen_memrd_data = ucnrbg_length_i/4;
                end
   	        else begin
                   burstlen_memrd_data = (ucnrbg_length_i/4) + 16'h0001;
                end
              end
           end
           8'h29: begin   // Instantiate services 
              burstlen_memrd_data = 16'h0001;        // # of bytes length
           end
           8'h2B: begin   // Reseed services 
              burstlen_memrd_data = 16'h0001;        // # of bytes length
           end
           default: begin
              burstlen_memrd_data = 16'h0000;
           end

         endcase // case (uclatchcmd_i)
      end // if (uctrig_i == 1'b1)
      else begin
         burstlen_memrd_data = burstlen_memrd_data_d1;
      end
   end // always @ (*)

   // --------------------------------------------------------------------------
   // burstlen_memrd_data_d1: Regisetered burstlen_memrd_data
   // --------------------------------------------------------------------------
   always  @(posedge clk or negedge resetn) begin
      if(~resetn) begin
         burstlen_memrd_data_d1 <= 16'h0000;
      end
      else begin
         burstlen_memrd_data_d1 <= burstlen_memrd_data;
      end
   end
   
   // --------------------------------------------------------------------------
   // req_desc_done: Set the signal to perform the write data to memory after  
   // the write descriptor to memory is performed.
   // It allows the transition from REQ_WAIT_MEMWR1/2 state to appropriate next st.
   // Set when current state is REQ_MEMWR_DESC
   // Reset when current state is REQ_MEMWR_DATA
   // --------------------------------------------------------------------------
   always  @(posedge clk or negedge resetn) begin
      if(~resetn) begin
         req_desc_done <= 1'b0;
      end
      else if(req_curr_state == REQ_MEMWR_DATA || req_curr_state == REQ_PHASE) begin
         req_desc_done <= 1'b0;
      end
      else if(req_curr_state == REQ_MEMWR_DESC) begin
         req_desc_done <= 1'b1;
      end
   end

   // --------------------------------------------------------------------------
   // resp_desc_done: Set the signal to perform the read data from comm_blk
   // to read the cmd, descriptor and status
   // Set when current state is RESP_RDCOMM_DESC
   // Reset when current state is RESP_RDCOMM_DATA
   // --------------------------------------------------------------------------
   always  @(posedge clk or negedge resetn) begin
      if(~resetn) begin
         resp_desc_done <= 1'b0;
         resp_data_done <= 1'b0;
         resp_frm_done <= 1'b0;
      end
      else if(resp_curr_state == RESP_IDLE) begin
         resp_desc_done <= 1'b0;
         resp_data_done <= 1'b0;
         resp_frm_done <= 1'b0;
      end
      else if(resp_curr_state == RESP_RDCOMM_DATA) begin
         resp_data_done <= 1'b1;
      end
      else if(resp_curr_state == RESP_RDCOMM_DESC) begin
         resp_desc_done <= 1'b1;
      end
      else if(resp_curr_state == RESP_RDCOMM_FRM) begin
         resp_frm_done <= 1'b1;
      end
   end

   // --------------------------------------------------------------------------
   // cfburst_len_wr_o: Calculate the burstlen for # of writes to be done in the   
   // memory and also for # of writes to be done on the comm_blk.
   // --------------------------------------------------------------------------
   always  @(*) begin
      if(req_curr_state == REQ_WAIT_MEMWR1 && idle_trigger) begin
         cfburst_len_wr_o <= {16'h0000, burstlen_memwr_desc};
      end
      else if(req_curr_state == REQ_WAIT_MEMWR2 && idle_trigger) begin
         cfburst_len_wr_o <= burstlen_memwr_data;
      end
      else if(req_curr_state == REQ_PHASE && idle_trigger) begin
         cfburst_len_wr_o <= 32'h00000001;
      end
      else if(resp_curr_state == RESP_PHASE && idle_trigger) begin 
         cfburst_len_wr_o <= 32'h00000001;
      end
      else if(resp_curr_state == RESP_RDCOMM_DESC && idle_trigger) begin
         cfburst_len_wr_o <= 32'h00000001;
      end
      else if(resp_curr_state == RESP_RDCOMM_FRM && idle_trigger) begin // For interrupt reg mask addition
         cfburst_len_wr_o <= 32'h00000001;
      end
      else begin
         cfburst_len_wr_o <= cfburst_len_wr_d1;
      end
   end // always  @ (posedge clk or negedge resetn)
   
   // --------------------------------------------------------------------------
   // cfburst_len_wr_d1: Delayed cfburst_len_wr_o
   // cfburst_len_rd_d1: Delayed cfburst_len_rd_o
   // --------------------------------------------------------------------------
   always  @(posedge clk or negedge resetn) begin
      if(~resetn) begin
         cfburst_len_wr_d1 <= 32'h00000000;
         cfburst_len_rd_d1 <= 16'h0000;
      end
      else begin
         cfburst_len_wr_d1 <= cfburst_len_wr_o;
         cfburst_len_rd_d1 <= cfburst_len_rd_o;
      end
   end
   
   // --------------------------------------------------------------------------
   // cfburst_len_rd_o: Calculate the burstlen for read to be done from the   
   // memory and also when read to be done from the comm_blk.
   // --------------------------------------------------------------------------
   always  @(*) begin
      if(resp_curr_state == RESP_RDCOMM_DATA && resp_next_state == RESP_WAIT_MEMRD) begin
         cfburst_len_rd_o <= burstlen_memrd_data;
      end
      else if((req_curr_state == REQ_PHASE) || (req_next_state == REQ_MEMWR_DESC) || 
              (resp_curr_state == RESP_COMMRD) || (resp_curr_state == RESP_PHASE) && !resp_data_done) begin 
         cfburst_len_rd_o <= 16'h0001;
      end
      else begin
         cfburst_len_rd_o <= cfburst_len_rd_d1;
      end
   end

   // --------------------------------------------------------------------------
   // datawr_reqd:Determine whether any data write to memory is required or
   // not.
   // --------------------------------------------------------------------------
   always @(*) begin
      datawr_reqd = 1'b0;
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h03, 8'h06, 8'h0A, 8'h0C: begin // AES128/256/SHA/HMAC services
              datawr_reqd = 1'b1;
           end
           8'h29, 8'h2A, 8'h2B: begin     // Instantiate/Generate/Reseed services
              datawr_reqd = 1'b1;
           end
            8'h20: begin     // SPI services
              datawr_reqd = 1'b1;
           end
           default: begin
              datawr_reqd = 1'b0;
           end
  
         endcase // case (uclatchcmd_i)
      end // if (uctrig_i == 1'b1)           
   end

   // --------------------------------------------------------------------------
   // cfdst_addr_int: Generate and pass the appropriate address corresponding to
   // the state in which the state machine is.
   // --------------------------------------------------------------------------
   always @(*) begin
      // Write desc address
      if(req_curr_state == REQ_MEMWR_DESC) begin
         cfdst_addr_o = memwr_desc_addr;
      end
      // Write data address
      else if(req_curr_state == REQ_MEMWR_DATA) begin
         cfdst_addr_o = memwr_data_addr;        
      end
      // write address for COMM_BLK -->
      else if(req_curr_state == REQ_FIIC_INT) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_CTRL) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_INT) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_INT2) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_CTRL2) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(resp_curr_state == RESP_WRCOMM_CTRL1) begin  
         cfdst_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_WRCOMM_CTRL2) begin 
         cfdst_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_WRCOMM_INT2) begin   // For interrupt reg masking addition in resp FSM
         cfdst_addr_o = resp_srcreg_addr;
      end
      else if(req_curr_state == REQ_RDCOMM_STATUS1) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_FRM) begin
         cfdst_addr_o = req_dstreg_addr;
      end 
      else if(req_curr_state == REQ_RDCOMM_STATUS2) begin
         cfdst_addr_o = req_dstreg_addr;
      end
      else if(req_curr_state == REQ_WRCOMM_DATA) begin   
         cfdst_addr_o = req_dstreg_addr;
      end
      else begin
         cfdst_addr_o = cfdst_addr_d1;
      end
   end

   // --------------------------------------------------------------------------
   // cfdst_addr_d1: Registered cfdst_addr_o
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cfdst_addr_d1 <= 32'h00000000;
      end
      else begin
         cfdst_addr_d1 <= cfdst_addr_o;
      end
   end

   // --------------------------------------------------------------------------
   // cfsrc_addr_o: Generate and pass the appropriate address corresponding to
   // the state in which the state machine is.
   // --------------------------------------------------------------------------
   always @(*) begin
      // Read data address
      if(resp_curr_state == RESP_MEMRD) begin
         cfsrc_addr_o = memrd_data_addr;        
      end
      // Read address for COMM_BLK -->
      else if(resp_curr_state == RESP_RDCOMM_STATUS) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_STATUS2) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_STATUS3) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_STATUS4) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_FRM) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_FRM2) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_FRM3) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_DESC) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else if(resp_curr_state == RESP_RDCOMM_DATA) begin
         cfsrc_addr_o = resp_srcreg_addr;
      end
      else begin
         cfsrc_addr_o = cfsrc_addr_d1; 
      end
   end

   // --------------------------------------------------------------------------
   // cfsrc_addr_d1: Registered cfsrc_addr_o
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cfsrc_addr_d1 <= 32'h00000000;
      end
      else begin
         cfsrc_addr_d1 <= cfsrc_addr_o;
      end
   end


   // --------------------------------------------------------------------------
   // memwr_desc_addr: Calculate the address required for write to eSRAM 
   // memory space based on the type of service selected
   // --------------------------------------------------------------------------
   always @(*) begin
      memwr_desc_addr = 32'h00000000;
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h01: begin   // SN services
              memwr_desc_addr = DSNPTR;
           end
           8'h04: begin   // UC services
              memwr_desc_addr = USERCODEPTR;
           end
           8'h00: begin   // DC services
              memwr_desc_addr = DEVICECERTPTR;
           end
           8'h05: begin   // DV services
              memwr_desc_addr = DESIGNVERPTR;
           end
           8'h03: begin   // AES128 services
              memwr_desc_addr = CRYPTOAES128DATAPTR;
           end
           8'h06: begin   // AES256 services
              memwr_desc_addr = CRYPTOAES256DATAPTR;
           end
           8'h0A: begin   // SHA256 services
               memwr_desc_addr = CRYPTOSHA256DATAPTR;
           end
           8'h0C: begin   // HMAC services
              memwr_desc_addr = CRYPTOHMACDATAPTR;
           end
           8'h09: begin  // Key Tree services
              memwr_desc_addr = KEYTREEDATAPTR;
           end
           8'h0E: begin  // PUF services
              memwr_desc_addr = PPUFCHRESPPTR;
           end
           8'h29: begin  // Instantiate services
              memwr_desc_addr = NRBGINSTPTR;
           end
           8'h2A: begin  // Generate services
              memwr_desc_addr = NRBGGENPTR;
           end
           8'h2B: begin  // Reseed services
              memwr_desc_addr = NRBGRESEEDPTR;
           end
           default: begin
              memwr_desc_addr = 32'h00000000;
           end
   
         endcase // case (uclatchcmd_i)
      end // if (uctrig_i == 1'b1)     
   end
   
   // --------------------------------------------------------------------------
   // memwr_data_addr: Calculate the address required for write to eSRAM 
   // memory space based on the type of service selected
   // --------------------------------------------------------------------------
   always @(*) begin
      memwr_data_addr = 32'h00000000;
     if(ucvalid_cmd_i == 1'b1) begin
        case(uclatchcmd_i)
          8'h03, 8'h06: begin  // AES128/AES256 services   
             memwr_data_addr = CRYPTOSRCADPTR;
          end
          8'h0A , 8'h0C: begin  // SHA256/HMAC services  
             memwr_data_addr = CRYPTODATAINPPTR;
          end
          8'h29: begin  // Instantiate services
             memwr_data_addr = NRBGPERSTRINGPTR;
          end
          8'h2A: begin  // Generate services
             memwr_data_addr = NRBGADDINPPTR;
          end
          8'h2B: begin  // Reseed services
             memwr_data_addr = NRBGADDINPPTR;
          end          
          default: begin
             memwr_data_addr = 32'h00000000;
          end

        endcase // case (uclatchcmd_i)
     end // if (uctrig_i == 1'b1)     
   end

   // --------------------------------------------------------------------------
   // memrd_data_addr: Calculate the address required for read from eSRAM 
   // memory space based on the type of service selected
   // --------------------------------------------------------------------------
   always @(*) begin
      memrd_data_addr = 32'h00000000;
     if(ucvalid_cmd_i == 1'b1) begin
        case(uclatchcmd_i)
          8'h03, 8'h06: begin   // AES128/AES256 services  
             memrd_data_addr = CRYPTODSTADPTR;
          end
          8'h0A , 8'h0C: begin   // SHA256/HMAC services  
             memrd_data_addr = CRYPTORSLTPTR;
          end
          8'h01: begin   // Design and Information Services
             memrd_data_addr = DSNPTR;
          end
          8'h04: begin   // Design and Information Services
             memrd_data_addr = USERCODEPTR;
          end
          8'h00: begin   // Design and Information Services
             memrd_data_addr = DEVICECERTPTR;
          end
          8'h05: begin   // Design and Information Services
             memrd_data_addr = DESIGNVERPTR;
          end
          8'h09: begin   // Key Tree
             memrd_data_addr = KEYTREEDATAPTR;
          end
          8'h0E: begin   // PUF
             memrd_data_addr = PPUFCHRESPKEYADDR;
          end
          8'h2A: begin   // Generate NRBG
             memrd_data_addr = NRBGREQDATAPTR;
          end
          8'h29: begin  // Instantiate services
             memrd_data_addr = NRBGINSTPTR+32'h00000004;  // To read Handle
          end
          8'h2B: begin  // Reseed services
             memrd_data_addr = NRBGRESEEDPTR+32'h00000004;  // To read Handle
          end
          default: begin
             memrd_data_addr = 32'h00000000;
          end
        endcase // case (uclatchcmd_i)
     end // if (uctrig_i == 1'b1)     
   end // always @ (*)

   
   // --------------------------------------------------------------------------
   // Registered signals
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         req_phase_done_d1    <= 1'b0;
         resp_phase_done_d1   <= 1'b0;
         resp_phase_active_d1 <= 1'b0;
         resp_data_done_d1    <= 1'b0;         
         req_phase_active_d1  <= 1'b0;         
      end
      else begin
         req_phase_done_d1    <= req_phase_done;
         resp_phase_done_d1   <= resp_phase_done;
         resp_phase_active_d1 <= resp_phase_active;
         resp_data_done_d1    <= resp_data_done;
         req_phase_active_d1  <= req_phase_active;         
      end
   end

   // --------------------------------------------------------------------------
   // resp_phase_active_pulse: Generate response phase active pulse
   // This is used to invoke the response state machine
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         resp_phase_active_pulse <= 1'b0;
      end
      else begin
         resp_phase_active_pulse <= resp_phase_active & !resp_phase_active_d1;
      end
   end

   // --------------------------------------------------------------------------
   // resp_phase_done_pulse: Generate response phase done pulse
   // This is used to exit the main state machine from response phase back to 
   // idle indicating that the service has been serviced.
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         resp_phase_done_pulse <= 1'b0;
      end
      else begin
         resp_phase_done_pulse <= !resp_phase_done & resp_phase_done_d1;
      end
   end

   // --------------------------------------------------------------------------
   // req_phase_active_pulse: Generate request phase active pulse
   // This is used to invoke the request state machine
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         req_phase_active_pulse <= 1'b0;
      end
      else begin
         req_phase_active_pulse <= req_phase_active & !req_phase_active_d1;
      end
   end

   // --------------------------------------------------------------------------
   // pord: PoR Digest check pulse when reset is de-asserted
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         pord <= 1'b0;
      end
      else begin
         if(PORDSERVICE == 1'b1) begin
            pord <= pord_d1 & !pord_d2;
         end
         else begin
            pord <= 1'b0;
         end
      end
   end

   // --------------------------------------------------------------------------
   // Registered signals
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         pord_d1 <= 1'b0;
         pord_d2 <= 1'b0;
      end
      else begin
         pord_d1 <= 1'b1;
         pord_d2 <= pord_d1;
      end
   end

   
   // --------------------------------------------------------------------------
   /////////////////////////////////////////////////////////////////////////////
   //                                                                         //
   //        ||\  /|| ||||| || ||   ||         |||||| |||||| ||\  /||         //
   //        ||\\//|| || || || ||\  ||         ||     ||     ||\\//||         //
   //        || \/ || ||_|| || || \ ||   ==    ||||   |||||| || \/ ||         //
   //        ||    || || || || ||  \||         ||         || ||    ||         //
   //        ||    || || || || ||   \|         ||     |||||| ||    ||         //
   //                                                                         //
   /////////////////////////////////////////////////////////////////////////////
   // --------------------------------------------------------------------------

   // --------------------------------------------------------------------------
   // Main State Machine: Command Decoder 
   // This State Machine combines the two sub-state machines: Reqest FSM and
   // Response FSM
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         main_curr_state <= C_IDLE;
      end
      else begin
         main_curr_state <= main_next_state;
      end
   end
   
   // --------------------------------------------------------------------------
   // Main State Machine: Next state and output decoder
   // --------------------------------------------------------------------------
   always @(*) begin
      main_next_state   = main_curr_state;
      cubusy_o          = 1'b0;
      req_phase_active  = 1'b0;
      resp_phase_active = 1'b0;
      custatus_out_en     = 1'b0;

      case(main_curr_state)
        C_IDLE: begin
           if(pord == 1'b1) begin
              main_next_state = C_RESP_PHASE;              
           end
           else if(uctrig_i == 1'b1) begin
              main_next_state = C_REQ_PHASE;              
           end
        end

        C_REQ_PHASE: begin
           cubusy_o     = 1'b1;
           req_phase_active = 1'b1;

           if(!req_phase_done && req_phase_done_d1 && (uclatchcmd_i != 8'hF0)) begin
              main_next_state = C_RESP_PHASE; 
           end
           else if(!req_phase_done && req_phase_done_d1) begin 
              main_next_state = C_IDLE; 
           end
        end

        C_RESP_PHASE: begin
           cubusy_o      = 1'b1;
           resp_phase_active = 1'b1;

           if(resp_phase_done_pulse == 1'b1) begin
              main_next_state = C_IDLE;
              custatus_out_en = 1'b1;              
           end
        end
        default : main_next_state = C_IDLE;
        
      endcase // case (main_curr_state)      
   end // always @ (*)

   // --------------------------------------------------------------------------
   // cfgrant_o: Generate grant output to the AHB FSM
   // --------------------------------------------------------------------------
   assign cfgrant_o = cfgrant_req | cfgrant_resp;

   // --------------------------------------------------------------------------
   // Registered signals
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         fctrans_done_d1 <= 1'b0;
         fctrans_done_d2 <= 1'b0;
         fcbusreq_d1     <= 1'b0;         
      end
      else begin
         fctrans_done_d1 <= fctrans_done_i;
         fctrans_done_d2 <= fctrans_done_d1;
         fcbusreq_d1     <= fcbusreq_i;
      end
   end

   // --------------------------------------------------------------------------
   // cfwr_req_d: Write request enable to FSM control logic so that AHB write 
   // cycle is driven
   // --------------------------------------------------------------------------
   always @(*) begin
         if(req_curr_state == REQ_PHASE) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_RDCOMM_STATUS2 && txtokay == 1'b1 && 
		 idle_trigger && mchready_i) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_RDCOMM_STATUS1 && txtokay) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_REG2) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_REG11) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_REG1) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_REG10) begin 
            cfwr_req_d <= 1'b1;
         end
         else if(resp_curr_state == RESP_PHASE) begin
            cfwr_req_d <= 1'b1;
         end
         else if(resp_curr_state == RESP_RDCOMM_FRM && idle_trigger) begin
            cfwr_req_d <= 1'b1;
         end
         else if(resp_curr_state == RESP_RDCOMM_DESC && idle_trigger && uclatchcmd_i != 8'h28 && 
                 uclatchcmd_i != 8'h2D && uclatchcmd_i != 8'h17 && uclatchcmd_i != 8'hF1) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_PHASE) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_MEMWR2) begin
            cfwr_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_MEMWR1) begin
            cfwr_req_d <= 1'b1;
         end
         else begin
            cfwr_req_d <= 1'b0;
         end
   end // always @ (*)

   // --------------------------------------------------------------------------
   // cfwr_req_o: Write request enable to FSM control logic so that AHB write 
   // cycle is driven
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cfwr_req_o <= 1'b0;
      end
      else begin
         cfwr_req_o <= cfwr_req_d;
      end
   end
   
   // --------------------------------------------------------------------------
   // cfrd_req_d: Read request enable to FSM control logic so that AHB write 
   // cycle is driven
   // --------------------------------------------------------------------------
   always @(*) begin
         if(req_curr_state == REQ_WAIT_REG3) begin
            cfrd_req_d <= 1'b1;
         end
         else if(req_curr_state == REQ_WAIT_REG5) begin
            cfrd_req_d <= 1'b1;
         end
         else begin
            cfrd_req_d <= 1'b0;
         end
   end // always @ (*)

   // --------------------------------------------------------------------------
   // cfrd_req_o: Read request enable to FSM control logic so that AHB write 
   // cycle is driven
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cfrd_req_o <= 1'b0;
      end
      else begin
         cfrd_req_o <= cfrd_req_d;
      end
   end

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         wait_count <= 3'b000;
      end
      else begin
         if(!mchready_i) begin
            wait_count <= wait_count;
         end           
         else if((req_curr_state == REQ_WAIT_REG6 || req_curr_state == REQ_RDCOMM_STATUS2) && 
                 mchready_i) begin
            wait_count <= wait_count + 1'b1;
         end
         else begin
            wait_count <= 3'b000;
         end
      end
   end

   // --------------------------------------------------------------------------
   /////////////////////////////////////////////////////////////////////////////
   //                                                                         //
   //        |||||  ||||| ||||||         |||||| |||||| ||\  /||               //
   //        || ||  ||    ||  ||         ||     ||     ||\\//||               //
   //        ||_||  ||||  ||  ||   ==    ||||   |||||| || \/ ||               //
   //        || \\  ||    ||  ||         ||         || ||    ||               //
   //        ||  \\ ||||| ||||\\         ||     |||||| ||    ||               //
   //                                                                         //
   /////////////////////////////////////////////////////////////////////////////
   // --------------------------------------------------------------------------    

   // --------------------------------------------------------------------------
   // Request Phase State Machine
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         req_curr_state <= REQ_IDLE;
      end
      else begin
         req_curr_state <= req_next_state;
      end
   end
   
   // --------------------------------------------------------------------------
   // Request Phase: Next state and output decoder
   // --------------------------------------------------------------------------
   always @(*) begin
      req_next_state = req_curr_state;
      cfgrant_req    = 1'b0;
      req_phase_done = 1'b0;
      req_dstreg_addr = 32'h0;
      req_dstreg_data = 32'h0;
      cfcommaccess_active = 1'b0;      
      fiicreg_done     = 1'b0;
      commctrlreg_done = 1'b0;
      commpoll_done    = 1'b0;      

      case(req_curr_state)
        REQ_IDLE: begin
           if(req_phase_active_pulse && do_mem_wr) begin
              req_next_state = REQ_WAIT_MEMWR1;
           end
           else if(req_phase_active_pulse && !do_mem_wr) begin
              req_next_state = REQ_PHASE;         
           end
        end
        REQ_WAIT_MEMWR1: begin
           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_MEMWR_DESC;
           end
        end
        REQ_MEMWR_DESC: begin
           cfgrant_req = 1'b1;

           if(fctrans_done_i == 1'b1) begin
              if(datawr_reqd == 1'b1) begin
                 req_next_state = REQ_WAIT_MEMWR2;
              end
              else begin
                 req_next_state = REQ_PHASE;
              end
           end
        end
        REQ_WAIT_MEMWR2: begin
           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_MEMWR_DATA;
           end
        end
        REQ_MEMWR_DATA: begin
           cfgrant_req = 1'b1;

           if(fctrans_done_i == 1'b1) begin
              req_next_state = REQ_PHASE;
           end
        end
        REQ_PHASE: begin
           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_COMMWR;     
           end
        end
        REQ_COMMWR: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           
           req_next_state = REQ_FIIC_INT;
        end

        REQ_FIIC_INT: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40006000;
           req_dstreg_data = 32'h20000000;
           fiicreg_done    = 1'b1;
           
           if(fctrans_done_i == 1'b1) begin
              req_next_state = REQ_WAIT_REG1;
           end
        end

        REQ_WAIT_REG1: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           fiicreg_done     = fiicreg_done_d1;
           commctrlreg_done = commctrlreg_done_d1;
           commpoll_done    = commpoll_done_d1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_WRCOMM_CTRL;
           end

        end

        REQ_WRCOMM_CTRL: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016000;
           req_dstreg_data = 32'h00000010;
           commctrlreg_done = 1'b1;

           if(fctrans_done_i == 1'b1) begin
              req_next_state = REQ_WAIT_REG2;
           end
        end
        
        REQ_WAIT_REG2: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_WRCOMM_INT;
           end

        end

        // Set interrupt mask for TXTOKAY bit only
        REQ_WRCOMM_INT: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016008;
           req_dstreg_data = 32'h00000001;

           if(fctrans_done_i == 1'b1) begin
              req_next_state = REQ_POLL_CINT1; 
           end
        end

        // Poll for COMM_BLK interrupt
        REQ_POLL_CINT1: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           commpoll_done = 1'b1;
           if(uccommblk_int_i == 1'b1) begin
              req_next_state = REQ_WAIT_REG3;
           end
        end
        
        REQ_WAIT_REG3: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_RDCOMM_STATUS1;
           end

        end

        REQ_RDCOMM_STATUS1: begin
           cfgrant_req = 1'b1;           
           req_dstreg_addr = 32'h40016004;
           cfcommaccess_active = 1'b1;

           if(txtokay == 1'b1 && idle_trigger) begin 
              req_next_state = REQ_WAIT_REG4;
           end
        end
        
        REQ_WAIT_REG4: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_WRCOMM_FRM;
           end
        end

        // Write Command byte
        REQ_WRCOMM_FRM: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016018;
           req_dstreg_data = {24'h000000,uclatchcmd_i};

           if(uclatchcmd_i == 8'hF0) begin
              req_phase_done = 1'b1;
           end

           
           if(idle_trigger == 1'b1) begin  
              if(uclatchcmd_i == 8'h28 || uclatchcmd_i == 8'h2D) begin   
                 req_next_state = REQ_WAIT_REG11;
              end
              else if(uclatchcmd_i == 8'hF0) begin 
                 req_next_state = REQ_IDLE;
              end
              else begin
                 req_next_state = REQ_POLL_CINT2;
              end
           end
        end
        
        // Poll for COMM_BLK interrupt
        REQ_POLL_CINT2: begin
           cfgrant_req = 1'b1;           
           cfcommaccess_active = 1'b1;

           if(uccommblk_int_i == 1'b1) begin
              req_next_state = REQ_WAIT_REG5;
           end
        end
        
        REQ_WAIT_REG5: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_RDCOMM_STATUS2;
           end

        end

        // Check whether TXTOKAY bit is set in the COMM_BLK status 
        // register
        REQ_RDCOMM_STATUS2: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016004;
           if(txtokay == 1'b1 && idle_trigger && mchready_i) begin
              req_next_state = REQ_WAIT_REG6;
           end
        end

        REQ_WAIT_REG6: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_WRCOMM_CTRL2;
           end

        end
        
        REQ_WRCOMM_CTRL2: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016000;
           if(uclatchcmd_i == 8'h2C) begin
              req_dstreg_data = 32'h00000010;
           end
           else begin
              req_dstreg_data = 32'h00000014;
           end
           commctrlreg_done = 1'b1;

           if(fctrans_done_i == 1'b1) begin
              req_next_state = REQ_WAIT_REG10; 
           end
        end
        REQ_WAIT_REG10: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
                req_next_state = REQ_WRCOMM_DATA;
           end

        end

        // Send descriptor pointer
        REQ_WRCOMM_DATA: begin
           cfgrant_req    = 1'b1;
           cfcommaccess_active = 1'b1;
           if(uclatchcmd_i == 8'h2C) begin
             req_dstreg_addr = 32'h40016010;
           end
           else begin
             req_dstreg_addr = 32'h40016014;
           end

           if(uclatchcmd_i == 8'h02 || uclatchcmd_i == 8'h17) begin 
              req_dstreg_data = {{29{1'b0}},uclatchoptions_i};  // Send options
           end
           else if(uclatchcmd_i == 8'h2C) begin   // Send Handle for Uninstatiate service
              req_dstreg_data = {{24{1'b0}},ucnrbg_handle_i};
           end
           else begin
              req_dstreg_data = memwr_desc_addr;  // Send descriptor
           end

           if(fctrans_done_d1 == 1'b1) begin
              req_next_state = REQ_WAIT_REG11 ; 
           end
        end
        
        REQ_WAIT_REG11: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              req_next_state = REQ_WRCOMM_INT2;
           end

        end

        // Set interrupt register to mask 
        // only CMDRCV and RCVOKAY
        REQ_WRCOMM_INT2: begin
           cfgrant_req = 1'b1;
           cfcommaccess_active = 1'b1;
           req_dstreg_addr = 32'h40016008;
           req_dstreg_data = 32'h00000080;  
           req_phase_done = 1'b1; 

           if(fctrans_done_d1 == 1'b1) begin
              req_next_state = REQ_IDLE;
           end
        end

        default: req_next_state = REQ_IDLE;
      endcase // case (req_curr_state)
   end // always @ (*)


   /////////////////////////////////////////////////////////////////////////////
   // Memory write data logic signals                                         //
   /////////////////////////////////////////////////////////////////////////////

   // --------------------------------------------------------------------------
   // cudata_wrdy_o: It is used to request for the write data from the
   // user logic.
   // --------------------------------------------------------------------------
   assign cudata_wrdy_int = fcpop_i & (req_curr_state == REQ_MEMWR_DATA);  

   // --------------------------------------------------------------------------
   // Delayed signals
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         fcpop_d1            <= 1'b0;
         fiicreg_done_d1     <= 1'b0;  
         commctrlreg_done_d1 <= 1'b0;  
         commpoll_done_d1    <= 1'b0;        
         cudata_wrdy_o       <= 1'b0;        
      end
      else begin
         fcpop_d1            <= fcpop_i;
         fiicreg_done_d1     <= fiicreg_done;
         commctrlreg_done_d1 <= commctrlreg_done;
         commpoll_done_d1    <= commpoll_done;
         cudata_wrdy_o       <= cudata_wrdy_int;
      end
   end

   // --------------------------------------------------------------------------
   // desc_datasel_cntr: Used to select descriptor data word-wise for service
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         desc_datasel_cntr  <= 'h0;
      end
      else begin
         if(req_curr_state != REQ_MEMWR_DESC) begin
            desc_datasel_cntr <= 'h0;
         end
         else if(fcpop_d1 == 1'b1 && req_curr_state == REQ_MEMWR_DESC) begin
            desc_datasel_cntr <= desc_datasel_cntr + 1;
         end
      end
   end

   // --------------------------------------------------------------------------
   // memwr_desc: Construct the write descriptor for each service which is to be
   // written to eSRAM memory space
   // --------------------------------------------------------------------------
   always @(*) begin
      if(ucvalid_cmd_i == 1'b1) begin
         case(uclatchcmd_i)
           8'h03: begin   // AES128 services
              memwr_desc = {{128{1'b0}},CRYPTOSRCADPTR,CRYPTODSTADPTR,8'h00,uccrypto_mode_i,uccrypto_nblocks_i,uccrypto_iv_i,uccrypto_key_i[127:0]}; 
           end
           8'h06: begin   // AES256 services
              memwr_desc = {CRYPTOSRCADPTR,CRYPTODSTADPTR,8'h00,uccrypto_mode_i,uccrypto_nblocks_i,uccrypto_iv_i,uccrypto_key_i};
           end
           8'h0A: begin   // SHA256 services
              memwr_desc = {{384{1'b0}},CRYPTODATAINPPTR,CRYPTORSLTPTR,uccrypto_length_i};
           end
           8'h0C: begin   // HMAC services
              memwr_desc = {{128{1'b0}},CRYPTORSLTPTR,CRYPTODATAINPPTR,uccrypto_length_i,uccrypto_key_i};
           end
           8'h09: begin  // Key Tree services
              memwr_desc = {{88{1'b0}},ucdpa_path_i,ucdpa_optype_i,ucdpa_key_i};
           end
           8'h0E: begin  // PUF services
              memwr_desc = {{312{1'b0}},ucdpa_path_i,ucdpa_optype_i,PPUFCHRESPKEYADDR};
           end
           8'h29: begin  // Instantiate services
              memwr_desc = {{424{1'b0}},ucnrbg_handle_i,8'h00,ucnrbg_length_i,NRBGPERSTRINGPTR};
           end
           8'h2A: begin  // Generate services
              memwr_desc = {{384{1'b0}},ucnrbg_handle_i,ucnrbg_prreq_i,ucnrbg_addlength_i,ucnrbg_length_i,NRBGADDINPPTR,NRBGREQDATAPTR};
           end
           8'h2B: begin  // Reseed services
              memwr_desc = {{432{1'b0}},ucnrbg_handle_i,ucnrbg_addlength_i,NRBGADDINPPTR};
           end
           default: begin
              memwr_desc = {480{1'b0}};
           end

         endcase // case (uclatchcmd_i)
      end // if (uctrig_i == 1'b1)
      else begin
         memwr_desc = {480{1'b0}};
      end
   end


   // --------------------------------------------------------------------------
   // memwr_desc_int: This the descriptor data to be written in to external
   // memory every AHB write cycle.
   // --------------------------------------------------------------------------
   always @(*) begin
      case(desc_datasel_cntr)

        'h0: memwr_desc_int = memwr_desc[31:0];
        'h1: memwr_desc_int = memwr_desc[63:32];
        'h2: memwr_desc_int = memwr_desc[95:64];
        'h3: memwr_desc_int = memwr_desc[127:96];
        'h4: memwr_desc_int = memwr_desc[159:128];
        'h5: memwr_desc_int = memwr_desc[191:160];
        'h6: memwr_desc_int = memwr_desc[223:192];
        'h7: memwr_desc_int = memwr_desc[255:224];
        'h8: memwr_desc_int = memwr_desc[287:256];
        'h9: memwr_desc_int = memwr_desc[319:288];
        'hA: memwr_desc_int = memwr_desc[351:320];
        'hB: memwr_desc_int = memwr_desc[383:352];
        'hC: memwr_desc_int = memwr_desc[415:384];
        'hD: memwr_desc_int = memwr_desc[447:416];
        'hE: memwr_desc_int = memwr_desc[479:448];
        default: memwr_desc_int = 32'h00000000;
      endcase
   end

   
   // --------------------------------------------------------------------------
   // cfdatain_o: Write data to FSM Control.block
   // It is the AHB Master write data. It is selected only when write valid.
   // --------------------------------------------------------------------------
   always @(*) begin
      // external memory write data
      if(req_curr_state == REQ_MEMWR_DATA) begin 
         cfdatain_o = ucdata_w_i;
      end
      // external memory write descriptor
      else if(cudata_wrdy_d1 && (req_curr_state == REQ_MEMWR_DESC || 
                                 req_curr_state == REQ_PHASE || 
                                 req_curr_state == REQ_WAIT_MEMWR2)) begin
         cfdatain_o = memwr_desc_int;
      end
      // write to COMM_BLK -->
      else if(fcpop_i && req_curr_state == REQ_FIIC_INT) begin
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_CTRL) begin
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_CTRL2) begin  
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && resp_curr_state == RESP_WRCOMM_CTRL1) begin 
         cfdatain_o = resp_srcreg_data;
      end
      else if(fcpop_i && resp_curr_state == RESP_WRCOMM_CTRL2) begin 
         cfdatain_o = resp_srcreg_data;
      end
      else if(fcpop_i && resp_curr_state == RESP_WRCOMM_INT2) begin 
         cfdatain_o = resp_srcreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_INT) begin
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_INT2) begin
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_FRM) begin
         cfdatain_o = req_dstreg_data;
      end
      else if(fcpop_i && req_curr_state == REQ_WRCOMM_DATA) begin
         cfdatain_o = req_dstreg_data;
      end
      else begin
         cfdatain_o = cfdatain_d1;
      end
      
   end   

   // --------------------------------------------------------------------------
   // cudata_wrdy_d1: Registered cudata_wrdy_o
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cudata_wrdy_d1 <= 1'b0;
         cfdatain_d1    <= 32'h00000000;
      end
      else begin
         cudata_wrdy_d1 <= fcpop_i;
         cfdatain_d1    <= cfdatain_o;
      end
   end
   
   /////////////////////////////////////////////////////////////////////////////
   // Memory read data logic signals                                          //
   /////////////////////////////////////////////////////////////////////////////

   // --------------------------------------------------------------------------
   // cudata_r_o: Send the read data back to the user logic through Cmd Dec
   // --------------------------------------------------------------------------
   always @(*) begin
     cudata_r_int <= fcdataout_i;
   end
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cudata_r_o <= 32'h00000000;
      end
      else begin
         cudata_r_o <= cudata_r_int;
      end
   end
   // --------------------------------------------------------------------------
   // cudata_rvalid_int: intermediate rvalid for read data from memory
   // --------------------------------------------------------------------------
   assign cudata_rvalid_int = (rd_active & rvalid_out_en) | 
                              (resp_data_done_d1 & !resp_data_done & do_mem_rd); 
   
   // --------------------------------------------------------------------------
   // cudata_rvalid_o: Send the read data valid back to the user logic thru' 
   // the Cmd Dec. 
   // This indicates the ravalid for the data read from the eSRAM memory.
   // --------------------------------------------------------------------------
   assign cudata_rvalid_int2 = rvalid_out_en & rd_active;

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cudata_rvalid_o <= 1'b0;
      end
      else begin
         cudata_rvalid_o <= cudata_rvalid_int2;
      end
   end

   // --------------------------------------------------------------------------
   // custatus_valid_o: Send the status valid back to the user logic thru' 
   // the Cmd Dec. 
   // This indicates that the received response data from COMM_BLK is valid.
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         custatus_valid_o <= 1'b0;
      end
      else begin
         if((resp_curr_state == RESP_WAIT_REG12) || 
            (resp_curr_state == RESP_REG7 && 
             (uclatchcmd_i == 8'h17 || uclatchcmd_i == 8'h28 || 
              uclatchcmd_i == 8'h2D || uclatchcmd_i == 8'hF1))) begin
            custatus_valid_o <= 1'b1;
         end
         else begin
            custatus_valid_o <= 1'b0;
         end
      end
   end
   

   // --------------------------------------------------------------------------
   // rdcommstatus_valid: Valid indicator for checking the status register for
   // rcvokay/txtokay/cmdrcv bits.
   // --------------------------------------------------------------------------
   assign rdcommstatus_valid = fcpush_i &  (resp_curr_state == RESP_RDCOMM_STATUS);

   // --------------------------------------------------------------------------
   // cmdrcv: Determine whether 'cmdrcv' bit is set after read from status
   // register. 
   // --------------------------------------------------------------------------
   assign cmdrcv_bit  = fcdataout_i[7];
   assign cmdrcv_c  = mchready_i ? (cmdrcv_bit  == 1'b1) : cmdrcv; 

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         cmdrcv <= 1'b0;
      end
      else begin
         cmdrcv <= cmdrcv_c;
      end
   end

   // --------------------------------------------------------------------------
   // rcvokay: Determine whether 'rcvokay' bit is set after read from status
   // register. 
   // --------------------------------------------------------------------------
   assign rcvokay_bit = fcdataout_i[1];
   assign rcvokay_c = mchready_i ? (rcvokay_bit == 1'b1) : rcvokay; 


   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         rcvokay <= 1'b0;
      end
      else begin
         rcvokay <= rcvokay_c;
      end
   end

   // --------------------------------------------------------------------------
   // txtokay: Determine whether 'txtokay' bit is set after read from status
   // register. 
   // --------------------------------------------------------------------------
   assign txtokay_bit = fcdataout_i[0];
   assign txtokay_c = mchready_i ? (txtokay_bit == 1'b1) : txtokay;

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         txtokay <= 1'b0;
         resp_srcreg_addr_d1 <= 32'h00000000;         
         resp_srcreg_data_d1 <= 32'h00000000;         
      end
      else begin
         txtokay <= txtokay_c;
         resp_srcreg_addr_d1 <= resp_srcreg_addr;
         resp_srcreg_data_d1 <= resp_srcreg_data;
      end
   end

   //--------------------------------------------------------------------
   // FLASH_FREEZE: Component instance
   //--------------------------------------------------------------------
   FLASH_FREEZE FLASH_FREEZE_0(
        // Outputs
        .FF_TO_START ( FF_TO_START ),
        .FF_DONE     ( FF_DONE ) 
        );

   // --------------------------------------------------------------------------
   // FF_entry: Determine whether "E0" is set after read from FRM8 register
   // --------------------------------------------------------------------------
   assign FF_entry_bit = (fcdataout_i[7:0] == 8'hE0);
   assign FF_entry_c   = mchready_i ? (FF_entry_bit == 1'b1) : FF_entry;  

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         FF_entry <= 1'b0;
      end
      else begin
         FF_entry <= FF_entry_c;
      end
   end

   // Only for validation purpose
   always @(posedge clk or negedge resetn) begin  
      if(resetn == 1'b0) begin
         FF_entry_led <= 1'b0;
      end
      else begin
         //if(FF_entry == 1'b1) begin
         if(FF_TO_START == 1'b1) begin
           FF_entry_led <= 1'b1;
         end	
      end
   end
   
   // Only for validation purpose
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         FF_exit_led <= 1'b1;
      end
      else begin  
         //if(FF_exit == 1'b1) begin
         if(FF_DONE == 1'b1) begin
           FF_exit_led <= 1'b0;
         end	
      end
   end  

   // --------------------------------------------------------------------------
   // FF_exit: Determine whether "E1" is set after read from FRM8 register
   // --------------------------------------------------------------------------
   assign FF_exit_bit = (fcdataout_i[7:0] == 8'hE1);
   assign FF_exit_c   = mchready_i ? (FF_exit_bit == 1'b1) : FF_exit;

   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         FF_exit <= 1'b0;
      end
      else begin
         FF_exit <= FF_exit_c;
      end
   end


   // --------------------------------------------------------------------------
   /////////////////////////////////////////////////////////////////////////////
   //                                                                         //
   //        |||||  ||||| |||||| ||||||         |||||| |||||| ||\  /||        //
   //        || ||  ||    ||     ||  ||         ||     ||     ||\\//||        //
   //        ||_||  ||||  |||||| ||||||   ==    ||||   |||||| || \/ ||        //
   //        || \\  ||        || ||             ||         || ||    ||        //
   //        ||  \\ ||||| |||||| ||             ||     |||||| ||    ||        //
   //                                                                         //
   /////////////////////////////////////////////////////////////////////////////
   // --------------------------------------------------------------------------

   // --------------------------------------------------------------------------
   // Response Phase State Machine
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         resp_curr_state <= RESP_IDLE;
      end
      else begin
         resp_curr_state <= resp_next_state;
      end
   end

   // --------------------------------------------------------------------------
   // Response Phase: Next state and output decoder
   // --------------------------------------------------------------------------
   always @(*) begin
      resp_next_state          = resp_curr_state;
      cfgrant_resp             = 1'b0;
      cfrd_resp_o              = 1'b0;
      resp_srcreg_addr         = resp_srcreg_addr_d1;
      resp_srcreg_data         = resp_srcreg_data_d1;
      resp_phase_done          = 1'b0;
      cfcommaccess_resp_active = 1'b0;
      rd_active                = 1'b0;
      
      case(resp_curr_state)
   
        RESP_IDLE: begin
           if(resp_phase_active_pulse == 1'b1) begin
              resp_next_state = RESP_PHASE;     
           end
        end

        RESP_PHASE: begin
           cfcommaccess_resp_active = 1'b1;
           resp_next_state = RESP_WAIT_REG11;  
        end

        RESP_WAIT_REG11: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_WRCOMM_CTRL1;
           end

        end
        RESP_WRCOMM_CTRL1: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016000;
           resp_srcreg_data = 32'h00000010;

           if(fctrans_done_i == 1'b1) begin
              resp_next_state = RESP_POLL_CINT1; 
           end
        end

        RESP_COMMRD: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           resp_next_state = RESP_POLL_CINT1;
        end

        RESP_POLL_CINT1: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uccommblk_int_i == 1'b1) begin
              resp_next_state = RESP_REG1;

              cfrd_resp_o    = 1'b1;
           end
        end

        RESP_REG1: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_STATUS;
           end
        end
        
        RESP_RDCOMM_STATUS: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016004;

           if(idle_trigger) begin
              if(cmdrcv && idle_trigger) begin
                 resp_next_state = RESP_REG2;
                 cfrd_resp_o    = 1'b1;
              end
              else begin
                 resp_next_state = RESP_POLL_CINT1;
                 cfrd_resp_o    = 1'b0;
              end
           end
        end

        RESP_REG2: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_FRM;
           end
        end

        // Read command in response phase
        RESP_RDCOMM_FRM: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016018;

           if(fctrans_done_i == 1'b1) begin
              resp_next_state = RESP_REG12;
           end
         end

        RESP_REG12: begin
           cfgrant_resp = 1'b1;
           cfcommaccess_resp_active = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_WRCOMM_INT2;
           end

        end

        // Set interrupt register to mask 
        // only CMDRCV and RCVOKAY
        RESP_WRCOMM_INT2: begin
           cfgrant_resp = 1'b1;
           cfcommaccess_resp_active = 1'b1;
           resp_srcreg_addr = 32'h40016008;
	   if(uclatchcmd_i == 8'h02) begin
             resp_srcreg_data  = 32'h00000082;   // To set mask only on cmdrcv+rcvokay for F*F
           end 
	   else begin
             resp_srcreg_data  = 32'h00000002;   // To set mask only on rcvokay
           end

           if(fctrans_done_i == 1'b1) begin
              resp_next_state = RESP_POLL_CINT3;
           end
        end

        // Poll for COMM_BLK interrupt
        RESP_POLL_CINT3: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uccommblk_int_i == 1'b1 && idle_trigger) begin
              resp_next_state = RESP_REG3;

              cfrd_resp_o    = 1'b1;
           end
        end

        RESP_REG3: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_STATUS2;
           end
        end

        RESP_RDCOMM_STATUS2: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016004;

           if(idle_trigger) begin
              if(rcvokay && idle_trigger) begin
                 resp_next_state = RESP_REG4;
                 cfrd_resp_o    = 1'b1;
              end
              else begin
                 resp_next_state = RESP_POLL_CINT3;
              end	      
           end
        end

        RESP_REG4: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_DESC;
           end
           
        end

        // Read the status response
        RESP_RDCOMM_DESC: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016010;

           if(uclatchcmd_i != 8'h17 && uclatchcmd_i != 8'h28 && 
              uclatchcmd_i != 8'h2D && uclatchcmd_i != 8'hF1) begin
              if(fctrans_done_i == 1'b1) begin
                 resp_next_state = RESP_WAIT_REG12; 
              end
           end
           else begin
              if(idle_trigger) begin 
                 resp_next_state = RESP_REG7;
              end  
           end
        end

        RESP_WAIT_REG12: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uclatchcmd_i == 8'h02) begin 
              if(fcbusreq_d1 == 1'b1) begin
                 resp_next_state = RESP_POLL_CINT4;
              end
           end
           else begin
              if(fcbusreq_d1 == 1'b1) begin
                 resp_next_state = RESP_WRCOMM_CTRL2;
              end
           end
        end

        RESP_WRCOMM_CTRL2: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016000;
           if(uclatchcmd_i == 8'h2C) begin
             resp_srcreg_data = 32'h00000010;
           end
           else begin
             resp_srcreg_data = 32'h00000018;
           end

           if(fctrans_done_i == 1'b1) begin
              resp_next_state = RESP_POLL_CINT4; 
           end
        end

        RESP_REG7: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           if(mchready_i == 1'b1) begin
              resp_next_state = RESP_REG8;
           end
        end

        RESP_REG8: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1; 

           resp_next_state = RESP_REG9;
        end

        RESP_REG9: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1; 

           resp_phase_done = 1'b1;
           resp_next_state = RESP_IDLE;
        end

        RESP_POLL_CINT4: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uccommblk_int_i == 1'b1 && idle_trigger) begin
              resp_next_state = RESP_REG5;

              cfrd_resp_o    = 1'b1;
           end
        end

        RESP_REG5: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_STATUS3;  
           end
        end

        RESP_RDCOMM_STATUS3: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016004;

           if(uclatchcmd_i == 8'h02) begin
              if(idle_trigger) begin           
                 if(cmdrcv && rcvokay && idle_trigger) begin 
                    resp_next_state = RESP_REG6;
                    cfrd_resp_o    = 1'b1;
                 end
                 else begin
                    resp_next_state = RESP_POLL_CINT4;
                 end	      
              end
           end
           else begin
              if(idle_trigger) begin           
                 if(rcvokay && idle_trigger) begin 
                    resp_next_state = RESP_REG6;
                    cfrd_resp_o    = 1'b1;
                 end
                 else begin
                    resp_next_state = RESP_POLL_CINT4;
                 end	      
              end
           end
        end

        RESP_REG6: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uclatchcmd_i == 8'h02) begin
              if(fcbusreq_d1 == 1'b1) begin
                 resp_next_state = RESP_RDCOMM_FRM2;
              end
           end
           else begin
              if(fcbusreq_d1 == 1'b1) begin
                 resp_next_state = RESP_RDCOMM_DATA;
              end
           end
              
        end

        // Read descriptor pointer
        RESP_RDCOMM_DATA: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           if(uclatchcmd_i == 8'h2C) begin
             resp_srcreg_addr = 32'h40016010;
           end
           else begin
             resp_srcreg_addr = 32'h40016014;
           end

           if(idle_trigger) begin
              if(do_mem_rd) begin
                 resp_next_state = RESP_WAIT_MEMRD;
                 
                 cfrd_resp_o   = 1'b1;
              end
              else begin
                 resp_phase_done = 1'b1;
                 resp_next_state = RESP_IDLE;
              end
           end
        end

        // Read E0h in case of F*F
        RESP_RDCOMM_FRM2: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016018;

           if(fctrans_done_i == 1'b1) begin
              resp_next_state = RESP_POLL_CINT5;
           end
        end

        RESP_POLL_CINT5: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uccommblk_int_i == 1'b1 && idle_trigger) begin
              resp_next_state = RESP_REG10;

              cfrd_resp_o    = 1'b1;
           end
        end

        RESP_REG10: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_RDCOMM_STATUS4;  
           end
        end

        RESP_RDCOMM_STATUS4: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016004;

           if(uclatchcmd_i == 8'h02) begin
              if(idle_trigger) begin           
                 if(cmdrcv && rcvokay && idle_trigger) begin 
                    resp_next_state = RESP_REG11;
                    cfrd_resp_o    = 1'b1;
                 end
                 else begin
                    resp_next_state = RESP_POLL_CINT5;
                 end	      
              end
           end
        end

        RESP_REG11: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(uclatchcmd_i == 8'h02) begin
              if(fcbusreq_d1 == 1'b1) begin
                 resp_next_state = RESP_RDCOMM_FRM3;
              end
           end
        end

        // Read E1h in case of F*F
        RESP_RDCOMM_FRM3: begin
           cfcommaccess_resp_active = 1'b1;
           cfgrant_resp = 1'b1;
           resp_srcreg_addr = 32'h40016018;

           if(fctrans_done_i == 1'b1) begin
              resp_phase_done = 1'b1;
              resp_next_state = RESP_IDLE;
           end
        end

        RESP_WAIT_MEMRD: begin
           rd_active = 1'b1;
           cfgrant_resp = 1'b1;

           if(fcbusreq_d1 == 1'b1) begin
              resp_next_state = RESP_MEMRD; 

           end
        end

        RESP_MEMRD: begin
           rd_active = 1'b1;
           cfgrant_resp    = 1'b1;
           resp_phase_done = 1'b1;
           
           if(fctrans_done_i) begin
              resp_next_state = RESP_IDLE; 
           end
        end

        default: resp_next_state = RESP_IDLE;
        
      endcase // case (resp_curr_state)      
   end // always @ (*)
   
   // --------------------------------------------------------------------------
   // High Priority Service: FSM
   // --------------------------------------------------------------------------
   always @(posedge clk or negedge resetn) begin
      if(resetn == 1'b0) begin
         hprior_curr_state <= HPRIOR_POLL_WAIT;
      end
      else begin
         hprior_curr_state <= hprior_next_state;
      end
   end

   // --------------------------------------------------------------------------
   // High Priority Service: Next state and output decoder
   // --------------------------------------------------------------------------
   always @(*) begin
      cuhprior_flushdone_o  = 1'b0;
      hprior_next_state = hprior_curr_state;
      case(hprior_curr_state)
   
        HPRIOR_POLL_WAIT: begin
           if(uchprior_flushreq_i == 1'b1) begin
              hprior_next_state = HPRIOR_POLL_CINT;
           end
        end
        HPRIOR_POLL_CINT: begin
           if(uccommblk_int_i == 1'b1) begin
              hprior_next_state = HPRIOR_RDCOMM_STATUS;
           end
        end
        HPRIOR_RDCOMM_STATUS: begin
           if(fctrans_done_i == 1'b1 && txtokay == 1'b1) begin
              hprior_next_state = HPRIOR_WRCOMM_CTRL;
           end
        end
        HPRIOR_WRCOMM_CTRL: begin

           if(fctrans_done_i == 1'b1) begin
              hprior_next_state = HPRIOR_WAIT;

              cuhprior_flushdone_o  = 1'b1;
           end
        end
        HPRIOR_WAIT: begin
           if(fctrans_done_i == 1'b1 && req_phase_active == 1'b1) begin
              hprior_next_state = REQ_IDLE;
           end
           else if(fctrans_done_i == 1'b1 && resp_phase_active == 1'b1) begin
              hprior_next_state = RESP_IDLE;
           end
        end
      endcase // case (hprior_curr_state)
   end // always @ (*)
   
   

endmodule // CmdDec

