
/*******************************************************************************
    Verilog netlist generated by IPGEN Lattice Propel (64-bit) 0.0.11.31.0
    Soft IP Version: 1.0.0
    Thu Jun 11 13:44:55 2020
*******************************************************************************/
/*******************************************************************************
    Wrapper Module generated per user settings.
*******************************************************************************/
module ahbl2apb0 (clk_i, 
        rst_n_i, 
        ahbl_hsel_i, 
        ahbl_hready_i, 
        ahbl_haddr_i, 
        ahbl_hburst_i, 
        ahbl_hsize_i, 
        ahbl_hmastlock_i, 
        ahbl_hprot_i, 
        ahbl_htrans_i, 
        ahbl_hwdata_i, 
        ahbl_hwrite_i, 
        ahbl_hreadyout_o, 
        ahbl_hresp_o, 
        ahbl_hrdata_o, 
        apb_pready_i, 
        apb_pslverr_i, 
        apb_prdata_i, 
        apb_psel_o, 
        apb_paddr_o, 
        apb_pwrite_o, 
        apb_pwdata_o, 
        apb_penable_o) ;
    input clk_i ; 
    input rst_n_i ; 
    input ahbl_hsel_i ; 
    input ahbl_hready_i ; 
    input [31:0] ahbl_haddr_i ; 
    input [2:0] ahbl_hburst_i ; 
    input [2:0] ahbl_hsize_i ; 
    input ahbl_hmastlock_i ; 
    input [3:0] ahbl_hprot_i ; 
    input [1:0] ahbl_htrans_i ; 
    input [31:0] ahbl_hwdata_i ; 
    input ahbl_hwrite_i ; 
    output ahbl_hreadyout_o ; 
    output ahbl_hresp_o ; 
    output [31:0] ahbl_hrdata_o ; 
    input apb_pready_i ; 
    input apb_pslverr_i ; 
    input [31:0] apb_prdata_i ; 
    output apb_psel_o ; 
    output [31:0] apb_paddr_o ; 
    output apb_pwrite_o ; 
    output [31:0] apb_pwdata_o ; 
    output apb_penable_o ; 
    parameter ADDR_WIDTH = 32 ; 
    ahbl2apb0_ipgen_lscc_ahbl2apb #(.ADDR_WIDTH(ADDR_WIDTH),
            .DATA_WIDTH(32),
            .APB_CLK_EN(0),
            .FAMILY("je5d00")) lscc_ahbl2apb_inst (.clk_i(clk_i), 
                .rst_n_i(rst_n_i), 
                .pclk_i(1'b0), 
                .presetn_i(1'b1), 
                .ahbl_hsel_i(ahbl_hsel_i), 
                .ahbl_hready_i(ahbl_hready_i), 
                .ahbl_haddr_i(ahbl_haddr_i[31:0]), 
                .ahbl_hburst_i(ahbl_hburst_i[2:0]), 
                .ahbl_hsize_i(ahbl_hsize_i[2:0]), 
                .ahbl_hmastlock_i(ahbl_hmastlock_i), 
                .ahbl_hprot_i(ahbl_hprot_i[3:0]), 
                .ahbl_htrans_i(ahbl_htrans_i[1:0]), 
                .ahbl_hwdata_i(ahbl_hwdata_i[31:0]), 
                .ahbl_hwrite_i(ahbl_hwrite_i), 
                .ahbl_hreadyout_o(ahbl_hreadyout_o), 
                .ahbl_hresp_o(ahbl_hresp_o), 
                .ahbl_hrdata_o(ahbl_hrdata_o[31:0]), 
                .apb_pready_i(apb_pready_i), 
                .apb_pslverr_i(apb_pslverr_i), 
                .apb_prdata_i(apb_prdata_i[31:0]), 
                .apb_psel_o(apb_psel_o), 
                .apb_paddr_o(apb_paddr_o[31:0]), 
                .apb_pwrite_o(apb_pwrite_o), 
                .apb_pwdata_o(apb_pwdata_o[31:0]), 
                .apb_penable_o(apb_penable_o)) ; 
endmodule



`timescale 1ns/1ps
/* >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
     ------------------------------------------------------------------
     Copyright (c) 2022 by Lattice Semiconductor Corporation
     ALL RIGHTS RESERVED
     ------------------------------------------------------------------

       IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPEL™ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK.

       Lattice grants permission to use this code pursuant to the
       terms of the Lattice Propel License Agreement.

     DISCLAIMER:

       LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE'S REQUIREMENTS, OR THAT LICENSEE'S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED.  LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM.  LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.  IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE'S SOLE LIABILITY, AND LICENSEE'S SOLE REMEDY, IS SET FORTH ABOVE.  LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER'S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS.

     ------------------------------------------------------------------
 */
//
// =============================================================================
//                         FILE DETAILS
// Project               :
// File                  : lscc_ahbl2apb.v
// Title                 :
// Dependencies          : 1.
//                       : 2.
// Description           :
// =============================================================================
//                        REVISION HISTORY
// Version               : 1.0.0
// Author(s)             :
// Mod. Date             :
// Changes Made          : Initial release.
// =============================================================================
module ahbl2apb0_ipgen_lscc_ahbl2apb #(parameter DATA_WIDTH = 32, 
        parameter ADDR_WIDTH = 32, 
        parameter APB_CLK_EN = 0, 
        parameter FAMILY = "LIFCL") (
    // -----------------------------------------------------------------------------
    // Module Parameters
    // -----------------------------------------------------------------------------
    // 8/16/32/64/128/256/512/1024
    // 11-32
    // ------------------------------------------------------------------------------
    // Input/Output Ports
    // ------------------------------------------------------------------------------
    input clk_i, 
    input rst_n_i, 
    input pclk_i, 
    input presetn_i, 
    // ------------------------
    // AHB-Lite Interface
    // ------sim:/soc_top/dut/ahbl2apb1_inst/lscc_ahbl2apb_inst/ahbl_hready_i------------------
    input ahbl_hsel_i, 
    input ahbl_hready_i, 
    input [(ADDR_WIDTH - 1):0] ahbl_haddr_i, 
    input [2:0] ahbl_hburst_i,  // n/a - fixed size
    input [2:0] ahbl_hsize_i,  // n/a - fixed size
    input ahbl_hmastlock_i,  // n/a
    input [3:0] ahbl_hprot_i,  // n/a
    input [1:0] ahbl_htrans_i, 
    input ahbl_hwrite_i, 
    input [(DATA_WIDTH - 1):0] ahbl_hwdata_i, 
    output reg ahbl_hreadyout_o, 
    output reg ahbl_hresp_o, 
    output reg [(DATA_WIDTH - 1):0] ahbl_hrdata_o, 
    // -----------------------------------------
    // APB Interface
    // -----------------------------------------
    output apb_psel_o, 
    output [(ADDR_WIDTH - 1):0] apb_paddr_o, 
    output [(DATA_WIDTH - 1):0] apb_pwdata_o, 
    output apb_pwrite_o, 
    output apb_penable_o, 
    input apb_pready_i, 
    input apb_pslverr_i, 
    input [(DATA_WIDTH - 1):0] apb_prdata_i) ;
    // ------------------------------------------------------------------------------
    // Local Parameters
    // ------------------------------------------------------------------------------
    localparam ST_W = 9 ; 
    localparam ST_IDLE = 9'h01, 
        ST_READ = 9'h02, 
        ST_WWAIT = 9'h04, 
        ST_WRITE = 9'h08, 
        ST_WRITEP = 9'h10, 
        ST_RENABLE = 9'h20, 
        ST_WENABLE = 9'h40, 
        ST_WENABLEP = 9'h80, 
        ST_ERROR = 9'h100 ; 
    localparam IDLE = 2'b00 ; 
    localparam BUSY = 2'b01 ; 
    localparam NSEQ = 2'b10 ; 
    localparam SEQ = 2'b11 ; 
    localparam ST_APB_W = 3 ; 
    localparam ST_APB_IDLE = 3'h1 ; 
    localparam ST_APB_SETUP = 3'h2 ; 
    localparam ST_APB_ACCESS = 3'h4 ; 
    // ------------------------------------------------------------------------------
    // Register Declarations
    // ------------------------------------------------------------------------------
    reg [(ST_W - 1):0] cs_ahbl_sm ; 
    reg [(ST_W - 1):0] ns_ahbl_sm ; 
    reg [(ADDR_WIDTH - 1):0] haddr_r ; 
    reg hwrite_r ; 
    reg [1:0] buff_valid_r ; 
    reg apb_psel_r /* synthesis syn_preserve=1 */; 
    reg [(ADDR_WIDTH - 1):0] apb_paddr_r ; 
    reg [(DATA_WIDTH - 1):0] apb_pwdata_r ; 
    reg apb_pwrite_r ; 
    reg apb_penable_r ; 
    wire ahbl_req_w ; 
    wire ahbl_ready_w ; 
    wire ahbl_req_rdy_w ; 
    wire apb_pready_w ; 
    wire apb_pslverr_w ; 
    wire [(DATA_WIDTH - 1):0] apb_prdata_w ; 
    assign ahbl_req_w = (ahbl_hsel_i && ((ahbl_htrans_i == NSEQ) || (ahbl_htrans_i == SEQ))) ; 
    assign ahbl_ready_w = (ahbl_hreadyout_o && ahbl_hready_i) ; 
    assign ahbl_req_rdy_w = (ahbl_ready_w && ahbl_req_w) ; 
    // -----------------------
    // AHB-Lite State Machine
    // -----------------------
    always
        @(*)
        begin
            ns_ahbl_sm = cs_ahbl_sm ;
            case (cs_ahbl_sm)
            ST_IDLE : 
                begin
                    if (ahbl_req_rdy_w) 
                        ns_ahbl_sm = (ahbl_hwrite_i ? ST_WWAIT : ST_READ) ;
                    else
                        ns_ahbl_sm = ST_IDLE ;
                end
            ST_WWAIT : 
                begin
                    // data is available in next cyle after address phase
                    ns_ahbl_sm = (ahbl_req_rdy_w ? ST_WRITEP : ST_WRITE) ;
                end
            ST_WRITE : 
                begin
                    ns_ahbl_sm = (ahbl_req_rdy_w ? ST_WENABLEP : ST_WENABLE) ;
                end
            ST_WRITEP : 
                begin
                    ns_ahbl_sm = ST_WENABLEP ;
                end
            ST_WENABLEP : 
                begin
                    if (apb_pslverr_w) 
                        ns_ahbl_sm = ST_ERROR ;
                    else
                        if ((ahbl_hreadyout_o && hwrite_r)) 
                            ns_ahbl_sm = (ahbl_req_rdy_w ? ST_WRITEP : ST_WRITE) ;
                        else
                            if ((apb_pready_w && (~hwrite_r))) 
                                ns_ahbl_sm = ST_READ ;
                            else
                                ns_ahbl_sm = ST_WENABLEP ;
                end
            ST_WENABLE : 
                begin
                    if (apb_pslverr_w) 
                        ns_ahbl_sm = ST_ERROR ;
                    else
                        if (apb_pready_w) 
                            if (ahbl_req_rdy_w) 
                                ns_ahbl_sm = (ahbl_hwrite_i ? ST_WWAIT : ST_READ) ;
                            else
                                if (buff_valid_r[1]) 
                                    ns_ahbl_sm = (hwrite_r ? ST_WWAIT : ST_READ) ;
                                else
                                    ns_ahbl_sm = ST_IDLE ;
                        else
                            if ((buff_valid_r[1] || ahbl_req_rdy_w)) 
                                ns_ahbl_sm = ST_WENABLEP ;
                            else
                                ns_ahbl_sm = ST_WENABLE ;
                end
            ST_READ : 
                begin
                    ns_ahbl_sm = ST_RENABLE ;
                end
            ST_RENABLE : 
                begin
                    if (apb_pslverr_w) 
                        ns_ahbl_sm = ST_ERROR ;
                    else
                        if (apb_pready_w) 
                            if (ahbl_req_rdy_w) 
                                ns_ahbl_sm = (ahbl_hwrite_i ? ST_WWAIT : ST_READ) ;
                            else
                                ns_ahbl_sm = ST_IDLE ;
                        else
                            ns_ahbl_sm = ST_RENABLE ;
                end
            ST_ERROR : 
                begin
                    ns_ahbl_sm = ST_IDLE ;
                end
            default : 
                begin
                    ns_ahbl_sm = ST_IDLE ;
                end
            endcase 
        end
    // State register and state outputs
    always
        @(posedge clk_i or 
            negedge rst_n_i)
        begin
            if ((~rst_n_i)) 
                begin
                    cs_ahbl_sm <=  ST_IDLE ;
                    ahbl_hreadyout_o <=  1'b1 ;
                    ahbl_hresp_o <=  1'b0 ;
                    ahbl_hrdata_o <=  {DATA_WIDTH{1'b0}} ;
                    apb_psel_r <=  1'b0 ;
                    apb_penable_r <=  1'b0 ;
                    apb_pwrite_r <=  1'b0 ;
                    apb_paddr_r <=  {ADDR_WIDTH{1'b0}} ;
                    apb_pwdata_r <=  {DATA_WIDTH{1'b0}} ;
                end
            else
                begin
                    cs_ahbl_sm <=  ns_ahbl_sm ;
                    ahbl_hresp_o <=  1'b0 ;//apb_pslverr_w; 
                    apb_psel_r <=  1'b0 ;
                    apb_penable_r <=  1'b0 ;
                    case (ns_ahbl_sm)
                    ST_IDLE : 
                        begin
                            ahbl_hreadyout_o <=  1'b1 ;
                        end
                    ST_WWAIT : 
                        begin
                            ahbl_hreadyout_o <=  1'b1 ;
                        end
                    ST_WRITE : 
                        begin
                            apb_psel_r <=  1'b1 ;
                            apb_pwrite_r <=  1'b1 ;
                            apb_paddr_r <=  haddr_r ;
                            apb_pwdata_r <=  ahbl_hwdata_i ;
                            ahbl_hreadyout_o <=  1'b1 ;
                        end
                    ST_WRITEP : 
                        begin
                            apb_psel_r <=  1'b1 ;
                            apb_pwrite_r <=  1'b1 ;
                            apb_paddr_r <=  haddr_r ;
                            apb_pwdata_r <=  ahbl_hwdata_i ;
                            ahbl_hreadyout_o <=  1'b0 ;
                        end
                    ST_WENABLEP : 
                        begin
                            if (((cs_ahbl_sm == ST_WENABLEP) && apb_pready_w)) 
                                begin
                                    apb_penable_r <=  1'b0 ;// PSEL and PENABLE should negate in next cycle after apb_pready_w=1      
                                    apb_psel_r <=  1'b0 ;
                                end
                            else
                                begin
                                    apb_penable_r <=  1'b1 ;
                                    apb_psel_r <=  1'b1 ;
                                end
                            if (((ahbl_req_rdy_w && (~ahbl_hwrite_i)) || (buff_valid_r[1] && (~hwrite_r)))) 
                                // if next Tx is Read, negate HREADY
                                ahbl_hreadyout_o <=  1'b0 ;
                            else
                                ahbl_hreadyout_o <=  ((~apb_pslverr_w) && apb_pready_w) ;
                            ahbl_hresp_o <=  apb_pslverr_w ;
                        end
                    ST_WENABLE : 
                        begin
                            apb_psel_r <=  1'b1 ;
                            apb_penable_r <=  1'b1 ;
                            ahbl_hreadyout_o <=  (((~apb_pslverr_w) && (~ahbl_req_w)) && (~buff_valid_r[1])) ;// Ready when no next transfer
                            ahbl_hresp_o <=  apb_pslverr_w ;
                        end
                    ST_READ : 
                        begin
                            if ((cs_ahbl_sm == ST_WENABLEP)) 
                                apb_paddr_r <=  haddr_r ;
                            else
                                apb_paddr_r <=  (buff_valid_r[1] ? haddr_r : ahbl_haddr_i) ;
                            apb_psel_r <=  1'b1 ;
                            apb_pwrite_r <=  1'b0 ;
                            if ((cs_ahbl_sm == ST_RENABLE)) 
                                // Data is available in the PRDATA
                                ahbl_hreadyout_o <=  1'b1 ;
                            else
                                ahbl_hreadyout_o <=  1'b0 ;
                        end
                    ST_RENABLE : 
                        begin
                            apb_psel_r <=  1'b1 ;
                            apb_penable_r <=  1'b1 ;
                            if ((apb_pslverr_w || (cs_ahbl_sm != ST_RENABLE))) 
                                // HREADY should be negated on 1st cycle of ST_RENABLE
                                ahbl_hreadyout_o <=  1'b0 ;
                            else
                                ahbl_hreadyout_o <=  apb_pready_w ;
                            ahbl_hresp_o <=  apb_pslverr_w ;
                        end
                    ST_ERROR : 
                        begin
                            apb_psel_r <=  1'b0 ;
                            apb_penable_r <=  1'b0 ;
                            apb_pwrite_r <=  1'b0 ;
                            apb_paddr_r <=  {ADDR_WIDTH{1'b0}} ;
                            apb_pwdata_r <=  {DATA_WIDTH{1'b0}} ;
                            ahbl_hrdata_o <=  {DATA_WIDTH{1'b0}} ;
                            ahbl_hreadyout_o <=  1'b1 ;
                            ahbl_hresp_o <=  1'b1 ;
                        end
                    default : 
                        begin
                            ahbl_hreadyout_o <=  1'b1 ;
                        end
                    endcase 
                    if (((cs_ahbl_sm == ST_RENABLE) && apb_pready_w)) 
                        ahbl_hrdata_o <=  apb_prdata_w ;
                end
        end
    always
        @(*)
        begin
        end
    wire apb_tx_ok = (apb_pready_w & apb_penable_r) ; 
    // Register the memory inputs except for HWDATA to add 1 cycle delay 
    always
        @(posedge clk_i or 
            negedge rst_n_i)
        begin
            if ((~rst_n_i)) 
                begin
                    hwrite_r <=  1'b0 ;
                    haddr_r <=  {ADDR_WIDTH{1'b0}} ;
                    buff_valid_r <=  2'b00 ;
                end
            else
                begin
                    if (ahbl_req_rdy_w) 
                        begin
                            hwrite_r <=  ahbl_hwrite_i ;
                            haddr_r <=  ahbl_haddr_i ;
                        end
                    //    if (ahbl_ready_w)
                    //      buff_valid_r  <= ahbl_req_w;
                    if ((ahbl_req_rdy_w && (~apb_tx_ok))) 
                        buff_valid_r <=  ((buff_valid_r == 2'b00) ? 2'b01 : 2'b11) ;
                    else
                        if (((~ahbl_req_rdy_w) && apb_tx_ok)) 
                            buff_valid_r <=  ((buff_valid_r == 2'b11) ? 2'b01 : 2'b00) ;
                end
        end
    generate
        if ((APB_CLK_EN == 0)) 
            begin : single_clk
                assign apb_psel_o = apb_psel_r ; 
                assign apb_paddr_o = apb_paddr_r ; 
                assign apb_pwdata_o = apb_pwdata_r ; 
                assign apb_pwrite_o = apb_pwrite_r ; 
                assign apb_penable_o = apb_penable_r ; 
                assign apb_pready_w = apb_pready_i ; 
                assign apb_pslverr_w = apb_pslverr_i ; 
                assign apb_prdata_w = apb_prdata_i ; 
            end
        else
            begin : dual_clk
                // HCLK registers
                reg h_pend_r ; 
                reg h_done_d1_r ; 
                reg h_done_d2_r ; 
                reg h_done_d3_r ; 
                // PLCK registers
                reg p_pend_d1_r ; 
                reg p_pend_d2_r ; 
                reg p_pend_d3_r ; 
                reg p_done_r ; 
                reg [(ST_APB_W - 1):0] cs_apb_sm ; 
                reg [(ST_APB_W - 1):0] ns_apb_sm ; 
                reg [(DATA_WIDTH - 1):0] p_prdata_r ; 
                reg p_pslverr_r ; 
                reg p_psel_r ; 
                reg [(ADDR_WIDTH - 1):0] p_paddr_r ; 
                reg [(DATA_WIDTH - 1):0] p_pwdata_r ; 
                reg p_pwrite_r ; 
                reg p_penable_r ; 
                wire p_new_tx_w ; 
                // Note: p_pend_d1_r can be metastable
                //    assign    p_new_tx_w = (p_pend_d2_r  != p_pend_d1_r); // This toggles for new transaction
                assign p_new_tx_w = (p_pend_d2_r != p_pend_d3_r) ; // This toggles for new transaction
                // HCLK registering
                always
                    @(posedge clk_i or 
                        negedge rst_n_i)
                    begin
                        if ((~rst_n_i)) 
                            begin
                                h_pend_r <=  1'b0 ;
                                h_done_d1_r <=  1'b0 ;
                                h_done_d2_r <=  1'b0 ;
                                h_done_d3_r <=  1'b0 ;
                            end
                        else
                            begin
                                // Invert h_pend_r during APB setup state
                                if ((((ns_ahbl_sm == ST_WRITE) || (ns_ahbl_sm == ST_WRITEP)) || (ns_ahbl_sm == ST_READ))) 
                                    h_pend_r <=  (~h_pend_r) ;
                                // 2FF synchronizer
                                h_done_d1_r <=  p_done_r ;
                                h_done_d2_r <=  h_done_d1_r ;
                                h_done_d3_r <=  h_done_d2_r ;
                            end
                    end
                always
                    @(*)
                    begin
                        //      ns_apb_sm = cs_apb_sm;
                        case (cs_apb_sm)
                        ST_APB_IDLE : 
                            begin
                                ns_apb_sm = (p_new_tx_w ? ST_APB_SETUP : ST_APB_IDLE) ;
                            end
                        ST_APB_SETUP : 
                            begin
                                // data is available in next cyle after address phase
                                ns_apb_sm = ST_APB_ACCESS ;
                            end
                        ST_APB_ACCESS : 
                            begin
                                ns_apb_sm = (apb_pready_i ? ST_APB_IDLE : ST_APB_ACCESS) ;
                            end
                        default : 
                            begin
                                ns_apb_sm = ST_APB_IDLE ;
                            end
                        endcase 
                    end
                // PCLK registering
                always
                    @(posedge pclk_i or 
                        negedge presetn_i)
                    begin
                        if ((~presetn_i)) 
                            begin
                                p_done_r <=  1'b0 ;
                                p_pend_d1_r <=  1'b0 ;
                                p_pend_d2_r <=  1'b0 ;
                                p_pend_d3_r <=  1'b0 ;
                                cs_apb_sm <=  ST_APB_IDLE ;
                                p_prdata_r <=  {DATA_WIDTH{1'b0}} ;
                                p_pslverr_r <=  1'b0 ;
                                p_psel_r <=  1'b0 ;
                                p_penable_r <=  1'b0 ;
                                p_paddr_r <=  {ADDR_WIDTH{1'b0}} ;
                                p_pwdata_r <=  {DATA_WIDTH{1'b0}} ;
                                p_pwrite_r <=  1'b0 ;
                            end
                        else
                            begin
                                cs_apb_sm <=  ns_apb_sm ;
                                // Invert h_pend_r during APB setup state
                                if (((cs_apb_sm == ST_APB_ACCESS) && apb_pready_i)) 
                                    begin
                                        p_done_r <=  (~p_done_r) ;
                                        p_prdata_r <=  apb_prdata_i ;
                                        p_pslverr_r <=  apb_pslverr_i ;
                                    end
                                else
                                    if ((cs_apb_sm == ST_APB_SETUP)) 
                                        p_pslverr_r <=  1'b0 ;
                                // 2FF synchronizer
                                p_pend_d1_r <=  h_pend_r ;
                                p_pend_d2_r <=  p_pend_d1_r ;
                                p_pend_d3_r <=  p_pend_d2_r ;
                                case (ns_apb_sm)
                                ST_APB_SETUP : 
                                    begin
                                        // data is available in next cyle after address phase
                                        p_psel_r <=  1'b1 ;
                                        p_penable_r <=  1'b0 ;
                                        p_paddr_r <=  apb_paddr_r ;
                                        p_pwdata_r <=  apb_pwdata_r ;
                                        p_pwrite_r <=  apb_pwrite_r ;
                                    end
                                ST_APB_ACCESS : 
                                    begin
                                        p_psel_r <=  1'b1 ;
                                        p_penable_r <=  1'b1 ;
                                    end
                                default : 
                                    begin
                                        p_psel_r <=  1'b0 ;
                                        p_penable_r <=  1'b0 ;
                                    end
                                endcase 
                            end
                    end
                assign apb_psel_o = p_psel_r ; 
                assign apb_penable_o = p_penable_r ; 
                assign apb_paddr_o = p_paddr_r ; 
                assign apb_pwdata_o = p_pwdata_r ; 
                assign apb_pwrite_o = p_pwrite_r ; 
                //    assign apb_pready_w  = (h_done_d2_r != h_done_d1_r); // h_done_d1_r could be metastable
                assign apb_pready_w = (h_done_d2_r != h_done_d3_r) ; 
                assign apb_pslverr_w = p_pslverr_r ; 
                assign apb_prdata_w = p_prdata_r ; 
            end
    endgenerate
endmodule


