module axi_mcb_cmd_fsm 
(
///////////////////////////////////////////////////////////////////////////////
// Port Declarations     
///////////////////////////////////////////////////////////////////////////////
  input  wire                                 clk           , 
  input  wire                                 reset         , 
  output wire                                 axready       , 
  input  wire                                 axvalid       , 
  output wire                                 cmd_en        , 
  input  wire                                 cmd_full      , 
  input  wire                                 calib_done    ,
  // signal to increment to the next mcb transaction 
  output wire                                 next_cmd      , 
  // signal to the fsm there is another transaction required
  input  wire                                 next_pending  ,
  // Write Data portion has completed or Read FIFO has a slot available (not
  // full)
  input  wire                                 data_ready    ,
  output wire                                 b_push        ,
  input  wire                                 b_full        ,
  output wire                                 r_push

);

////////////////////////////////////////////////////////////////////////////////
// Local parameters
////////////////////////////////////////////////////////////////////////////////
// AXBURST decodes
localparam SM_WAIT_FOR_CALIB_DONE = 3'b000;
localparam SM_IDLE                = 3'b001;
localparam SM_CMD_EN              = 3'b010;
localparam SM_CMD_ACCEPTED        = 3'b011;
localparam SM_DONE_WAIT           = 3'b100;
localparam SM_DONE                = 3'b101;
localparam SM_FAIL                = 3'b111;

////////////////////////////////////////////////////////////////////////////////
// Wires/Reg declarations
////////////////////////////////////////////////////////////////////////////////
reg [2:0]       state;
reg [2:0]       next_state;

////////////////////////////////////////////////////////////////////////////////
// BEGIN RTL
////////////////////////////////////////////////////////////////////////////////

// State is registered
always @(posedge clk) begin
  if (reset) begin
    state <= SM_WAIT_FOR_CALIB_DONE;
  end else begin
    state <= next_state;
  end
end

// Next state transitions.
always @(*)
begin
  next_state = state;
  case (state)
    SM_WAIT_FOR_CALIB_DONE:
      if (calib_done)
        next_state = SM_IDLE;
      else 
        next_state = state;

    SM_IDLE:
      if (axvalid & data_ready)
        next_state = SM_CMD_EN;
      else 
        next_state = state;

    SM_CMD_EN:
      if (~cmd_full & next_pending)
        next_state = SM_CMD_ACCEPTED;
      else if (~cmd_full & ~next_pending & b_full)
        next_state = SM_DONE_WAIT;
      else if (~cmd_full & ~next_pending & ~b_full)
        next_state = SM_DONE;
      else 
        next_state = state;

    SM_CMD_ACCEPTED:
      if (data_ready)
        next_state = SM_CMD_EN;
      else 
        next_state = SM_IDLE;

    SM_DONE_WAIT:
      if (!b_full)
        next_state = SM_DONE;
      else 
        next_state = state;

    SM_DONE:
      next_state = SM_IDLE;

    SM_FAIL:
      next_state = SM_FAIL;

      default:
        next_state = SM_FAIL;
  endcase
end

// Assign outputs based on current state.
assign cmd_en   = (state == SM_CMD_EN);
assign next_cmd = (state == SM_CMD_ACCEPTED) || (state == SM_DONE);
assign axready  = (state == SM_DONE);
assign b_push   = (state == SM_DONE);
assign r_push   = (state == SM_CMD_ACCEPTED) || (state == SM_DONE);


endmodule