module quarter_rate_downconverter #(
  parameter WIDTH=24
)(
  input clk,
  input reset,
  input phase_sync,

  input [2*WIDTH-1:0] i_tdata,
  input i_tlast,
  input i_tvalid,
  output i_tready,

  output [2*WIDTH-1:0] o_tdata,
  output o_tlast,
  output o_tvalid,
  input o_tready,

  input dirctn
);

  // temporary signals for i and q after rotation
  reg [WIDTH-1:0] tmp_i = {WIDTH{1'b0}};
  reg [WIDTH-1:0] tmp_q = {WIDTH{1'b0}};

  // State machine types and reg
  localparam S0=0, S1=1, S2=2, S3=3;
  reg[1:0] cur_state;

  // split input into i and q signal
  wire[WIDTH-1:0] i_in, q_in;
  assign i_in = i_tdata[2*WIDTH-1:WIDTH];
  assign q_in = i_tdata[WIDTH-1:0];

  // The state machine doing the rotations among states
  always @(posedge clk) begin
    if(reset || phase_sync) begin
       cur_state <= S0;
    end else begin
      case (cur_state)
        S0: begin
            if(i_tvalid == 1'b1 && i_tready == 1'b1)
              if(dirctn == 1'b0)
                cur_state <= S1;
              else
                cur_state <= S3;
            else
              cur_state <= S0;
          end
        S1: begin
            if(i_tvalid == 1'b1 && i_tready == 1'b1)
              if(dirctn == 1'b0)
                cur_state <= S2;
              else
                cur_state <= S0;
            else
              cur_state <= S1;
          end
        S2: begin
            if(i_tvalid == 1'b1 && i_tready == 1'b1)
              if(dirctn == 1'b0)
                cur_state <= S3;
              else
                cur_state <= S1;
            else
              cur_state <= S2;
          end
        S3: begin
            if(i_tvalid == 1'b1 && i_tready == 1'b1)
              if(dirctn == 1'b0)
                cur_state <= S0;
              else
                cur_state <= S2;
            else
              cur_state <= S3;
          end
      endcase
    end
  end

  // Multiplication of input IQ signal with (1,i,-1,-i):
  always @(*) begin
    case (cur_state)
      S0: begin
          // S(t) * 1 = I(t) + iQ(t):
          tmp_i = i_in;
          tmp_q = q_in;
        end
      S1: begin
          // S(t) * i = -Q(t) + iI(t):
          tmp_i = -q_in;
          tmp_q = i_in;
        end
      S2: begin
          // S(t) * -1 = -I(t) - iQ(t):
          tmp_i = -i_in;
          tmp_q = -q_in;
        end
      S3: begin
          // S(t) * -i = Q(t) - iI(t):
          tmp_i = q_in;
          tmp_q = -i_in;
        end
      default: begin
          tmp_i = i_in;
          tmp_q = q_in;
        end
    endcase
  end

  // Flop for valid and ready signals and shortening of comb. paths.
  axi_fifo #(.WIDTH(2*WIDTH + 1), .SIZE(1)) flop (
    .clk(clk), .reset(reset), .clear(1'b0),
    .i_tdata({i_tlast, tmp_i, tmp_q}), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .occupied(), .space());

endmodule // quarter_rate_downconverter