//======================================================================
// Self-Defined Bus to AXI4.0 Protocol Bridge
// Features:
// - Full duplex read/write operations
// - Pipeline optimization for back-to-back transactions
// - AXI4.0 burst mode support (single transaction per request)
// - Configurable address mapping
// - Error handling with AXI-compatible response codes
//======================================================================

module cfg_noc_axi_bridge #(
    parameter DATA_WID      = 32,
    parameter ID_WID        = 5,
    parameter NODE_ID_WID   = 5,
    parameter SUB_ADDR_WID  = 22,
    parameter ERR_WID       = 2,
    parameter ADDR_WID      = 32,
    parameter REQ_FLIT_WID  = 1 
                            + ID_WID
                            + NODE_ID_WID
                            + SUB_ADDR_WID
                            + DATA_WID ,
    parameter RSP_FLIT_WID  = 1
                            + ID_WID
                            + ERR_WID
                            + DATA_WID
)(
    // Global signals
    input  wire                    clk,
    input  wire                    rst_n,

    // Self-defined Bus Request Interface
    output wire                    bridge_req_rdy,
    input  wire                    bridge_req_vld,
    input  wire [REQ_FLIT_WID-1:0] bridge_req_flit,

    // Self-defined Bus Response Interface
    input  wire                    bridge_rsp_rdy,
    output wire                    bridge_rsp_vld,
    output wire [RSP_FLIT_WID-1:0] bridge_rsp_flit,

    // AXI4.0 Master Interface
    // Write Address Channel
    output wire                    m_axi_awvalid,
    output wire [ID_WID-1:0]       m_axi_awid,
    output wire [ADDR_WID-1:0]     m_axi_awaddr,
    output wire [7:0]              m_axi_awlen,
    output wire [2:0]              m_axi_awsize,
    output wire [1:0]              m_axi_awburst,
    input  wire                    m_axi_awready,

    // Write Data Channel
    output wire                    m_axi_wvalid,
    output wire [ID_WID-1:0]       m_axi_wid,
    output wire [DATA_WID-1:0]     m_axi_wdata,
    output wire [DATA_WID/8-1:0]   m_axi_wstrb,
    output wire                    m_axi_wlast,
    input  wire                    m_axi_wready,

    // Write Response Channel
    input  wire                    m_axi_bvalid,
    input  wire [ID_WID-1:0]       m_axi_bid,
    input  wire [1:0]              m_axi_bresp,
    output wire                    m_axi_bready,

    // Read Address Channel
    output wire [ID_WID-1:0]       m_axi_arid,
    output wire [ADDR_WID-1:0]     m_axi_araddr,
    output wire [7:0]              m_axi_arlen,
    output wire [2:0]              m_axi_arsize,
    output wire [1:0]              m_axi_arburst,
    output wire                    m_axi_arvalid,
    input  wire                    m_axi_arready,

    // Read Data Channel
    input  wire [ID_WID-1:0]       m_axi_rid,
    input  wire [DATA_WID-1:0]     m_axi_rdata,
    input  wire [1:0]              m_axi_rresp,
    input  wire                    m_axi_rlast,
    input  wire                    m_axi_rvalid,
    output wire                    m_axi_rready
);

//----------------------------------------------------------------------
// Parameters 
//----------------------------------------------------------------------
localparam BYTE_EN_WID   = DATA_WID/8;

//----------------------------------------------------------------------
// Request Flit Decomposition (Structure matching your spec)
//----------------------------------------------------------------------


wire                    bridge_req_type;  // 0:Read, 1:Write
wire [ID_WID-1:0]       bridge_req_id;
wire [NODE_ID_WID-1:0]  bridge_req_node_id;
wire [SUB_ADDR_WID-1:0] bridge_req_sub_addr;
wire [DATA_WID-1:0]     bridge_req_wdata; // Valid for write requests

assign {
    bridge_req_type,       // 1 bit
    bridge_req_id,         // ID_WID
    bridge_req_node_id,    // NODE_ID_WID
    bridge_req_sub_addr,   // SUB_ADDR_WID
    bridge_req_wdata       // DATA_WID
} = bridge_req_flit;




//----------------------------------------------------------------------
// FSM Declaration (Handling read/write transactions)
//----------------------------------------------------------------------
localparam IDLE         = 3'b000;
localparam HOLD_REQ     = 3'b001;
localparam AW_W_CHAN    = 3'b010;
localparam AR_CHAN      = 3'b011;
localparam WR_RESP_CHAN = 3'b100;
localparam RD_DATA_CHAN = 3'b110;
//localparam ERROR        = 3'b111;

reg [2:0] curr_state;
reg [2:0] next_state;

//----------------------------------------------------------------------
// FSM-1 FSM transition logic
//----------------------------------------------------------------------

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        curr_state <= IDLE;
    end else begin
        curr_state <= next_state;
    end
end

//----------------------------------------------------------------------
// FSM-2 FSM Jump condition logic
//----------------------------------------------------------------------

reg                     hold_req_vld;         // Hold current request
reg                     hold_req_type;         // Hold current request
reg [ID_WID-1:0]        hold_req_id;        // Transaction ID in progress
reg [SUB_ADDR_WID-1:0]  hold_req_sub_addr;
reg [DATA_WID-1:0]      hold_req_wdata; // Valid for write requests

always @(*) begin
    if (!rst_n) begin
        next_state = IDLE;
    end else begin
        case (curr_state)
            IDLE: begin
                next_state = (bridge_req_vld) ? HOLD_REQ : IDLE;
            end 

            HOLD_REQ: begin
                if(hold_req_type && m_axi_awready && m_axi_wready) begin
                    next_state = AW_W_CHAN;
                end else if (!hold_req_type && m_axi_arready) begin
                    next_state = AR_CHAN;
                end else begin
                    next_state = HOLD_REQ;
                end
            end

            AW_W_CHAN: begin
                next_state = WR_RESP_CHAN;
            end 

            AR_CHAN: begin
                next_state = RD_DATA_CHAN;
            end

            WR_RESP_CHAN: begin
                next_state = (m_axi_bvalid && m_axi_rlast) ? IDLE : WR_RESP_CHAN; 
            end

            RD_DATA_CHAN: begin
                next_state = (m_axi_rvalid) ? IDLE : RD_DATA_CHAN;
            end
        endcase
    end
end

//----------------------------------------------------------------------
// FSM-3 :FSM Action Logic
//----------------------------------------------------------------------
//reg                     req_vld;
//reg                     req_type;  // 0:Read, 1:Write
//reg [ID_WID-1:0]        req_id;
//reg [NODE_ID_WID-1:0]   req_node_id;
//reg [SUB_ADDR_WID-1:0]  req_sub_addr;
//reg [DATA_WID-1:0]      req_wdata; // Valid for write requests
//
//always @(posedge clk or negedge rst_n) begin
//    if (!rst_n) begin
//        req_vld     <= 1'b0;
//        req_type    <= 1'b0;
//        req_id      <= 'b0;
//        req_sub_addr    <= 'b0;
//        req_data    <= 'b0;
//        req_err     <= 'b0;
//    end else if (bridge_req_vld && !req_vld) begin
//        req_vld     <= 1'b1;
//        req_type    <= bridge_req_type;
//        req_id      <= bridge_req_id;
//        req_addr    <= bridge_req_sub_addr;
//        req_wdata   <=bridge_req_wdata;
//    end else begin
//        req_vld <= 1'b0;
//    end
//end

assign bridge_req_rdy = (curr_state == IDLE);

//----------------------------------------------------------------------
// Transaction Processing
//----------------------------------------------------------------------

reg                     reg_rsp_vld;
reg                     reg_rsp_type;
reg [2 -1:0]            reg_rsp_resp;
reg [ID_WID -1:0]       reg_rsp_id;        // Transaction ID in progress
reg [DATA_WID-1:0]      reg_rsp_rdata;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        hold_req_vld    <= 1'b0;
        hold_req_type   <= 1'b0;
        hold_req_id     <= 'b0;

        reg_rsp_vld     <= 'b0;            
        reg_rsp_type    <= 'b0;
        reg_rsp_id      <= 'b0;
        reg_rsp_resp    <= 'b0;
        reg_rsp_rdata   <= 'b0;
        //====current_req
    end
    else begin
        case (curr_state)
            IDLE: begin
                if (bridge_req_vld) begin
                    hold_req_vld    <= 1'b1;
                    hold_req_type   <= bridge_req_type;
                    hold_req_id     <= bridge_req_id;
                    hold_req_sub_addr<=bridge_req_sub_addr;
                    hold_req_wdata  <= bridge_req_wdata;
                end else begin
                    hold_req_vld    <= 'b0;
                    hold_req_type   <= 'b0;
                    hold_req_id     <= 'b0;
                    hold_req_sub_addr<='b0;
                    hold_req_wdata  <= 'b0;
                end

                reg_rsp_vld     <= 'b0;            
                reg_rsp_type    <= 'b0;
                reg_rsp_id      <= 'b0;
                reg_rsp_resp    <= 'b0;
                reg_rsp_rdata   <= 'b0;
            end 
            HOLD_REQ: begin
                hold_req_vld    <= hold_req_vld;
                hold_req_type   <= hold_req_vld;
                hold_req_id     <= hold_req_id;
                hold_req_sub_addr<=hold_req_sub_addr;
                hold_req_wdata  <= hold_req_wdata;
            end

            AW_W_CHAN: begin
                
            end
            
            AR_CHAN: begin
              
            end
            
            WR_RESP_CHAN: begin
                if (m_axi_bvalid==1'b1) begin
                    reg_rsp_vld <= 1'b1;            
                    reg_rsp_type<= 'b1;
                    reg_rsp_id  <= m_axi_bid;
                    reg_rsp_resp<= m_axi_bresp;
                    reg_rsp_rdata<= 'b0;
                end else begin
                  
                end
            end

            RD_DATA_CHAN: begin
                if (m_axi_rvalid==1'b1) begin
                    reg_rsp_vld <= 1'b1; 
                    reg_rsp_type<= 1'b0;
                    reg_rsp_id  <= m_axi_rid;
                    reg_rsp_resp<= m_axi_rresp;
                    reg_rsp_rdata<=m_axi_rdata;
                end
            end
            
            default: begin
              
            end
        endcase
        
    end
end


//----------------------------------------------------------------------
// AXI control signals
//----------------------------------------------------------------------
// AXI signal assignments
assign m_axi_awvalid = (curr_state == AW_W_CHAN);
assign m_axi_awaddr  = (curr_state == AW_W_CHAN) ? {10'b0,hold_req_sub_addr} : 'b0;
assign m_axi_awid    = (curr_state == AW_W_CHAN) ? hold_req_id : 'b0;
assign m_axi_awlen   = 8'h00;     // Single transaction
assign m_axi_awsize  = 3'b100;    // 4 bytes (DATA_WID/8)
assign m_axi_awburst = 2'b01;     // INCR burst type

assign m_axi_wvalid  = (curr_state == AW_W_CHAN);
assign m_axi_wid     = (curr_state == AW_W_CHAN) ? hold_req_id : 'b0;
assign m_axi_wdata   = (curr_state == AW_W_CHAN) ? hold_req_wdata : 'b0;
assign m_axi_wstrb   = {BYTE_EN_WID{1'b1}}; // All bytes enabled
assign m_axi_wlast   = 1'b1;

assign m_axi_arvalid = (curr_state == AR_CHAN);
assign m_axi_arid    = (curr_state == AR_CHAN) ? hold_req_id : 'b0;
assign m_axi_araddr  = (curr_state == AR_CHAN) ? {10'b0,hold_req_sub_addr} : 'b0;
assign m_axi_arlen   = 8'h00;
assign m_axi_arsize  = 3'b100;
assign m_axi_arburst = 2'b01;

assign m_axi_bready  = 1'b1;  // Always ready for write responses
//assign m_axi_rready  = 1'b1;
assign m_axi_rready  = bridge_rsp_rdy;

//----------------------------------------------------------------------
// Response Packet Formatting
//----------------------------------------------------------------------
assign bridge_rsp_vld = reg_rsp_vld;

// Response format: [type(1)|ID(5)|ERR(2)|DATA(32)]
assign bridge_rsp_flit = {
    reg_rsp_type,       // type bit 
    reg_rsp_id,         // ID_WID
    reg_rsp_resp,       // ERR_WID
    reg_rsp_rdata       // DATA_WID
};

//----------------------------------------------------------------------
// Timeout Protection (Prevent transaction hangs)
//----------------------------------------------------------------------
//  localparam TIMEOUT_VALUE = 1023;
//  reg [9:0] timeout_counter;
//  
//  always_ff @(posedge clk or negedge rst_n) begin
//      if (!rst_n) 
//          timeout_counter <= '0;
//      else if (curr_state != next_state) 
//          timeout_counter <= '0;
//      else if (curr_state != IDLE) 
//          timeout_counter <= timeout_counter + 1;
//  end

endmodule