dakies/OSS_Verilog huggingface dataset:
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
module axi_bit_reduce
  #(parameter WIDTH_IN=48,
    parameter WIDTH_OUT=25,
    parameter DROP_TOP=6,
    parameter VECTOR_WIDTH=1)   // vector_width = 2 for complex, 1 for real
   (input [VECTOR_WIDTH*WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [VECTOR_WIDTH*WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   genvar 				i;
   generate
      for(i=0; i<VECTOR_WIDTH; i=i+1)
	assign o_tdata[(i+1)*WIDTH_OUT-1:i*WIDTH_OUT] = i_tdata[(i+1)*WIDTH_IN-DROP_TOP-1:i*WIDTH_IN+(WIDTH_IN-WIDTH_OUT)-DROP_TOP];
   endgenerate

   assign o_tlast = i_tlast;
   assign o_tvalid = i_tvalid;
   assign i_tready = o_tready;

endmodule // axi_bit_sel
module split_stream_fifo
  #(parameter WIDTH=16,
    parameter FIFO_SIZE=5,
    parameter ACTIVE_MASK=4'b1111)
   (input clk, input reset, input clear,
    input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
    output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
    output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
    output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready);

   wire [WIDTH-1:0]    o0_tdata_int, o1_tdata_int, o2_tdata_int, o3_tdata_int;
   wire 	       o0_tlast_int, o1_tlast_int, o2_tlast_int, o3_tlast_int;
   wire 	       o0_tvalid_int, o1_tvalid_int, o2_tvalid_int, o3_tvalid_int;
   wire 	       o0_tready_int, o1_tready_int, o2_tready_int, o3_tready_int;
   
   split_stream #(.WIDTH(WIDTH), .ACTIVE_MASK(ACTIVE_MASK)) split_stream
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
      .o0_tdata(o0_tdata_int), .o0_tlast(o0_tlast_int), .o0_tvalid(o0_tvalid_int), .o0_tready(o0_tready_int),
      .o1_tdata(o1_tdata_int), .o1_tlast(o1_tlast_int), .o1_tvalid(o1_tvalid_int), .o1_tready(o1_tready_int),
      .o2_tdata(o2_tdata_int), .o2_tlast(o2_tlast_int), .o2_tvalid(o2_tvalid_int), .o2_tready(o2_tready_int),
      .o3_tdata(o3_tdata_int), .o3_tlast(o3_tlast_int), .o3_tvalid(o3_tvalid_int), .o3_tready(o3_tready_int));

   generate
      if(ACTIVE_MASK[0])
	axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo0
	  (.clk(clk), .reset(reset), .clear(clear),
	   .i_tdata({o0_tlast_int, o0_tdata_int}), .i_tvalid(o0_tvalid_int), .i_tready(o0_tready_int),
	   .o_tdata({o0_tlast, o0_tdata}), .o_tvalid(o0_tvalid), .o_tready(o0_tready),
	   .occupied(), .space());
      if(ACTIVE_MASK[1])
	axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo1
	  (.clk(clk), .reset(reset), .clear(clear),
	   .i_tdata({o1_tlast_int, o1_tdata_int}), .i_tvalid(o1_tvalid_int), .i_tready(o1_tready_int),
	   .o_tdata({o1_tlast, o1_tdata}), .o_tvalid(o1_tvalid), .o_tready(o1_tready),
	   .occupied(), .space());
      if(ACTIVE_MASK[2])
	axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo2
	  (.clk(clk), .reset(reset), .clear(clear),
	   .i_tdata({o2_tlast_int, o2_tdata_int}), .i_tvalid(o2_tvalid_int), .i_tready(o2_tready_int),
	   .o_tdata({o2_tlast, o2_tdata}), .o_tvalid(o2_tvalid), .o_tready(o2_tready),
	   .occupied(), .space());
      if(ACTIVE_MASK[3])
	axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo3
	  (.clk(clk), .reset(reset), .clear(clear),
	   .i_tdata({o3_tlast_int, o3_tdata_int}), .i_tvalid(o3_tvalid_int), .i_tready(o3_tready_int),
	   .o_tdata({o3_tlast, o3_tdata}), .o_tvalid(o3_tvalid), .o_tready(o3_tready),
	   .occupied(), .space());
   endgenerate
      
endmodule // split_stream_fifo
module split_stream
  #(parameter WIDTH=16,
    parameter ACTIVE_MASK=4'b1111)
   (input clk, input reset, input clear,  // These are not used in plain split_stream
    input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
    output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
    output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
    output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready);

   assign { o0_tlast, o0_tdata } = { i_tlast, i_tdata };
   assign { o1_tlast, o1_tdata } = { i_tlast, i_tdata };
   assign { o2_tlast, o2_tdata } = { i_tlast, i_tdata };
   assign { o3_tlast, o3_tdata } = { i_tlast, i_tdata };

   // NOTE -- this violates the AXI spec because tvalids are dependent on treadys.
   //   It will be ok most of the time, but muxes and demuxes will need a fifo in 
   //   the middle to avoid deadlock
   
   assign i_tready = ~|(~{o3_tready,o2_tready,o1_tready,o0_tready} & ACTIVE_MASK);
   assign { o3_tvalid, o2_tvalid, o1_tvalid, o0_tvalid } = {4{i_tready & i_tvalid}};
   
endmodule // split_stream
module puncture #(
  parameter WIDTH                   = 32,      // Input bit width
  parameter MAX_LEN                 = 8,       // Maximum length of puncturing vector
  parameter DEFAULT_VECTOR_LEN      = 8,       // Vector length reset value
  parameter DEFAULT_PUNCTURE_VECTOR = 8'hFF)   // Puncture vector reset value
(
  input clk, input reset, input clear,
  input [$clog2(MAX_LEN):0] vector_len_tdata, input vector_len_tvalid, output vector_len_tready,
  input [MAX_LEN-1:0] puncture_vector_tdata, input puncture_vector_tvalid, output puncture_vector_tready,
  input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  assign vector_len_tready      = 1'b1;
  assign puncture_vector_tready = 1'b1;

  reg [$clog2(MAX_LEN):0] puncture_index, vector_len;
  reg [MAX_LEN-1:0] puncture_vector;
  always @(posedge clk) begin
    if (reset | clear) begin
      vector_len         <= DEFAULT_VECTOR_LEN-1;
      puncture_index     <= DEFAULT_VECTOR_LEN-1;
      puncture_vector    <= DEFAULT_PUNCTURE_VECTOR;
    end else begin
      if (puncture_vector_tvalid | vector_len_tvalid) begin
        puncture_index   <= vector_len_tdata - 1;
      end else if (i_tready & i_tvalid) begin
        if (puncture_index == 0) begin
          puncture_index <= vector_len;
        end else begin
          puncture_index <= puncture_index - 1;
        end
      end
      if (puncture_vector_tvalid) begin
        puncture_vector = puncture_vector_tdata;
      end
      if (vector_len_tvalid) begin
        vector_len = vector_len_tdata - 1;
      end
    end
  end

  wire puncture = puncture_vector[puncture_index];
  // Puncture by ANDing i_tvalid
  axi_fifo_flop #(.WIDTH(WIDTH+1)) axi_fifo_flop_punctured (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid & puncture), .i_tready(i_tready),
    .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .space(), .occupied());

endmodule
module cvita_hdr_decoder (
  input [127:0] header,
  output [1:0] pkt_type, output eob, output has_time,
  output [11:0] seqnum, output [15:0] length, output [15:0] payload_length,
  output [15:0] src_sid, output [15:0] dst_sid,
  output [63:0] vita_time
);

  wire [63:0] hdr[0:1];
  assign hdr[0] = header[127:64];
  assign hdr[1] = header[63:0];

  assign pkt_type  = hdr[0][63:62];
  assign has_time  = hdr[0][61];
  assign eob       = hdr[0][60];
  assign seqnum    = hdr[0][59:48];
  assign length    = hdr[0][47:32];
  assign src_sid   = hdr[0][31:16];
  assign dst_sid   = hdr[0][15:0];
  assign vita_time = hdr[1];

  assign payload_length = has_time ? length - 16'd16 : length - 16'd8;

endmodule
module symbol_to_gray_bits #(
  parameter WIDTH_IN         = 16,
  parameter MODULATION_ORDER = 6,  // QPSK = 2, QAM16 = 4, QAM64 = 6
  parameter REVERSE          = 0)  // 0: Q/I mapping (i.e. QPSK symbol 10 Q = 1, I = 0), 1: I/Q mapping
(
  input clk, input reset, input clear,
  input [2*WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [MODULATION_ORDER-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  // Truncate & invert sign bit
  wire [MODULATION_ORDER/2-1:0] symbol_i = {~i_tdata[2*WIDTH_IN-1],i_tdata[2*WIDTH_IN-2:2*WIDTH_IN-MODULATION_ORDER/2]};
  wire [MODULATION_ORDER/2-1:0] symbol_q = {~i_tdata[WIDTH_IN-1],i_tdata[WIDTH_IN-2:WIDTH_IN-MODULATION_ORDER/2]};

  // Symbol to gray coded bits
  reg [MODULATION_ORDER/2-1:0] gray_bits_i, gray_bits_q;
  integer k;
  always @(*) begin
    for (k = MODULATION_ORDER/2-1; k >= 0; k = k - 1) begin
      if (k == MODULATION_ORDER/2-1) begin
        gray_bits_i[k]   = symbol_i[k];
        gray_bits_q[k]   = symbol_q[k];
      end else begin
        gray_bits_i[k]   = symbol_i[k] ^ symbol_i[k+1];
        gray_bits_q[k]   = symbol_q[k] ^ symbol_q[k+1];
      end
    end
  end

  wire [MODULATION_ORDER-1:0] gray_bits = REVERSE ? {gray_bits_q,gray_bits_i} : {gray_bits_i,gray_bits_q};

  axi_fifo_flop #(.WIDTH(MODULATION_ORDER+1)) reg_gray_bits (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({i_tlast,gray_bits}), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .space(), .occupied());

endmodule
module axi_pipe_join
  #(parameter PRE_JOIN_STAGES0=3,
    parameter PRE_JOIN_STAGES1=3,
    parameter POST_JOIN_STAGES=3)
   (input clk, input reset, input clear,
    input i0_tlast, input i0_tvalid, output i0_tready,
    input i1_tlast, input i1_tvalid, output i1_tready,
    output o_tlast, output o_tvalid, input o_tready,
    output [PRE_JOIN_STAGES0-1:0] enables0,
    output [PRE_JOIN_STAGES1-1:0] enables1,
    output [POST_JOIN_STAGES-1:0] enables_post);

   wire 			  join_tlast, join_tvalid, join_tready;
   wire 			  int0_tlast, int0_tvalid, int0_tready;
   wire 			  int1_tlast, int1_tvalid, int1_tready;
   
   axi_pipe #(.STAGES(PRE_JOIN_STAGES0)) pipe_pre_0
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(i0_tlast), .i_tvalid(i0_tvalid), .i_tready(i0_tready),
      .o_tlast(int0_tlast), .o_tvalid(int0_tvalid), .o_tready(int0_tready),
      .enables(enables0), .valids());
   
   axi_pipe #(.STAGES(PRE_JOIN_STAGES1)) pipe_pre_1
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(i1_tlast), .i_tvalid(i1_tvalid), .i_tready(i1_tready),
      .o_tlast(int1_tlast), .o_tvalid(int1_tvalid), .o_tready(int1_tready),
      .enables(enables1), .valids());
   
   axi_pipe #(.STAGES(POST_JOIN_STAGES)) pipe_post
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(join_tlast), .i_tvalid(join_tvalid), .i_tready(join_tready),
      .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready),
      .enables(enables_post), .valids());
   
   axi_join #(.INPUTS(2)) joiner
     (.i_tlast({int1_tlast,int0_tlast}), .i_tvalid({int1_tvalid,int0_tvalid}), .i_tready({int1_tready,int0_tready}),
      .o_tlast(join_tlast), .o_tvalid(join_tvalid), .o_tready(join_tready));
   
endmodule // axi_pipe_join
module delay_fifo
  #(parameter MAX_LEN=1023,
    parameter WIDTH=16)
   (input clk, input reset, input clear,
    input [$clog2(MAX_LEN+1)-1:0] len,
    input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   reg [$clog2(MAX_LEN+1)-1:0] full_count;
   wire 		  full = full_count == len;
   
   wire 		  do_op = i_tvalid & o_tready;

   assign i_tready = o_tready;
   assign o_tvalid = i_tvalid;

   wire [WIDTH-1:0] 		    fifo_out;
   
   axi_fifo #(.WIDTH(WIDTH), .SIZE($clog2(MAX_LEN+1))) sample_fifo
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tdata(i_tdata), .i_tvalid(do_op), .i_tready(),
      .o_tdata(fifo_out), .o_tvalid(), .o_tready(do_op&full));

   always @(posedge clk)
     if(reset | clear)
       full_count <= 0;
     else
       if(do_op & ~full)
	 full_count <= full_count + 1;     // FIXME careful if len changes during operation you must clear
   
   assign o_tdata = full ? fifo_out : 0;
   assign o_tlast = i_tlast;

endmodule // delay_fifo
module moving_sum #(
  parameter MAX_LEN = 1023,
  parameter WIDTH   = 16
)(
  input clk, input reset, input clear,
  input [$clog2(MAX_LEN+1)-1:0] len,
  input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [WIDTH+$clog2(MAX_LEN+1)-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  wire signed [WIDTH+$clog2(MAX_LEN+1)-1:0] sum;
  reg signed [WIDTH+$clog2(MAX_LEN+1)-1:0] sum_reg;
  reg [$clog2(MAX_LEN+1)-1:0] full_count, len_reg;
  reg len_changed;

  wire full  = (full_count == len_reg);
  wire do_op = (i_tvalid & i_tready);

  wire i_tready_int, i_tvalid_int;
  wire fifo_tvalid, fifo_tready;
  wire [WIDTH-1:0] fifo_tdata;

  axi_fifo #(.WIDTH(WIDTH), .SIZE($clog2(MAX_LEN))) axi_fifo (
    .clk(clk), .reset(reset | len_changed), .clear(clear),
    .i_tdata(i_tdata), .i_tvalid(do_op), .i_tready(),
    .o_tdata(fifo_tdata), .o_tvalid(fifo_tvalid), .o_tready(fifo_tready),
    .occupied(), .space());

  assign fifo_tready = i_tvalid & i_tready_int & full;

  always @(posedge clk) begin
    if (reset | clear | len_changed) begin
       full_count <= 'd0;
    end else begin
      if (do_op & ~full) begin
        full_count <= full_count + 1;
      end
    end
  end

  assign sum = sum_reg + $signed(i_tdata) - (full ? $signed(fifo_tdata) : 0);

  always @(posedge clk) begin
    if (reset | clear) begin
      sum_reg     <= 'd0;
      len_reg     <= 1;
      len_changed <= 1'b0;
    end else begin
      len_reg <= (len == 0) ? 1 : len;
      if (len_reg != len) begin
        len_changed <= 1'b1;
      end else begin
        len_changed <= 1'b0;
      end
      if (len_changed) begin
        sum_reg <= 'd0;
      end else if (do_op) begin
        sum_reg <= sum;
      end
    end
  end

  // Output register
  axi_fifo_flop #(.WIDTH(WIDTH+$clog2(MAX_LEN+1)+1)) axi_fifo_flop (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({i_tlast,sum}), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
    .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .occupied(), .space());

  assign i_tready     = (~full | (fifo_tvalid & full)) & i_tready_int & ~len_changed;
  assign i_tvalid_int = (~full | (fifo_tvalid & full)) & i_tvalid     & ~len_changed;

endmodule // moving_sum
module mult_rc
  #(parameter WIDTH_REAL=25,
    parameter WIDTH_CPLX=18,
    parameter WIDTH_P=48,
    parameter DROP_TOP_P=0,
    parameter LATENCY=3,
    parameter CASCADE_OUT=0)
   (input clk, input reset,
    input [WIDTH_REAL-1:0] real_tdata, input real_tlast, input real_tvalid, output real_tready,
    input [2*WIDTH_CPLX-1:0] cplx_tdata, input cplx_tlast, input cplx_tvalid, output cplx_tready,
    output [2*WIDTH_P-1:0] p_tdata, output p_tlast, output p_tvalid, input p_tready);

   // NOTE -- we cheat here and share ready/valid.  This works because we can guarantee both
   //           paths will match
   generate
      if(WIDTH_REAL > WIDTH_CPLX)
	begin
	   mult #(.WIDTH_A(WIDTH_REAL), .WIDTH_B(WIDTH_CPLX), .WIDTH_P(WIDTH_P), .DROP_TOP_P(DROP_TOP_P),
		  .LATENCY(LATENCY), .CASCADE_OUT(CASCADE_OUT)) mult_i
	     (.clk(clk), .reset(reset),
	      .a_tdata(real_tdata), .a_tlast(real_tlast), .a_tvalid(real_tvalid), .a_tready(real_tready),
	      .b_tdata(cplx_tdata[2*WIDTH_CPLX-1:WIDTH_CPLX]), .b_tlast(cplx_tlast), .b_tvalid(cplx_tvalid), .b_tready(cplx_tready),
	      .p_tdata(p_tdata[2*WIDTH_P-1:WIDTH_P]), .p_tlast(p_tlast), .p_tvalid(p_tvalid), .p_tready(p_tready));
           
	   mult #(.WIDTH_A(WIDTH_REAL), .WIDTH_B(WIDTH_CPLX), .WIDTH_P(WIDTH_P), .DROP_TOP_P(DROP_TOP_P),
		  .LATENCY(LATENCY), .CASCADE_OUT(CASCADE_OUT)) mult_q
	     (.clk(clk), .reset(reset),
	      .a_tdata(real_tdata), .a_tlast(real_tlast), .a_tvalid(real_tvalid), .a_tready(),
	      .b_tdata(cplx_tdata[WIDTH_CPLX-1:0]), .b_tlast(cplx_tlast), .b_tvalid(cplx_tvalid), .b_tready(),
	      .p_tdata(p_tdata[WIDTH_P-1:0]), .p_tlast(), .p_tvalid(), .p_tready(p_tready));
        end // if (WIDTH_REAL > WIDTH_CPLX)
      else
	begin
	   mult #(.WIDTH_A(WIDTH_CPLX), .WIDTH_B(WIDTH_REAL), .WIDTH_P(WIDTH_P), .DROP_TOP_P(DROP_TOP_P),
		  .LATENCY(LATENCY), .CASCADE_OUT(CASCADE_OUT)) mult_i
	     (.clk(clk), .reset(reset),
	      .a_tdata(cplx_tdata[2*WIDTH_CPLX-1:WIDTH_CPLX]), .a_tlast(cplx_tlast), .a_tvalid(cplx_tvalid), .a_tready(cplx_tready),
	      .b_tdata(real_tdata), .b_tlast(real_tlast), .b_tvalid(real_tvalid), .b_tready(real_tready),
	      .p_tdata(p_tdata[2*WIDTH_P-1:WIDTH_P]), .p_tlast(p_tlast), .p_tvalid(p_tvalid), .p_tready(p_tready));
           
	   mult #(.WIDTH_A(WIDTH_CPLX), .WIDTH_B(WIDTH_REAL), .WIDTH_P(WIDTH_P), .DROP_TOP_P(DROP_TOP_P),
		  .LATENCY(LATENCY), .CASCADE_OUT(CASCADE_OUT)) mult_q
	     (.clk(clk), .reset(reset),
	      .a_tdata(cplx_tdata[WIDTH_CPLX-1:0]), .a_tlast(cplx_tlast), .a_tvalid(cplx_tvalid), .a_tready(),
	      .b_tdata(real_tdata), .b_tlast(real_tlast), .b_tvalid(real_tvalid), .b_tready(),
	      .p_tdata(p_tdata[WIDTH_P-1:0]), .p_tlast(), .p_tvalid(), .p_tready(p_tready));
	end // else: !if(WIDTH_REAL > WIDTH_CPLX)
   endgenerate
   
endmodule // mult_rc
module axi_join
  #(parameter INPUTS=2)
  (input [INPUTS-1:0] i_tlast, input [INPUTS-1:0] i_tvalid, output [INPUTS-1:0] i_tready,
   output o_tlast, output o_tvalid, input o_tready);

   wire   all_here = &i_tvalid;
   assign o_tvalid = all_here;
   assign o_tlast = |i_tlast;
   assign i_tready = {INPUTS{o_tready & all_here}};
   
endmodule // axi_join
module axi_packet_mux #(
  parameter NUM_INPUTS = 1,
  parameter MUX_PRE_FIFO_SIZE = 0,  // Use 0 (most efficient) unless there is need to compensate for unbalanced input path latencies
  parameter MUX_POST_FIFO_SIZE = 0, // Generally leave at 0, similar effect as FIFO_SIZE
  parameter FIFO_SIZE = 5           // Size of FIFO in CHDR framer
)(
  input clk, input reset, input clear,
  input [NUM_INPUTS*64-1:0] i_tdata, input [NUM_INPUTS-1:0] i_tlast, input [NUM_INPUTS-1:0] i_tvalid, output [NUM_INPUTS-1:0] i_tready, input [NUM_INPUTS*128-1:0] i_tuser,
  output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  wire [NUM_INPUTS*(64+128)-1:0] i_tdata_flat;
  genvar i;
  generate
    for (i = 0; i < NUM_INPUTS; i = i + 1) begin
      assign i_tdata_flat[(128+64)*(i+1)-1:(128+64)*i] = {i_tuser[128*(i+1)-1:128*i],i_tdata[64*(i+1)-1:64*i]};
    end
  endgenerate

  wire [63:0] int_tdata;
  wire [127:0] int_tuser;
  wire int_tlast, int_tvalid, int_tready;
  axi_mux #(.PRIO(0), .WIDTH(128+64), .PRE_FIFO_SIZE(MUX_PRE_FIFO_SIZE), .POST_FIFO_SIZE(MUX_POST_FIFO_SIZE), .SIZE(NUM_INPUTS)) axi_mux (
    .clk(clk), .reset(reset), .clear(1'b0),
    .i_tdata(i_tdata_flat), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .o_tdata({int_tuser, int_tdata}), .o_tlast(int_tlast), .o_tvalid(int_tvalid), .o_tready(int_tready));

  chdr_framer #(.SIZE(FIFO_SIZE), .WIDTH(64)) chdr_framer (
    .clk(clk), .reset(reset), .clear(1'b0),
    .i_tdata(int_tdata), .i_tuser(int_tuser), .i_tlast(int_tlast), .i_tvalid(int_tvalid), .i_tready(int_tready),
    .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));

endmodule
module axi_pipe_mac
  #(parameter LATENCY=3,
    parameter CASCADE_IN=0)
   (input clk, input reset, input clear,
    input a_tlast, input a_tvalid, output a_tready,
    input b_tlast, input b_tvalid, output b_tready,
    input c_tlast, input c_tvalid, output c_tready,
    output p_tlast, output p_tvalid, input p_tready,
    output [LATENCY-3:0] enables_a,
    output [LATENCY-3:0] enables_b,
    output enable_c,
    output enable_m,
    output enable_p);
   
   wire 			  join_tlast, join_tvalid, join_tready;
   wire 			  join1_tlast, join1_tvalid, join1_tready;
   wire 			  int0_tlast, int0_tvalid, int0_tready;
   wire 			  int1_tlast, int1_tvalid, int1_tready;
   wire 			  int2_tlast, int2_tvalid, int2_tready;
   wire 			  int3_tlast, int3_tvalid, int3_tready;
   
   axi_pipe #(.STAGES(LATENCY-2)) pipe_a
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(a_tlast), .i_tvalid(a_tvalid), .i_tready(a_tready),
      .o_tlast(int0_tlast), .o_tvalid(int0_tvalid), .o_tready(int0_tready),
      .enables(enables_a), .valids());
   
   axi_pipe #(.STAGES(LATENCY-2)) pipe_b
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(b_tlast), .i_tvalid(b_tvalid), .i_tready(b_tready),
      .o_tlast(int1_tlast), .o_tvalid(int1_tvalid), .o_tready(int1_tready),
      .enables(enables_b), .valids());
   
   axi_join #(.INPUTS(2)) join_ab
     (.i_tlast({int1_tlast,int0_tlast}), .i_tvalid({int1_tvalid,int0_tvalid}), .i_tready({int1_tready,int0_tready}),
      .o_tlast(join_tlast), .o_tvalid(join_tvalid), .o_tready(join_tready));
   
   axi_pipe #(.STAGES(1)) pipe_m
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(join_tlast), .i_tvalid(join_tvalid), .i_tready(join_tready),
      .o_tlast(int2_tlast), .o_tvalid(int2_tvalid), .o_tready(int2_tready),
      .enables(enable_m), .valids());

   // If we use the cascade input, there is no flop in the input side adder
   generate
      if(CASCADE_IN)
	begin
	   assign int3_tlast = c_tlast;
	   assign int3_tvalid = c_tvalid;
	   assign c_tready = int3_tready;
	   assign enable_c = 1'b0;
	end
      else
	axi_pipe #(.STAGES(1)) pipe_c
	  (.clk(clk), .reset(reset), .clear(clear),
	   .i_tlast(c_tlast), .i_tvalid(c_tvalid), .i_tready(c_tready),
	   .o_tlast(int3_tlast), .o_tvalid(int3_tvalid), .o_tready(int3_tready),
	   .enables(enable_c), .valids());
   endgenerate
   
   axi_join #(.INPUTS(2)) joiner_mc
     (.i_tlast({int2_tlast,int3_tlast}), .i_tvalid({int2_tvalid,int3_tvalid}), .i_tready({int2_tready,int3_tready}),
      .o_tlast(join1_tlast), .o_tvalid(join1_tvalid), .o_tready(join1_tready));
   
   axi_pipe #(.STAGES(1)) pipe_p
     (.clk(clk), .reset(reset), .clear(clear),
      .i_tlast(join1_tlast), .i_tvalid(join1_tvalid), .i_tready(join1_tready),
      .o_tlast(p_tlast), .o_tvalid(p_tvalid), .o_tready(p_tready),
      .enables(enable_p), .valids());
   
endmodule // axi_pipe_mac
module conj
  #(parameter WIDTH=16)
   (input clk, input reset, input clear,
    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);

   assign o_tdata = { i_tdata[2*WIDTH-1:WIDTH] , -i_tdata[WIDTH-1:0] };
   assign o_tlast = i_tlast;
   assign o_tvalid = i_tvalid;
   assign i_tready = o_tready;
   
endmodule // conj
module axi_repeat
#(
  parameter WIDTH = 16) 
(
  input clk, input reset,
  input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output reg [WIDTH-1:0] o_tdata, output reg o_tlast, output reg o_tvalid, input o_tready
);

  assign i_tready = 1'b1;

  always @(posedge clk) begin
    if (reset) begin
      o_tdata  <= 'd0;
      o_tlast  <= 'd0;
      o_tvalid <= 'd0;
    end else begin
      if (i_tvalid) begin
        o_tvalid <= 1'b1;
        o_tlast  <= i_tlast;
        o_tdata  <= o_tdata;
      end
    end
  end

endmodule
module phase_accum #(
  parameter REVERSE_ROTATION = 0, // Negate phase increment value
  parameter WIDTH_ACCUM = 16,
  parameter WIDTH_IN = 16,
  parameter WIDTH_OUT = 16)
(
  input clk, input reset, input clear,
  input [WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  reg signed [WIDTH_ACCUM-1:0] accum, accum_next, phase_inc;
  // Scaled radians. Restrict range from +1 to -1.
  wire signed [WIDTH_ACCUM-1:0] POS_ROLLOVER = 2**(WIDTH_ACCUM-3);
  wire signed [WIDTH_ACCUM-1:0] NEG_ROLLOVER = -(2**(WIDTH_ACCUM-3));

  wire [WIDTH_OUT-1:0] output_round_tdata;
  wire output_round_tvalid, output_round_tready, output_round_tlast;

  // Phase accumulator, can rotate in either direction
  always @(posedge clk) begin
    if (reset | clear) begin
      accum      <= 'd0;
      accum_next <= 'd0;
      phase_inc  <= 'd0;
    end else if (i_tready & i_tvalid) begin
      if (i_tlast) begin
        accum       <= {WIDTH_ACCUM{1'b0}};
        accum_next  <= REVERSE_ROTATION ? -$signed(i_tdata) : $signed(i_tdata);
        phase_inc   <= REVERSE_ROTATION ? -$signed(i_tdata) : $signed(i_tdata);
      end else begin
        if (accum_next >= POS_ROLLOVER) begin
          accum_next <= accum_next + phase_inc - 2*POS_ROLLOVER;
          accum      <= accum + phase_inc - 2*POS_ROLLOVER;
        end else if (accum_next <= NEG_ROLLOVER) begin
          accum_next <= accum_next + phase_inc - 2*NEG_ROLLOVER;
          accum      <= accum + phase_inc - 2*NEG_ROLLOVER;
        end else begin
          accum_next <= accum_next + phase_inc;
          accum      <= accum + phase_inc;
        end
      end
    end
  end

  generate
    // Bypass rounding if accumulator width is same as output width
    if (WIDTH_ACCUM == WIDTH_OUT) begin
      assign o_tdata  = accum;
      assign o_tvalid = i_tvalid;
      assign o_tlast  = i_tlast;
      assign i_tready = o_tready;
    end else begin
      axi_round #(
        .WIDTH_IN(WIDTH_ACCUM),
        .WIDTH_OUT(WIDTH_OUT))
      axi_round (
        .clk(clk), .reset(reset),
        .i_tdata(accum), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
        .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));
    end
  endgenerate

endmodule
module biquad_filter_impl #(
  parameter DATA_W      = 16,
  parameter COEFF_W     = 16,
  parameter FEEDBACK_W  = 25,
  parameter FF_HEADROOM = 2,
  parameter FB_HEADROOM = 2
)(
  input  wire                      clk,
  input  wire                      reset,
  input  wire        [6:0]         chain_en,
  input  wire signed [COEFF_W-1:0] set_b0,
  input  wire signed [COEFF_W-1:0] set_b1,
  input  wire signed [COEFF_W-1:0] set_b2,
  input  wire signed [COEFF_W-1:0] set_a1,
  input  wire signed [COEFF_W-1:0] set_a2,
  input  wire signed [DATA_W-1:0]  data_in,
  output reg  signed [DATA_W-1:0]  data_out
);

  localparam FF_PROD_W  = DATA_W + COEFF_W - 1;       // Feedforward product width (signed multiply)
  localparam FF_SUM_W   = FF_PROD_W + FF_HEADROOM;    // Feedforward sum width (3 term add)
  localparam FB_PROD_W  = FEEDBACK_W + COEFF_W - 1;   // Feedback product width (signed multiply)
  localparam FB_SUM_W   = FB_PROD_W + FB_HEADROOM;    // Feedback sum width (3 term add) 

  reg  signed [DATA_W-1:0]      reg_x0 = 0, reg_x1 = 0, reg_x2 = 0;
  reg  signed [FF_PROD_W-1:0]   reg_b0x0 = 0, reg_b1x1 = 0, reg_b2x2 = 0, reg_b2x2_del = 0;
  reg  signed [FF_SUM_W-1:0]    reg_ffsum_0 = 0, reg_ffsum_1 = 0;
  wire signed [FB_PROD_W-1:0]   prod_yxa1, prod_yxa2;
  reg  signed [FB_SUM_W-1:0]    reg_fb_sum0 = 0, reg_fb_sum1 = 0;
  wire signed [FEEDBACK_W-1:0]  fb_sum1_trunc;
  wire signed [DATA_W-1:0]      out_rnd;

  always @(posedge clk) begin
    if (reset) begin
      {reg_x2, reg_x1, reg_x0} <= 0;
      reg_b0x0 <= 0;
      reg_b1x1 <= 0;
      reg_b2x2 <= 0;
      reg_b2x2_del <= 0;
      reg_ffsum_0 <= 0;
      reg_ffsum_1 <= 0;
      reg_fb_sum0 <= 0;
      reg_fb_sum1 <= 0;
      data_out <= 0;
    end else begin
      if (chain_en[0]) begin
        // Input pipeline register and delay line
        {reg_x2, reg_x1, reg_x0} <= {reg_x1, reg_x0, data_in};
      end
      if (chain_en[1]) begin
        // Feedforward products
        reg_b0x0 <= reg_x0 * set_b0;
        reg_b1x1 <= reg_x1 * set_b1;
        reg_b2x2 <= reg_x2 * set_b2;
        reg_b2x2_del <= reg_b2x2;
      end
      // Feedforward sums (in two pipelined stages)
      if (chain_en[2]) begin
        reg_ffsum_0 <= reg_b0x0 + reg_b1x1;
      end
      if (chain_en[3]) begin
        reg_ffsum_1 <= reg_ffsum_0 + reg_b2x2_del;
      end
      // Feedback sums (in two pipelined stages)
      if (chain_en[4]) begin
        reg_fb_sum0 <= (reg_ffsum_1 <<< (FB_SUM_W-FF_SUM_W-FB_HEADROOM)) + prod_yxa2;
      end
      if (chain_en[5]) begin
        reg_fb_sum1 <= reg_fb_sum0 + prod_yxa1;
      end
      if (chain_en[6]) begin
        // Output pipeline register
        data_out <= out_rnd;
      end
    end
  end
  // Feedback products
  assign prod_yxa1 = fb_sum1_trunc * set_a1;
  assign prod_yxa2 = fb_sum1_trunc * set_a2;
  // Truncate feedback
  assign fb_sum1_trunc = (reg_fb_sum1 >>> (FB_SUM_W-FEEDBACK_W-FB_HEADROOM));

  round #(
    .bits_in(FB_SUM_W-FB_HEADROOM-FF_HEADROOM), .bits_out(DATA_W)
  ) round_i (
    .in(reg_fb_sum1[FB_SUM_W-FB_HEADROOM-FF_HEADROOM-1:0]), .out(out_rnd), .err()
  );

endmodule // biquad_filter_impl
module datapath_gatekeeper #(
  parameter WIDTH   = 64,
  parameter COUNT_W = 16
)(
  // Clocks and resets
  input  wire               clk,
  input  wire               reset,
  // Input data stream      
  input  wire [WIDTH-1:0]   s_axis_tdata,
  input  wire               s_axis_tlast,
  input  wire               s_axis_tvalid,
  output wire               s_axis_tready,
  // Output data stream     
  output wire [WIDTH-1:0]   m_axis_tdata,
  output wire               m_axis_tlast,
  output wire               m_axis_tvalid,
  input  wire               m_axis_tready,
  // Settings and Status
  input  wire               flush,          // Drop all packets coming into module
  output wire               flushing,       // Is the module still dropping packets?
  output wire [COUNT_W-1:0] pkt_count       // Input packet counter (includes drops)
);

  axis_strm_monitor #(
    .WIDTH(1), .COUNT_W(COUNT_W),
    .PKT_LENGTH_EN(0), .PKT_CHKSUM_EN(0),
    .PKT_COUNT_EN(1), .XFER_COUNT_EN(0)
  ) monitor_i (
    .clk(clk), .reset(reset),
    .axis_tdata(1'b0), .axis_tlast(s_axis_tlast),
    .axis_tvalid(s_axis_tvalid), .axis_tready(s_axis_tready),
    .sop(), .eop(),
    .pkt_length(), .pkt_chksum(),
    .pkt_count(pkt_count), .xfer_count()
  );

  axis_packet_flush #(
    .WIDTH(WIDTH), .FLUSH_PARTIAL_PKTS(0)
  ) flusher_i (
    .clk(clk), .reset(reset),
    .enable(flush), .flushing(flushing),
    .s_axis_tdata(s_axis_tdata), .s_axis_tlast(s_axis_tlast),
    .s_axis_tvalid(s_axis_tvalid), .s_axis_tready(s_axis_tready),
    .m_axis_tdata(m_axis_tdata), .m_axis_tlast(m_axis_tlast),
    .m_axis_tvalid(m_axis_tvalid), .m_axis_tready(m_axis_tready)
  );

endmodule
module axi_packer #(
  parameter WIDTH_IN          = 8,   // Input bit width
  parameter WIDTH_OUT         = 32,  // Output bit width
  parameter REVERSE           = 0)   // 0: Fill LSB to MSB, 1: Fill MSB to LSB
(
  input clk, input reset, input clear,
  input [WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  localparam M = WIDTH_OUT/WIDTH_IN;

  reg packed_tlast, packed_tvalid;
  reg [WIDTH_OUT-1:0] packed_tdata;
  reg [$clog2(M)-1:0] cnt;
  reg i_tlast_hold;
  integer i;
  always @(posedge clk) begin
    if (reset | clear) begin
      i_tlast_hold      <= 1'b0;
      cnt               <= 'd0;
      packed_tdata      <= 'd0;
      packed_tvalid     <= 1'b0;
      packed_tlast      <= 1'b0;
    end else begin
      packed_tvalid     <= 1'b0;
      packed_tlast      <= 1'b0;
      if (i_tvalid & i_tready) begin
        if (i_tlast) begin
          i_tlast_hold  <= 1'b1;
        end
        if (cnt > M-1) begin
          cnt           <= 'd0;
          packed_tlast  <= i_tlast_hold;
          packed_tvalid <= 1'b1;
        end else begin
          cnt           <= cnt + 1;
        end
        if (REVERSE) begin
          packed_tdata[WIDTH_OUT-1:WIDTH_OUT-WIDTH_IN] <= i_tdata;
          for (i = 0; i < M-1; i = i + 1) begin
            packed_tdata[WIDTH_OUT-(i+1)*WIDTH_IN-1 -: WIDTH_IN] <= packed_tdata[WIDTH_OUT-i*WIDTH_IN-1 -: WIDTH_IN];
          end
        end else begin
          packed_tdata[WIDTH_IN-1:0] <= i_tdata;
          for (i = 0; i < M-1; i = i + 1) begin
            packed_tdata[(i+2)*WIDTH_IN-1 -: WIDTH_IN] <= packed_tdata[(i+1)*WIDTH_IN-1 -: WIDTH_IN];
          end
        end
      end
    end
  end

  axi_fifo_flop #(.WIDTH(WIDTH_OUT+1)) axi_fifo_flop_pack (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({packed_tlast,packed_tdata}), .i_tvalid(packed_tvalid), .i_tready(i_tready),
    .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .space(), .occupied());

endmodule
module axi_round_complex #(
  parameter WIDTH_IN  = 24,
  parameter WIDTH_OUT = 16,
  parameter FIFOSIZE  = 0)  // leave at 0 for a normal single flop
(
  input clk, input reset,
  input [2*WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [2*WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  wire [WIDTH_IN-1:0]  ii_tdata, iq_tdata;
  wire                 ii_tlast, ii_tvalid, ii_tready, iq_tlast, iq_tvalid, iq_tready;

  wire [WIDTH_OUT-1:0] oi_tdata, oq_tdata;
  wire                 oi_tlast, oi_tvalid, oi_tready, oq_tlast, oq_tvalid, oq_tready;

  split_complex #(.WIDTH(WIDTH_IN)) split_complex (
    .i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .oi_tdata(ii_tdata), .oi_tlast(ii_tlast), .oi_tvalid(ii_tvalid), .oi_tready(ii_tready),
    .oq_tdata(iq_tdata), .oq_tlast(iq_tlast), .oq_tvalid(iq_tvalid), .oq_tready(iq_tready));

  axi_round #(.WIDTH_IN(WIDTH_IN), .WIDTH_OUT(WIDTH_OUT), .FIFOSIZE(FIFOSIZE)) axi_round_i (
    .clk(clk), .reset(reset),
    .i_tdata(ii_tdata), .i_tlast(ii_tlast), .i_tvalid(ii_tvalid), .i_tready(ii_tready),
    .o_tdata(oi_tdata), .o_tlast(oi_tlast), .o_tvalid(oi_tvalid), .o_tready(oi_tready));

  axi_round #(.WIDTH_IN(WIDTH_IN), .WIDTH_OUT(WIDTH_OUT), .FIFOSIZE(FIFOSIZE)) axi_round_q (
    .clk(clk), .reset(reset),
    .i_tdata(iq_tdata), .i_tlast(iq_tlast), .i_tvalid(iq_tvalid), .i_tready(iq_tready),
    .o_tdata(oq_tdata), .o_tlast(oq_tlast), .o_tvalid(oq_tvalid), .o_tready(oq_tready));

  join_complex #(.WIDTH(WIDTH_OUT)) join_complex (
    .ii_tdata(oi_tdata), .ii_tlast(oi_tlast), .ii_tvalid(oi_tvalid), .ii_tready(oi_tready),
    .iq_tdata(oq_tdata), .iq_tlast(oq_tlast), .iq_tvalid(oq_tvalid), .iq_tready(oq_tready),
    .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));

endmodule
module cmul
  (input clk, input reset,
   input [31:0] a_tdata, input a_tlast, input a_tvalid, output a_tready,
   input [31:0] b_tdata, input b_tlast, input b_tvalid, output b_tready,
   output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   complex_multiplier complex_multiplier
     (.aclk(clk), .aresetn(~reset),
      .s_axis_a_tdata({a_tdata[15:0], a_tdata[31:16]}), .s_axis_a_tlast(a_tlast), .s_axis_a_tvalid(a_tvalid), .s_axis_a_tready(a_tready),
      .s_axis_b_tdata({b_tdata[15:0], b_tdata[31:16]}), .s_axis_b_tlast(b_tlast), .s_axis_b_tvalid(b_tvalid), .s_axis_b_tready(b_tready),
      .s_axis_ctrl_tdata(8'd0), .s_axis_ctrl_tvalid(1'b1), .s_axis_ctrl_tready(),
      .m_axis_dout_tdata({o_tdata[31:0], o_tdata[63:32]}), .m_axis_dout_tlast(o_tlast), .m_axis_dout_tvalid(o_tvalid), .m_axis_dout_tready(o_tready));

endmodule // cmul
module keep_one_in_n #(
  parameter KEEP_FIRST=0,  // 0: Drop n-1 words then keep last word, 1: Keep 1st word then drop n-1
  parameter WIDTH=16,
  parameter MAX_N=65535
)(
  input clk, input reset,
  input vector_mode,
  input [$clog2(MAX_N+1)-1:0] n,
  input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
  output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  reg [$clog2(MAX_N+1)-1:0] sample_cnt, pkt_cnt, n_reg;
  reg n_changed;

  always @(posedge clk) begin
    if (reset) begin
       n_reg      <= 1;
       n_changed  <= 1'b0;
    end else begin
      n_reg       <= n;
      if (n_reg != n) begin
        n_changed <= 1'b1;
      end else begin
        n_changed <= 1'b0;
      end
    end
  end

  wire on_last_sample  = ( (sample_cnt >= n_reg) | (n_reg == 0) );
  wire on_first_sample = ( (sample_cnt == 1)     | (n_reg == 0) );
  wire on_last_pkt     = ( (pkt_cnt >= n_reg)    | (n_reg == 0) );
  wire on_first_pkt    = ( (pkt_cnt == 1)        | (n_reg == 0) );

  always @(posedge clk) begin
    if (reset | n_changed) begin
       sample_cnt <= 1;
       pkt_cnt    <= 1;
    end else begin
      if (i_tvalid & i_tready) begin
        if (on_last_sample) begin
          sample_cnt <= 1;
        end else begin
          sample_cnt <= sample_cnt + 1'd1;
        end
      end
      if (i_tvalid & i_tready & i_tlast) begin
        if (on_last_pkt) begin
          pkt_cnt <= 1;
        end else begin
          pkt_cnt <= pkt_cnt + 1'd1;
        end
      end
    end
  end

  assign i_tready = o_tready | (vector_mode ? (KEEP_FIRST ? ~on_first_pkt    : ~on_last_pkt) :
                                              (KEEP_FIRST ? ~on_first_sample : ~on_last_sample));
  assign o_tvalid = i_tvalid & (vector_mode ? (KEEP_FIRST ?  on_first_pkt    :  on_last_pkt) :
                                              (KEEP_FIRST ?  on_first_sample :  on_last_sample));
  assign o_tdata  = i_tdata;
  assign o_tlast  = i_tlast  & (vector_mode ? 1'b1 : on_last_pkt);

endmodule // keep_one_in_n_vec
module axi_round_and_clip_complex
  #(parameter WIDTH_IN=24,
    parameter WIDTH_OUT=16,
    parameter CLIP_BITS=3,
    parameter FIFOSIZE=1)  // FIFOSIZE = 1, single output register
   (input clk, input reset,
    input [2*WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [2*WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   wire [WIDTH_IN-1:0]      ii_tdata, iq_tdata;
   wire                     ii_tlast, ii_tvalid, ii_tready, iq_tlast, iq_tvalid, iq_tready;

   wire [WIDTH_OUT-1:0]     oi_tdata, oq_tdata;
   wire                     oi_tlast, oi_tvalid, oi_tready, oq_tlast, oq_tvalid, oq_tready;

   split_complex #(.WIDTH(WIDTH_IN)) split
     (.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
      .oi_tdata(ii_tdata), .oi_tlast(ii_tlast), .oi_tvalid(ii_tvalid), .oi_tready(ii_tready),
      .oq_tdata(iq_tdata), .oq_tlast(iq_tlast), .oq_tvalid(iq_tvalid), .oq_tready(iq_tready));

   axi_round_and_clip #(.WIDTH_IN(WIDTH_IN), .WIDTH_OUT(WIDTH_OUT), .CLIP_BITS(CLIP_BITS), .FIFOSIZE(FIFOSIZE)) r_and_c_i
     (.clk(clk), .reset(reset),
      .i_tdata(ii_tdata), .i_tlast(ii_tlast), .i_tvalid(ii_tvalid), .i_tready(ii_tready),
      .o_tdata(oi_tdata), .o_tlast(oi_tlast), .o_tvalid(oi_tvalid), .o_tready(oi_tready));

   axi_round_and_clip #(.WIDTH_IN(WIDTH_IN), .WIDTH_OUT(WIDTH_OUT), .CLIP_BITS(CLIP_BITS), .FIFOSIZE(FIFOSIZE)) r_and_c_q
     (.clk(clk), .reset(reset),
      .i_tdata(iq_tdata), .i_tlast(iq_tlast), .i_tvalid(iq_tvalid), .i_tready(iq_tready),
      .o_tdata(oq_tdata), .o_tlast(oq_tlast), .o_tvalid(oq_tvalid), .o_tready(oq_tready));
   
   join_complex #(.WIDTH(WIDTH_OUT)) join_complex
     (.ii_tdata(oi_tdata), .ii_tlast(oi_tlast), .ii_tvalid(oi_tvalid), .ii_tready(oi_tready),
      .iq_tdata(oq_tdata), .iq_tlast(oq_tlast), .iq_tvalid(oq_tvalid), .iq_tready(oq_tready),
      .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));

endmodule // round_and_clip_complex
module const_sreg
  #(parameter BASE=0,
    parameter WIDTH=32)
   (input clk, input reset,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,
    output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   wire [WIDTH-1:0]     const_val;
   
   setting_reg #(.my_addr(BASE), .width(WIDTH)) reg_max
     (.clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data), .out(const_val));

   assign o_tdata = const_val;
   assign o_tlast = 1'b0; // FIXME do we want something else here?
   assign o_tvalid = 1'b1; // caution -- will fill up a fifo
   
endmodule // const_sreg
module addsub
  #(parameter WIDTH = 16)
   (input clk, input reset,
    input [WIDTH*2-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
    input [WIDTH*2-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
    output [WIDTH*2-1:0] sum_tdata, output sum_tlast, output sum_tvalid, input sum_tready,
    output [WIDTH*2-1:0] diff_tdata, output diff_tlast, output diff_tvalid, input diff_tready);

   wire [WIDTH*4-1:0] 	 dummy;
   wire [WIDTH*4-1:0] 	 int_tdata;
   wire 		 int_tlast, int_tvalid, int_tready;

   assign int_tvalid = i0_tvalid & i1_tvalid;
   assign i0_tready = int_tvalid & int_tready;
   assign i1_tready = int_tvalid & int_tready;

   wire [WIDTH-1:0] 	 sum_a = i0_tdata[WIDTH*2-1:WIDTH] + i1_tdata[WIDTH*2-1:WIDTH];
   wire [WIDTH-1:0] 	 diff_a = i0_tdata[WIDTH*2-1:WIDTH] - i1_tdata[WIDTH*2-1:WIDTH];
   
   wire [WIDTH-1:0] 	 sum_b = i0_tdata[WIDTH-1:0] + i1_tdata[WIDTH-1:0];
   wire [WIDTH-1:0] 	 diff_b = i0_tdata[WIDTH-1:0] - i1_tdata[WIDTH-1:0];

   assign int_tdata = { sum_a,sum_b,diff_a,diff_b };
   assign int_tlast = i0_tlast;  // Follow first input.
   
   split_stream_fifo #(.WIDTH(4*WIDTH), .ACTIVE_MASK(4'b0011)) splitter
     (.clk(clk), .reset(reset), .clear(1'b0),
      .i_tdata(int_tdata), .i_tlast(int_tlast), .i_tvalid(int_tvalid), .i_tready(int_tready),
      .o0_tdata({sum_tdata,dummy[WIDTH*2-1:0]}), .o0_tlast(sum_tlast), .o0_tvalid(sum_tvalid), .o0_tready(sum_tready),
      .o1_tdata({dummy[WIDTH*4-1:WIDTH*2],diff_tdata}), .o1_tlast(diff_tlast), .o1_tvalid(diff_tvalid), .o1_tready(diff_tready),
      .o2_tready(1'b1), .o3_tready(1'b1));
   
endmodule // addsub
module file_sink #(
  parameter SR_SWAP_SAMPLES        = 0, // 0: Do nothing, 1: 8-bit swap, 2: 16-bit, 3: 32-bit
  parameter SR_ENDIANNESS          = 1, // 0: Do nothing, 1: 16-bit boundary, 2: 32-bit
  // Default (after reset) values for above settings register set to sc16 (reverse endianess on
  parameter DEFAULT_SWAP_SAMPLES   = 2,
  parameter DEFAULT_ENDIANNESS     = 2,
  parameter FILENAME = "")
(
  input clk_i,
  input rst_i,

  input set_stb_i,
  input [7:0] set_addr_i,
  input [31:0] set_data_i,

  input  [63:0] i_tdata,
  input  i_tlast,
  input  i_tvalid,
  output i_tready);

  integer file = 0;
  reg hdr = 1'b1;

  wire [1:0] swap_samples;
  wire [1:0] endianness;

  wire [63:0] data_int;
  wire [63:0] data;

  setting_reg #(
    .my_addr(SR_SWAP_SAMPLES),
    .width(2),
    .at_reset(DEFAULT_SWAP_SAMPLES))
  sr_swap_samples (
    .clk(clk_i),
    .rst(rst_i),
    .strobe(set_stb_i),
    .addr(set_addr_i),
    .in(set_data_i),
    .out(swap_samples),
    .changed());

  setting_reg #(
    .my_addr(SR_ENDIANNESS),
    .width(2),
    .at_reset(DEFAULT_ENDIANNESS))
  sr_endianness (
    .clk(clk_i),
    .rst(rst_i),
    .strobe(set_stb_i),
    .addr(set_addr_i),
    .in(set_data_i),
    .out(endianness),
    .changed());

  // We're ready as soon as the file is open
  assign i_tready = (file == 0) ? 1'b0 : 1'b1;

  // Swap samples
  assign data_int = (swap_samples == 2'd0) ?  i_tdata :
                    (swap_samples == 2'd1) ? {i_tdata[55:48], i_tdata[63:56], i_tdata[39:32], i_tdata[47:40],
                                              i_tdata[23:16], i_tdata[31:24], i_tdata[ 7: 0], i_tdata[15: 8]} :
                    (swap_samples == 2'd2) ? {i_tdata[47:32], i_tdata[63:48], i_tdata[15: 0], i_tdata[31:16]} :
                    (swap_samples == 2'd3) ? {i_tdata[31:0], i_tdata[63:32]} :
                                              64'd0;

  // Swap endianness
  assign data = (endianness == 2'd0) ?  data_int :
                (endianness == 2'd1) ? {data_int[47:32], data_int[63:48], data_int[15: 0], data_int[31:16]} :
                (endianness == 2'd2) ? {data_int[39:32], data_int[47:40], data_int[55:48], data_int[63:56],
                                        data_int[ 7: 0], data_int[15: 8], data_int[23:16], data_int[31:24]} :
                                        64'd0;

  initial begin
    if (FILENAME != "") begin
      file = $fopen(FILENAME, "wb");
      if(!file)
        $error("Could not open file sink.");
      $display("File sink ready.");
    end
  end

  always @(posedge clk_i) begin
    if(rst_i) begin
      hdr <= 1'b1;
    end
    else begin
      if(i_tvalid) begin
        if(hdr) begin
          hdr <= 1'b0;
        end
        else begin
          $fwrite(file, "%u", data);
        end
      end

      if(i_tlast) begin
        hdr <= 1'b1;
      end
    end
  end

endmodule
module axi_round
  #(parameter WIDTH_IN=17,
    parameter WIDTH_OUT=16,
    parameter round_to_zero=0,       // original behavior
    parameter round_to_nearest=1,    // lowest noise
    parameter trunc=0,               // round to negative infinity
    parameter FIFOSIZE=0)  // leave at 0 for a normal single flop
   (input clk, input reset,
    input [WIDTH_IN-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [WIDTH_OUT-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

  wire [WIDTH_OUT-1:0] out;

  generate
    if (WIDTH_IN == WIDTH_OUT) begin
      assign o_tdata = i_tdata;
      assign o_tlast = i_tlast;
      assign o_tvalid = i_tvalid;
      assign i_tready = o_tready;
    end else begin
      wire round_corr,round_corr_trunc,round_corr_rtz,round_corr_nearest,round_corr_nearest_safe;
      wire [WIDTH_IN-WIDTH_OUT-1:0] err;

      assign round_corr_trunc = 0;
      assign round_corr_rtz = (i_tdata[WIDTH_IN-1] & |i_tdata[WIDTH_IN-WIDTH_OUT-1:0]);
      assign round_corr_nearest = i_tdata[WIDTH_IN-WIDTH_OUT-1];

      assign round_corr_nearest_safe =  (WIDTH_IN-WIDTH_OUT > 1) ? 
                                        ((~i_tdata[WIDTH_IN-1] & (&i_tdata[WIDTH_IN-2:WIDTH_IN-WIDTH_OUT])) ? 1'b0 : round_corr_nearest) :
                                        round_corr_nearest;

      assign round_corr = round_to_nearest ? round_corr_nearest_safe :
                          trunc ? round_corr_trunc : 
                          round_to_zero ? round_corr_rtz :
                          0;  // default to trunc

      assign out = i_tdata[WIDTH_IN-1:WIDTH_IN-WIDTH_OUT] + round_corr;

      assign err = i_tdata - {out,{(WIDTH_IN-WIDTH_OUT){1'b0}}};

      axi_fifo #(.WIDTH(WIDTH_OUT+1), .SIZE(FIFOSIZE)) flop
        (.clk(clk), .reset(reset), .clear(1'b0),
         .i_tdata({i_tlast, out}), .i_tvalid(i_tvalid), .i_tready(i_tready),
         .o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
         .occupied(), .space());

   end
  endgenerate

endmodule // axi_round