module axi_serializer #(
  parameter WIDTH = 32)
(
  input clk, input rst, input reverse_input,
  input [WIDTH-1:0] i_tdata, input  i_tlast, input i_tvalid,  output reg i_tready,
  output reg o_tdata, output reg o_tlast, output reg o_tvalid, input o_tready
);

  reg i_tlast_latch;
  reg [WIDTH-1:0] serial_data_reg;
  reg [$clog2(WIDTH)-1:0] serial_cnt;
  reg serializing;

  always @(posedge clk) begin
    if (rst) begin
      i_tready        <= 1'b0;
      i_tlast_latch   <= 1'b0;
      o_tdata         <= 1'b0;
      o_tlast         <= 1'b0;
      o_tvalid        <= 1'b0;
      serial_data_reg <= 'd0;
      serializing     <= 1'b0;
      serial_cnt      <= 0;
    end else begin
      i_tready <= 1'b0;
      // Shift out a bit when downstream can consume it
      if (serializing & o_tready) begin
        o_tvalid <= 1'b1;
        if (reverse_input) begin
          o_tdata                    <= serial_data_reg[0];
          serial_data_reg[WIDTH-2:0] <= serial_data_reg[WIDTH-1:1];
        end else begin
          o_tdata                    <= serial_data_reg[WIDTH-1];
          serial_data_reg[WIDTH-1:1] <= serial_data_reg[WIDTH-2:0];
        end
        if (serial_cnt == WIDTH-1) begin
          serial_cnt      <= 0;
          serial_data_reg <= i_tdata;
          i_tlast_latch   <= i_tlast;
          o_tlast         <= i_tlast_latch;
          if (~i_tvalid) begin
            serializing <= 1'b0;
          end else begin
            i_tready <= 1'b1;
          end
        end else begin
          serial_cnt <= serial_cnt + 1;
        end
      end else if (~serializing) begin
        i_tready <= 1'b1;
        if (o_tvalid && o_tready) begin
          o_tvalid <= 1'b0;
        end
        // Serial shift register (serial_data_reg) is empty, load it 
        if (i_tvalid) begin
          i_tready        <= 1'b0;
          serializing     <= 1'b1;
          i_tlast_latch   <= i_tlast;
          serial_data_reg <= i_tdata;
        end
      end
    end
  end

endmodule