dakies/OSS_Verilog huggingface dataset:
module cvita_dechunker # (
   parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
) (
   input          clk,
   input          reset,
   input          clear,
   input [15:0]   frame_size,

   input [63:0]   i_tdata,
   input          i_tvalid,
   output         i_tready,
   
   output [63:0]  o_tdata,
   output         o_tlast,
   output         o_tvalid,
   input          o_tready,

   output         error
);

   localparam ST_HEADER  = 2'd0;
   localparam ST_DATA    = 2'd1;
   localparam ST_PADDING = 2'd2;
   localparam ST_ERROR   = 2'd3;

   reg [1:0]   state;
   reg [15:0]  frame_rem, pkt_rem;
   wire        i_tlast;

   wire [15:0] cvita_len_ceil = i_tdata[47:32] + 7;
   wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]};

   always @(posedge clk) begin
      if (reset | clear) begin
         state <= ST_HEADER;
         frame_rem <= 16'd0;
         pkt_rem   <= 16'd0;
      end else if (i_tvalid & i_tready) begin
         case (state)
            ST_HEADER: begin
               if (axi_len > frame_size)
                  state <= ST_ERROR;
               else if (~o_tlast)
                  state <= ST_DATA;
               else
                  state <= ST_PADDING;
                  
               frame_rem <= frame_size - 16'd1;
               pkt_rem   <= axi_len - 16'd1;
            end
         
            ST_DATA: begin
               if (o_tlast) begin
                  state   <= i_tlast ? ST_HEADER : ST_PADDING;
                  pkt_rem <= 16'd0;
               end else begin
                  state   <= ST_DATA;
                  pkt_rem <= pkt_rem - 16'd1;
               end
               frame_rem <= frame_rem - 16'd1;
            end

            ST_PADDING: begin
               if (i_tlast) begin
                  state   <= ST_HEADER;
                  frame_rem <= 16'd0;
               end else begin
                  state   <= ST_PADDING;
                  frame_rem <= frame_rem - 16'd1;
               end
            end
         endcase   
      end   
   end
   
   assign i_tready = o_tready | (state == ST_PADDING);
   assign i_tlast = (frame_rem == 16'd1); //Temp signal
   
   assign o_tvalid = i_tvalid & (state != ST_PADDING);
   assign o_tlast = (pkt_rem != 0) ? (pkt_rem == 16'd1) : (axi_len == 16'd1);
   assign o_tdata  = i_tdata;
   
   assign error = (state == ST_ERROR);

endmodule // cvita_dechunker
module fix_short_packet
  (input clk, input reset, input clear,
   input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
   output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   reg [12:0] 	 lines_left;

   reg [1:0] 	 state;
   localparam ST_CHDR =   2'd0;
   localparam ST_PACKET = 2'd1;
   localparam ST_DUMP =   2'd2;
   
   wire 	 lastline = (lines_left == 0);
   wire [12:0] 	 packet_length = i_tdata[47:35] + (|i_tdata[34:32]);
   
   always @(posedge clk)
     if(reset | clear)
       begin
	  state <= ST_CHDR;
	  lines_left <= 13'd0;
       end
     else
       if(i_tvalid & i_tready)
	 case(state)
	   ST_CHDR :
	     if((packet_length == 1) && ~i_tlast)  // First line is valid, dump rest
	       state <= ST_DUMP;
	     else
	       begin
		  lines_left <= packet_length - 2;
		  state <= ST_PACKET;
	       end
	   
	   ST_PACKET :
	     if(lastline & ~i_tlast)
	       state <= ST_DUMP;
	     else if(i_tlast)
	       state <= ST_CHDR;
	     else
	       lines_left <= lines_left - 1;
	   
	   ST_DUMP :
	     if(i_tlast)
	       state <= ST_CHDR;
	 endcase // case (state)
   
   assign o_tdata = i_tdata;
   assign o_tlast = i_tlast | ((state == ST_CHDR) & (packet_length == 1)) | ((state == ST_PACKET) & lastline);
   assign o_tvalid = i_tvalid & (state != ST_DUMP);

   assign i_tready = o_tready | (state == ST_DUMP);
   
endmodule // fix_short_packet
module cvita_insert_tlast_tb();

   reg clk    = 0;
   reg reset  = 1;
   
   always #10 clk = ~clk;
   
   initial $dumpfile("cvita_insert_tlast_tb.vcd");
   initial $dumpvars(0,cvita_insert_tlast_tb);

   task send_packet;
      input [63:0] data_start;
      input [31:0] len;
      
      begin
	 if(len < 9)
	   begin
	      {i_tlast, i_tdata} <= { 1'b1, data_start[63:48],len[15:0], data_start[31:0] };
	      i_tvalid <= 1;
	      @(posedge clk);
	      i_tvalid <= 0;
	   end
	 else
	   begin
	      {i_tlast, i_tdata} <= { 1'b0, data_start[63:48],len[15:0], data_start[31:0] };
	      i_tvalid <= 1;
	      @(posedge clk);
	      repeat(((len-2)/2)-1+len[0])
		begin
		   i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
		   @(posedge clk);
		end
	      i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
	      i_tlast <= 1;
	      @(posedge clk);
	      i_tvalid <= 1'b0;
	   end // else: !if(len < 3)
      end
   endtask // send_packet
   
   initial
     begin
	#1000 reset = 0;
	#200000;
	$finish;
     end
   
   reg [63:0] i_tdata;
   reg 	      i_tlast;
   reg 	      i_tvalid;
   wire       i_tready;

   wire [63:0] o_tdata;
   wire        o_tlast, o_tvalid, o_tready, o_tlast_regen;
   
   initial
     begin
	i_tvalid <= 0;
	
	while(reset)
	  @(posedge clk);
	@(posedge clk);

	send_packet(64'hA0000000_A0000001, 24);
	send_packet(64'hA0000000_A0000001, 20);
	send_packet(64'hA0000000_A0000001, 16);
	send_packet(64'hA0000000_A0000001, 12);
	send_packet(64'hA0000000_A0000001, 8);
	send_packet(64'hA0000000_A0000001, 4);
	send_packet(64'hA0000000_A0000001, 4);
	send_packet(64'hA0000000_A0000001, 8);
	send_packet(64'hA0000000_A0000001, 12);
     end // initial begin

   cvita_insert_tlast dut
     (.clk(clk), .reset(reset), .clear(1'b0),
      .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
      .o_tdata(o_tdata), .o_tlast(o_tlast_regen), .o_tvalid(o_tvalid), .o_tready(o_tready));

   assign o_tready = 1;
   

   always @(posedge clk)
     if(o_tvalid & o_tready)
       begin
	  $display ("TLAST %x\t TLAST_REGEN %x",i_tlast, o_tlast_regen);
	  if(i_tlast != o_tlast_regen)
	    $display("ERROR!!!!!!");
       end
endmodule // cvita_insert_tlast_tb
module axis_to_cvita
(
        input wire           clk,

	input wire [63:0]    s_axis_tdata,
        input wire           s_axis_tlast,
        input wire           s_axis_tvalid,
        output wire          s_axis_tready,

	output wire [63:0]   o_tdata,
        output wire          o_tlast,
        output wire          o_tvalid,
        input wire           o_tready
);

	assign s_axis_tready = o_tready;

	assign o_tdata = {s_axis_tdata[31:0], s_axis_tdata[63:32]};
	assign o_tlast = s_axis_tlast;
	assign o_tvalid = s_axis_tvalid;

endmodule // axis_to_cvita
module cvita_dest_lookup
#(
    parameter DEST_WIDTH = 4
)
(
    input clk, input rst,
    input set_stb, input [7:0] set_addr, input [DEST_WIDTH-1:0] set_data,
    input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
    output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready,
    output [DEST_WIDTH-1:0] o_tdest
);

    reg [7:0] endpoint;
    ram_2port #(.DWIDTH(DEST_WIDTH), .AWIDTH(8)) dest_lut
    (
        .clka(clk), .ena(1'b1), .wea(set_stb), .addra(set_addr), .dia(set_data), .doa(),
        .clkb(clk), .enb(1'b1), .web(1'b0), .addrb(endpoint), .dib(8'hff), .dob(o_tdest)
    );

    reg forward;
    reg [1:0] count;
    always @(posedge clk) begin
        if (rst) begin
            forward <= 1'b0;
            count <= 2'b0;
        end
        else if (forward == 1'b0 && i_tvalid) begin
            if (count == 2'b11) forward <= 1'b1;
              endpoint <= i_tdata[7:0];
            count <= count + 1'b1;
        end
        else if (forward == 1'b1 && i_tvalid && i_tready && i_tlast) begin
            forward <= 1'b0;
            count <= 2'b0;
        end
    end

    assign o_tdata = i_tdata;
    assign o_tlast = i_tlast;
    assign o_tvalid = i_tvalid && forward;
    assign i_tready = o_tready && forward;

endmodule // cvita_dest_lookup
module cvita_insert_tlast
  (input clk, input reset, input clear,
   input [63:0] i_tdata, input i_tvalid, output i_tready,
   output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);

   assign o_tdata = i_tdata;
   assign o_tvalid = i_tvalid;
   assign i_tready = o_tready;

   wire [15:0] cvita_len_ceil = i_tdata[47:32] + 7;
   wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]};
   
   reg [15:0] 	 count;

   assign o_tlast = (count != 0) ? (count == 16'd1) : (axi_len == 16'd1);

   always @(posedge clk)
     if(reset | clear)
       begin
	  count <= 16'd0;
       end
     else
       if(i_tready & i_tvalid)
	 if(count != 16'd0)
	   count <= count - 16'd1;
	 else
	   count <= axi_len - 16'd1;
   
endmodule // cvita_insert_tlast
module cvita_packet_debug (
   input          clk,
   input          reset,
   input          clear,

   //Packet In
   input [63:0]   tdata,
   input          tlast,
   input          tvalid,
   input          tready,

   //Per packet info
   output reg           pkt_strobe,
   output reg [63:0]    header,
   output reg [63:0]    timestamp,
   output reg [15:0]    actual_length,
   output reg [63:0]    checksum,
   
   //Statistics
   output reg [31:0]    pkt_count,
   output reg [31:0]    ctrl_pkt_count
);

   localparam ST_HEADER = 2'd0;
   localparam ST_TIME   = 2'd1;
   localparam ST_DATA   = 2'd2;

   //Packet state logic
   reg [1:0]   pkt_state;
   always @(posedge clk) begin
      if (reset) begin
         pkt_state <= ST_HEADER;
      end else if (tvalid & tready) begin
         case(pkt_state)
            ST_HEADER: begin
               if (!tlast) 
                  pkt_state <= (tdata[61]) ? ST_TIME : ST_DATA;
            end
            ST_TIME: begin
               pkt_state <= (tlast) ? ST_HEADER : ST_DATA;
            end
            ST_DATA: begin
               pkt_state <= (tlast) ? ST_HEADER : ST_DATA;
            end
            default: pkt_state <= ST_HEADER;
         endcase
      end
   end

   //Trigger logic
   always @(posedge clk)
      if (reset)
         pkt_strobe <= 1'b0;
      else
         pkt_strobe <= tvalid & tready & tlast;

   //Header capture
   always @(posedge clk)
      if (reset)
         header <= 64'd0;
      else if (pkt_state == ST_HEADER)
         if (tvalid & tready)
            header <= tdata;

   //Timestamp capture
   always @(posedge clk)
      if (reset)
         timestamp <= 64'd0;
      else if (pkt_state == ST_TIME)
         if (tvalid & tready)
            timestamp <= tdata;

   //Length capture
   always @(posedge clk)
      if (reset || pkt_state == ST_HEADER)
         actual_length <= (tvalid & tready & tlast) ? 16'd8 : 16'd0;
      else
         if (tvalid & tready)
            actual_length <= actual_length + 16'd8;

   //Checksum capture
   always @(posedge clk)
      if (reset || pkt_state == ST_HEADER)
         checksum <= 64'd0;
      else if (pkt_state == ST_DATA)
         if (tvalid & tready)
            checksum <= checksum ^ tdata;

   //Counts
   always @(posedge clk)
      if (reset | clear) begin
         pkt_count      <= 32'd0;
         ctrl_pkt_count <= 32'd0;
      end else begin
         if (tvalid & tready & tlast) begin
            pkt_count <= pkt_count + 32'd1;
            if (pkt_state == ST_HEADER && tdata[63])
               ctrl_pkt_count <= ctrl_pkt_count + 32'd1;
            else if (header[63]) 
               ctrl_pkt_count <= ctrl_pkt_count + 32'd1;
         end
      end

endmodule // cvita_packet_debug
module cvita_to_axis
(
	input wire           clk,

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

	output wire [63:0]   m_axis_tdata,
        output wire          m_axis_tlast,
        output wire          m_axis_tvalid,
        input wire           m_axis_tready
);

	assign i_tready = m_axis_tready;

	assign m_axis_tdata = {i_tdata[31:0], i_tdata[63:32]};
	assign m_axis_tlast = i_tlast;
	assign m_axis_tvalid = i_tvalid;

endmodule // cvita_to_axis
module ip_hdr_checksum_tb();
   
   initial $dumpfile("ip_hdr_checksum_tb.vcd");
   initial $dumpvars(0,ip_hdr_checksum_tb);

   reg clk;
   
   wire [159:0] in = {
		      16'h4500,
		      16'h0030,
		      16'h4422,
		      16'h4000,
		      16'h8006,
		      16'h0000,
		      16'h8c7c,
		      16'h19ac,
		      16'hae24,
		      16'h1e2b
		      };
   
   wire [15:0] 	out;
   ip_hdr_checksum ip_hdr_checksum
     (.clk(clk), 
      .in(in),
      .out(out));

   initial
     begin
	clk <= 0;
	#100 clk <= 1;
	#100 clk <= 0;
	#100 clk <= 1;
	#100 $display("Computed 0x%x, should be 0x442e", out);
	#100 $finish;
     end
   
endmodule // ip_hdr_checksum_tb
module crc_xnor #(
  parameter INPUT_WIDTH=64,
  parameter OUTPUT_WIDTH=8
) (
   input clk,
   input [INPUT_WIDTH:1] input_data,
   input rst,
   input hold,
   output [OUTPUT_WIDTH:1] crc_out
);

    wire [INPUT_WIDTH:1] current_lfsr;
    reg  [INPUT_WIDTH:1] current_lfsr_r;

    // LFSR based on table given by Xilinx
    generate if (INPUT_WIDTH == 64) begin
        assign current_lfsr[1] = current_lfsr_r[64] ^ current_lfsr_r[63] ^ current_lfsr_r[61] ^ current_lfsr_r[60];
        assign current_lfsr[INPUT_WIDTH:2] = current_lfsr_r[INPUT_WIDTH-1:1]; 
    end else begin
        fake_error_thrower invalid_width_parameter();
    end endgenerate

   always @(posedge clk) begin
      if (rst) begin
         current_lfsr_r <= input_data;
      end else if(~hold) begin
         current_lfsr_r <= current_lfsr ^ input_data;
      end
   end

    // Sum reduce based on output width
    generate if(INPUT_WIDTH == 64 && OUTPUT_WIDTH == 16) begin
        assign crc_out =    current_lfsr_r[INPUT_WIDTH:INPUT_WIDTH/4*3+1]+current_lfsr_r[INPUT_WIDTH/4*3:INPUT_WIDTH/4*2+1]+
                            current_lfsr_r[INPUT_WIDTH/4*2:INPUT_WIDTH/4+1]+current_lfsr_r[INPUT_WIDTH/4:1];
    end else if(INPUT_WIDTH == 64 && OUTPUT_WIDTH == 32) begin
        assign crc_out =    current_lfsr_r[INPUT_WIDTH:INPUT_WIDTH/2+1]+current_lfsr_r[INPUT_WIDTH/2:1];
    end else begin
        fake_error_thrower invalid_width_parameter();
    end endgenerate
      
   

endmodule
module axi_chdr_header_trigger
  #(
    parameter WIDTH=64,
    parameter SID=0
   )
    (input clk, input reset, input clear,
     input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, input i_tready,
     output trigger
     );

   
   reg 	  state;
   localparam IDLE = 0;
   localparam RUN  = 1;
 

   always @(posedge clk)
     if(reset | clear)
       state <= IDLE;
     else
       case (state)
	 IDLE :
	   if(i_tvalid && i_tready)
	     state <= RUN;

	 RUN :
	   if(i_tready && i_tvalid && i_tlast)	    
	     state <= IDLE;

	 default :
	   state <= IDLE;
       endcase // case (state)

   assign     trigger =  i_tvalid && i_tready && (state == IDLE) && (i_tdata[15:0] != SID);

endmodule // axi_chdr_header_trigger
module axi_dummy
(
  // sys connect
  input         s_axi_aclk,
  input         s_axi_areset,

  // axi4 lite slave port
  input [31:0]  s_axi_awaddr,
  input         s_axi_awvalid,
  output        s_axi_awready,

  input [31:0]  s_axi_wdata,
  input [3:0]   s_axi_wstrb,
  input         s_axi_wvalid,
  output        s_axi_wready,

  output [1:0]  s_axi_bresp,
  output        s_axi_bvalid,
  input         s_axi_bready,

  input [31:0]  s_axi_araddr,
  input         s_axi_arvalid,
  output        s_axi_arready,

  output [31:0] s_axi_rdata,
  output [1:0]  s_axi_rresp,
  output        s_axi_rvalid,
  input         s_axi_rready
);
  parameter DEC_ERR = 1'b1;

  localparam IDLE              = 3'b001;
  localparam READ_IN_PROGRESS  = 3'b010;
  localparam WRITE_IN_PROGRESS = 3'b100;

  reg [2:0] state;

  always @ (posedge s_axi_aclk) begin
    if (s_axi_areset) begin
      state <= IDLE;
    end
    else case (state)

    IDLE: begin
      if (s_axi_arvalid)
        state <= READ_IN_PROGRESS;
      else if (s_axi_awvalid)
        state <= WRITE_IN_PROGRESS;
    end

    READ_IN_PROGRESS: begin
      if (s_axi_rready)
        state <= IDLE;
    end

    WRITE_IN_PROGRESS: begin
      if (s_axi_bready)
        state <= IDLE;
    end

    default: begin
      state <= IDLE;
    end

    endcase
  end

  assign s_axi_awready = (state == IDLE);
  assign s_axi_wready  = (state == WRITE_IN_PROGRESS);
  assign s_axi_bvalid  = (state == WRITE_IN_PROGRESS);

  assign s_axi_arready = (state == IDLE);
  assign s_axi_rdata = 32'hdead_ba5e;
  assign s_axi_rvalid  = (state == READ_IN_PROGRESS);
  assign s_axi_rresp = DEC_ERR ? 2'b11 : 2'b00;
  assign s_axi_bresp = DEC_ERR ? 2'b11 : 2'b00;

endmodule
module axi_embed_tlast #(
  parameter WIDTH=64,
  parameter ADD_CHECKSUM=0
) (
   input clk,
   input reset,
   input clear,
   //
   input [WIDTH-1:0] i_tdata,
   input i_tlast,
   input i_tvalid,
   output i_tready,
   //
   output reg [WIDTH-1:0] o_tdata,
   output o_tvalid,
   input o_tready
);

   localparam PASS = 0;
   localparam ZERO = 1;
   localparam ONE = 2;
   localparam ESCAPE = 3;

   localparam IDLE = 0;
   localparam LAST = 1;
   localparam ESC = 2;
   localparam FINISH = 3;
   
   reg [1:0]  state, next_state;

   reg [1:0]  select;

   wire [31:0] checksum;
   generate if (ADD_CHECKSUM == 1) begin
      reg [31:0] checksum_reg;
      always @(posedge clk) begin
         if (reset | clear) begin
            checksum_reg <= 0;
         end else if (i_tready && i_tvalid && i_tlast) begin
            checksum_reg <= 0;
         end else if (i_tready && i_tvalid) begin
            checksum_reg <= checksum_reg ^ i_tdata[31:0] ^ i_tdata[63:32];
         end
      end
      assign checksum = checksum_reg;
   end else begin
      assign checksum = 32'h0;
   end endgenerate

   always @(posedge clk) 
      if (reset | clear) begin
         state <= IDLE;
      end else begin if (o_tready)
         state <= next_state;
      end 

   always @(*) begin
      case(state)
         IDLE: begin
            if (i_tlast && i_tvalid) begin
               next_state = LAST;
               select = ESCAPE;
            end else if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
               next_state = ESC;
               select = ESCAPE;
            end else begin
               next_state = IDLE;
               select = PASS;
            end
         end // case: IDLE

         LAST: begin
            select = ONE;
            next_state = FINISH;
         end

         ESC: begin
            select = ZERO;
            next_state = FINISH;
         end

         FINISH: begin
            select = PASS;
            if (i_tvalid)
               next_state = IDLE;
            else
               next_state = FINISH;
         end
      endcase // case(state)
   end // always @ (*)

   //
   // Muxes
   //
   always @*
      begin
         case(select)
            PASS:   o_tdata = i_tdata;
            ZERO:   o_tdata = 0;
            ONE:    o_tdata = {checksum[31:0],32'h1};
            ESCAPE: o_tdata = 64'hDEADBEEFFEEDCAFE;
         endcase // case(select)
      end

   assign o_tvalid = (select == PASS) ? i_tvalid : 1'b1;
   assign i_tready = (select == PASS) ? o_tready : 1'b0;

endmodule // axi_embed_tlast
module axi_fast_fifo
  #(parameter WIDTH=64)
  (
   input clk,
   input reset,
   input clear,
   //
   input [WIDTH-1:0] i_tdata,
   input i_tvalid,
   output reg i_tready,
   //
   output [WIDTH-1:0] o_tdata,
   output reg o_tvalid,
   input  o_tready
   );

   reg [WIDTH-1:0] data_reg1, data_reg2;

   reg [1:0] 	   state;
   
   localparam EMPTY = 0;
   localparam HALF = 1;
   localparam FULL = 2;
   
   always @(posedge clk) 
     if (reset | clear) begin
	state <= EMPTY;
	data_reg1 <= 0;
	data_reg2 <= 0;
	o_tvalid <= 1'b0;
	i_tready <= 1'b0;
	
     end else begin
	case (state)
	  // Nothing in either register.
	  // Upstream can always push data to us.
	  // Downstream has nothing to take from us.
	  EMPTY: begin
	     if (i_tvalid) begin
		data_reg1 <= i_tdata;
		state <= HALF;
		i_tready <= 1'b1;
		o_tvalid <= 1'b1;
	     end else begin
		state <= EMPTY;
		i_tready <= 1'b1;
		o_tvalid <= 1'b0;
	     end
	  end
	  // First Register Full.
	  // Upstream can always push data to us.
	  // Downstream can always read from us.
	  HALF: begin
	     if (i_tvalid && o_tready) begin
		data_reg1 <= i_tdata;
		state <= HALF;
		i_tready <= 1'b1;
		o_tvalid <= 1'b1;
	     end else if (i_tvalid) begin
		data_reg1 <= i_tdata;
		data_reg2 <= data_reg1;
		state <= FULL;
		i_tready <= 1'b0;
		o_tvalid <= 1'b1;
	     end else if (o_tready) begin
		state <= EMPTY;
		i_tready <= 1'b1;
		o_tvalid <= 1'b0;
	     end else begin
		state <= HALF;
		i_tready <= 1'b1;
		o_tvalid <= 1'b1;
	     end
	  end // case: HALF
	  // Both Registers Full.
	  // Upstream can not push to us in this state.
	  // Downstream can always read from us.
	  FULL: begin
	     if (o_tready) begin
		state <= HALF;
		i_tready <= 1'b1;
		o_tvalid <= 1'b1;
	     end
	     else begin
		state <= FULL;
		i_tready <= 1'b0;
		o_tvalid <= 1'b1;
	     end
	  end
	endcase // case(state)
     end // else: !if(reset | clear)

   assign o_tdata = (state == FULL) ? data_reg2 : data_reg1;
   

endmodule // axi_fast_fifo
module axis_packet_flush #(
  parameter WIDTH               = 64,
  parameter FLUSH_PARTIAL_PKTS  = 0
)(
  input  wire             clk,
  input  wire             reset,
  input  wire             enable,
  output wire             flushing,
  input  wire [WIDTH-1:0] s_axis_tdata,
  input  wire             s_axis_tlast,
  input  wire             s_axis_tvalid,
  output wire             s_axis_tready,
  output wire [WIDTH-1:0] m_axis_tdata,
  output wire             m_axis_tlast,
  output wire             m_axis_tvalid,
  input  wire             m_axis_tready
);

  reg mid_pkt = 1'b0;
  reg active  = 1'b0;

  always @(posedge clk) begin
    if (reset) begin
      mid_pkt <= 1'b0;
      active <= 1'b0;
    end else begin
      if (s_axis_tvalid & s_axis_tready) begin
        mid_pkt <= ~s_axis_tlast;
      end
      if (enable & ((s_axis_tvalid & s_axis_tready & s_axis_tlast) | (~mid_pkt & (~s_axis_tvalid | ~s_axis_tready)))) begin
        active <= 1'b1;
      end else if (~enable) begin
        active <= 1'b0;
      end
    end
  end

  assign flushing      = (FLUSH_PARTIAL_PKTS == 0) ? active : enable;

  assign m_axis_tdata  = s_axis_tdata;
  assign m_axis_tlast  = s_axis_tlast;
  assign m_axis_tvalid = flushing ? 1'b0 : s_axis_tvalid;
  assign s_axis_tready = flushing ? 1'b1 : m_axis_tready;

endmodule
module axis_downsizer #(
  parameter OUT_DATA_W  = 32,
  parameter OUT_USER_W  = 1,
  parameter RATIO       = 4
)(
  // Clock, reset and settings
  input  wire                          clk,              // Clock
  input  wire                          reset,            // Reset
  // Data In (AXI-Stream)              
  input  wire [(OUT_DATA_W*RATIO)-1:0] s_axis_tdata,     // Input stream tdata
  input  wire [(OUT_USER_W*RATIO)-1:0] s_axis_tuser,     // Input stream tuser
  input  wire [RATIO-1:0]              s_axis_tkeep,     // Input stream tkeep
  input  wire                          s_axis_tlast,     // Input stream tlast
  input  wire                          s_axis_tvalid,    // Input stream tvalid
  output wire                          s_axis_tready,    // Input stream tready
  // Data Out (AXI-Stream)             
  output wire [OUT_DATA_W-1:0]         m_axis_tdata,     // Output stream tdata
  output wire [OUT_USER_W-1:0]         m_axis_tuser,     // Output stream tuser
  output wire                          m_axis_tlast,     // Output stream tlast
  output wire                          m_axis_tvalid,    // Output stream tvalid
  input  wire                          m_axis_tready     // Output stream tready
);

  genvar i;
  generate if (RATIO != 1) begin
    // Constants
    localparam [$clog2(RATIO)-1:0] SEL_FIRST  = 'd0;
    localparam [$clog2(RATIO)-1:0] SEL_LAST   = RATIO-1;
    localparam [RATIO-1:0]         KEEP_FIRST = {{(RATIO-1){1'b0}}, 1'b1};
    localparam [RATIO-1:0]         KEEP_ALL   = {(RATIO){1'b1}};

    // Keep a binary-coded and one-hot version of the current
    // section of the input that is being processed.
    reg [$clog2(RATIO)-1:0] select = SEL_FIRST;
    reg [RATIO-1:0]         keep   = KEEP_FIRST;

    // State machine to drive the select bits for the
    // input selection MUX.
    always @(posedge clk) begin
      if (reset) begin
        select <= SEL_FIRST;
        keep   <= KEEP_FIRST;
      end else if (m_axis_tvalid & m_axis_tready) begin
        select <= (select == SEL_LAST || m_axis_tlast) ? SEL_FIRST  : (select + 'd1);
        keep   <= (keep   == KEEP_ALL || m_axis_tlast) ? KEEP_FIRST : {keep[RATIO-2:0], 1'b1};
      end
    end

    // The input selection MUX
    wire [OUT_DATA_W-1:0] in_data[0:RATIO-1];
    wire [OUT_USER_W-1:0] in_user[0:RATIO-1];
    for (i = 0; i < RATIO; i=i+1) begin
      assign in_data[i] = s_axis_tdata[i*OUT_DATA_W+:OUT_DATA_W];
      assign in_user[i] = s_axis_tuser[i*OUT_USER_W+:OUT_USER_W];
    end
    assign m_axis_tdata   = in_data[select];
    assign m_axis_tuser   = in_user[select];
    assign m_axis_tlast   = s_axis_tlast && (keep == s_axis_tkeep);
    assign m_axis_tvalid  = s_axis_tvalid;
    assign s_axis_tready  = m_axis_tvalid && m_axis_tready && ((keep == KEEP_ALL) || m_axis_tlast);

  end else begin  // if (RATIO != 1)

    // Passthrough
    assign m_axis_tdata   = s_axis_tdata;
    assign m_axis_tuser   = s_axis_tuser;
    assign m_axis_tlast   = s_axis_tlast;
    assign m_axis_tvalid  = s_axis_tvalid;
    assign s_axis_tready  = m_axis_tready;

  end endgenerate

endmodule // axis_downsizer
module axi_to_strobed #(
  parameter WIDTH = 32,
  parameter FIFO_SIZE = 1,
  parameter MIN_RATE = 256
)(
  input clk, input reset, input clear,
  input [$clog2(MIN_RATE):0] out_rate,  // Number of clock cycles between strobes
  input ready,
  output error,                           // Output strobe but no data
  input [WIDTH-1:0] i_tdata, input i_tvalid, input i_tlast, output i_tready,
  output out_stb, output out_last, output [WIDTH-1:0] out_data
);

  reg strobe;
  wire valid;
  reg [$clog2(MIN_RATE):0] counter = 1;
  always @(posedge clk) begin
    if (reset | clear) begin
      strobe    <= 1'b0;
      counter   <= 1;
    end else if (ready) begin
      if (counter >= out_rate) begin
        strobe  <= 1'b1;
        counter <= 1;
      end else begin
        strobe  <= 1'b0;
        counter <= counter + 1'b1;
      end
    end else begin
      strobe <= 1'b0;
    end
  end

  axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
    .o_tdata({out_last,out_data}), .o_tvalid(valid), .o_tready(strobe),
    .space(), .occupied());

  assign out_stb = valid & strobe;
  assign error = ~valid & strobe;
endmodule
module strobed_to_axi #(
  parameter WIDTH = 32,
  parameter FIFO_SIZE = 1
)(
  input clk, input reset, input clear,
  input in_stb, input [WIDTH-1:0] in_data, input in_last,
  output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);

  axi_fifo #(.WIDTH(WIDTH+1), .SIZE(FIFO_SIZE)) axi_fifo (
    .clk(clk), .reset(reset), .clear(clear),
    .i_tdata({in_last,in_data}), .i_tvalid(in_stb), .i_tready(),
    .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
    .space(), .occupied());
endmodule
module fifo64_to_gpif2
#(
    parameter FIFO_SIZE = 9,
    parameter MTU = 12
)
(
    //input fifo interface
    input fifo_clk, input fifo_rst,
    input [63:0] i_tdata,
    input i_tlast,
    input i_tvalid,
    output i_tready,

    //output interface
    input gpif_clk, input gpif_rst,
    output [31:0] o_tdata,
    output o_tlast,
    output o_tvalid,
    input o_tready
);

    wire [31:0] i32_tdata;
    wire i32_tlast;
    wire i32_tvalid, i32_tready;

    axi_fifo64_to_fifo32 fifo64_to_fifo32
    (
        .clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
        .i_tdata(i_tdata), .i_tuser(3'b0/*done care*/), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
        .o_tdata(i32_tdata), .o_tuser(/*ignored cuz vita has len*/), .o_tlast(i32_tlast), .o_tvalid(i32_tvalid), .o_tready(i32_tready)
    );

    wire [31:0] gate_tdata;
    wire gate_tlast;
    wire gate_tvalid, gate_tready;

    axi_fifo_2clk #(.WIDTH(33), .SIZE(FIFO_SIZE)) cross_clock_fifo
    (
        .reset(fifo_rst | gpif_rst),
        .i_aclk(fifo_clk), .i_tdata({i32_tlast, i32_tdata}), .i_tvalid(i32_tvalid), .i_tready(i32_tready),
        .o_aclk(gpif_clk), .o_tdata({gate_tlast, gate_tdata}), .o_tvalid(gate_tvalid), .o_tready(gate_tready)
    );

    wire [31:0] int0_tdata; wire int0_tlast, int0_tvalid, int0_tready;

    axi_packet_gate #(.WIDTH(32), .SIZE(MTU), .USE_AS_BUFF(0)) buffer_whole_pkt
    (
        .clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
        .i_tdata(gate_tdata), .i_tlast(gate_tlast), .i_terror(1'b0), .i_tvalid(gate_tvalid), .i_tready(gate_tready),
        .o_tdata(int0_tdata), .o_tlast(int0_tlast), .o_tvalid(int0_tvalid), .o_tready(int0_tready)
    );

    axi_fifo #(.WIDTH(33), .SIZE(1)) outgress_timing_fifo
    (
        .clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
        .i_tdata({int0_tlast, int0_tdata}), .i_tvalid(int0_tvalid), .i_tready(int0_tready), .space(),
        .o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready), .occupied()
    );

endmodule //fifo_to_gpmc16
module cic_int_shifter(rate,signal_in,signal_out);
   parameter bw = 16;
   parameter maxbitgain = 21;
   
   input [7:0] rate;
   input       wire [bw+maxbitgain-1:0] signal_in;
   output      reg [bw-1:0] signal_out;

   function [4:0] bitgain;
      input [7:0] rate;
      case(rate)
	// Exact Cases
	8'd1 : bitgain = 0;
	8'd2 : bitgain = 3;
	8'd4 : bitgain = 6;
	8'd8 : bitgain = 9;
	8'd16 : bitgain = 12;
	8'd32 : bitgain = 15;
	8'd64 : bitgain = 18;
	8'd128 : bitgain = 21;
	
	// Nearest without overflow	
	8'd3 : bitgain = 5;
	8'd5 : bitgain = 7;
	8'd6 : bitgain = 8;
	8'd7 : bitgain = 9;
	8'd9,8'd10 : bitgain = 10;
	8'd11,8'd12 : bitgain = 11;
	8'd13,8'd14,8'd15 : bitgain = 12;
	8'd17,8'd18,8'd19,8'd20 : bitgain = 13;
	8'd21,8'd22,8'd23,8'd24,8'd25 : bitgain = 14;
	8'd26,8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 15;
	8'd33,8'd34,8'd35,8'd36,8'd37,8'd38,8'd39,8'd40 : bitgain = 16;
	8'd41,8'd42,8'd43,8'd44,8'd45,8'd46,8'd47,8'd48,8'd49,8'd50 : bitgain = 17;
	8'd51,8'd52,8'd53,8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 18;
	8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76,8'd77,8'd78,8'd79,8'd80 : bitgain = 19;
	8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90,8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101 : bitgain = 20;
	
	default : bitgain = 21;
      endcase // case(rate)
   endfunction // bitgain
   
   wire [4:0] 	  shift = bitgain(rate);
   
   // We should be able to do this, but can't ....
   // assign 	  signal_out = signal_in[shift+bw-1:shift];
   
   always @*
     case(shift)
       5'd0  : signal_out = signal_in[0+bw-1:0];
       5'd3  : signal_out = signal_in[3+bw-1:3];
       5'd6  : signal_out = signal_in[6+bw-1:6];
       5'd9  : signal_out = signal_in[9+bw-1:9];
       5'd12 : signal_out = signal_in[12+bw-1:12];
       5'd15 : signal_out = signal_in[15+bw-1:15];
       5'd18 : signal_out = signal_in[18+bw-1:18];
       5'd21 : signal_out = signal_in[21+bw-1:21];
       
       5'd5  : signal_out = signal_in[5+bw-1:5];
       5'd7  : signal_out = signal_in[7+bw-1:7];
       5'd8  : signal_out = signal_in[8+bw-1:8];
       5'd10 : signal_out = signal_in[10+bw-1:10];
       5'd11 : signal_out = signal_in[11+bw-1:11];
       5'd13 : signal_out = signal_in[13+bw-1:13];
       5'd14 : signal_out = signal_in[14+bw-1:14];
       5'd16 : signal_out = signal_in[16+bw-1:16];
       5'd17 : signal_out = signal_in[17+bw-1:17];
       5'd19 : signal_out = signal_in[19+bw-1:19];
       5'd20 : signal_out = signal_in[20+bw-1:20];
       
       default : signal_out = signal_in[21+bw-1:21];
     endcase // case(shift)

endmodule // cic_int_shifter
module rx_dcoffset 
  #(parameter WIDTH=16,
    parameter ADDR=8'd0,
    parameter alpha_shift=20)
   (input clk, input rst,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,
    input in_stb, input [WIDTH-1:0] in,
    output out_stb, output [WIDTH-1:0] out);

   wire 	      set_now = set_stb & (ADDR == set_addr);
   reg 		      fixed;  // uses fixed offset
   wire [WIDTH-1:0]   fixed_dco;

   localparam int_width = WIDTH + alpha_shift;
   reg [int_width-1:0] integrator;
   reg                 integ_in_stb;
   wire [WIDTH-1:0]    quantized;

   always @(posedge clk) begin
     if(rst)
       begin
       integ_in_stb <= 0;
	  fixed <= 0;
	  integrator <= {int_width{1'b0}};
       end
     else if(set_now)
       begin
	  fixed <= set_data[31];
	  if(set_data[30])
	    integrator <= {set_data[29:0],{(int_width-30){1'b0}}};
       end
     else if(~fixed & in_stb)
       integrator <= integrator +  {{(alpha_shift){out[WIDTH-1]}},out};
     integ_in_stb <= in_stb;
   end

   round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd
     (.clk(clk), .reset(rst), .in(integrator), .strobe_in(integ_in_stb), .out(quantized), .strobe_out());

   add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg
     (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(in_stb), .sum(out), .strobe_out(out_stb));

endmodule // rx_dcoffset
module add2_reg
  #(parameter WIDTH=16)
    (input clk,
     input [WIDTH-1:0] in1,
     input [WIDTH-1:0] in2,
     output reg [WIDTH-1:0] sum);

   wire [WIDTH-1:0] sum_int;
   
   add2 #(.WIDTH(WIDTH)) add2 (.in1(in1),.in2(in2),.sum(sum_int));

   always @(posedge clk)
     sum <= sum_int;
   
endmodule // add2_reg
module small_hb_int
  #(parameter WIDTH=18)
    (input clk,
     input rst,
     input bypass,
     input stb_in,
     input [WIDTH-1:0] data_in,
     input [7:0] output_rate,
     input stb_out,
     output reg [WIDTH-1:0] data_out);

  
   reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6;

   localparam 	   MWIDTH = 36;
   wire [MWIDTH-1:0] prod;

   reg [6:0] 	     stbin_d;
   
   always @(posedge clk)
     stbin_d <= {stbin_d[5:0],stb_in};
   
   always @(posedge clk)
     if (rst) 
       begin
	  d1 <= 0;
	  d2 <= 0;
	  d3 <= 0;
	  d4 <= 0;
	  d5 <= 0;
	  d6 <= 0;
       end
     else if(stb_in)
       begin
	  d1 <= data_in;
	  d2 <= d1;
	  d3 <= d2;
	  d4 <= d3;
	  d5 <= d4;
	  d6 <= d5;
       end

   wire [WIDTH-1:0] sum_outer, sum_inner;
   add2_and_round_reg #(.WIDTH(WIDTH)) add_outer (.clk(clk),.in1(d1),.in2(d4),.sum(sum_outer));
   add2_and_round_reg #(.WIDTH(WIDTH)) add_inner (.clk(clk),.in1(d2),.in2(d3),.sum(sum_inner));

   wire [17:0] 	   coeff_outer = -10690;
   wire [17:0] 	   coeff_inner = 75809;

   MULT18X18S mult(.C(clk), .CE(1), .R(rst), .P(prod), .A(stbin_d[1] ? coeff_outer : coeff_inner), 
		   .B(stbin_d[1] ? sum_outer : sum_inner) );

   wire [MWIDTH:0] accum;
   acc #(.IWIDTH(MWIDTH),.OWIDTH(MWIDTH+1)) 
     acc (.clk(clk),.clear(stbin_d[2]),.acc(|stbin_d[3:2]),.in(prod),.out(accum));
   
   wire [WIDTH+2:0] 	 accum_rnd;
   round_reg #(.bits_in(MWIDTH+1),.bits_out(WIDTH+3))
     final_round (.clk(clk),.in(accum),.out(accum_rnd));

   wire [WIDTH-1:0] 	 clipped;
   clip_reg #(.bits_in(WIDTH+3),.bits_out(WIDTH)) final_clip
     (.clk(clk),.in(accum_rnd),.strobe_in(1'b1), .out(clipped));

   reg [WIDTH-1:0] 	 saved, saved_d3;
   always @(posedge clk)
     if(stbin_d[6])
       saved <= clipped;

   always @(posedge clk)
     if(stbin_d[3])
       saved_d3 <= d3;
	   
   always @(posedge clk)
     if(bypass)
       data_out <= data_in;
     else if(stb_in & stb_out)
       case(output_rate)
	 1 : data_out <= d6; 
	 2 : data_out <= d4;
	 3, 4, 5, 6, 7 : data_out <= d3;
	 default : data_out <= d2;
       endcase // case(output_rate)
     else if(stb_out)
       data_out <= saved;

endmodule // small_hb_int
module round
  #(parameter bits_in=0,
    parameter bits_out=0,
    parameter round_to_zero=0,       // original behavior
    parameter round_to_nearest=1,    // lowest noise
    parameter trunc=0)               // round to negative infinity
    (input [bits_in-1:0] in,
     output [bits_out-1:0] out,
     output [bits_in-bits_out:0] err);

   wire 			 round_corr,round_corr_trunc,round_corr_rtz,round_corr_nearest,round_corr_nearest_safe;

   assign 			 round_corr_trunc = 0;
   assign 			 round_corr_rtz = (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
   assign 			 round_corr_nearest = in[bits_in-bits_out-1];

   generate
      if(bits_in-bits_out > 1)
	assign 			 round_corr_nearest_safe = (~in[bits_in-1] & (&in[bits_in-2:bits_in-bits_out])) ? 1'b0 :
				 round_corr_nearest;
      else
	assign round_corr_nearest_safe = round_corr_nearest;
   endgenerate


   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 = in[bits_in-1:bits_in-bits_out] + round_corr;

   assign err = in - {out,{(bits_in-bits_out){1'b0}}};

endmodule // round
module add2_and_clip_reg
  #(parameter WIDTH=16)
    (input clk,
     input rst,
     input [WIDTH-1:0] in1,
     input [WIDTH-1:0] in2,
     input strobe_in,
     output reg [WIDTH-1:0] sum,
     output reg strobe_out);

   wire [WIDTH-1:0] sum_int;

   add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int));

   always @(posedge clk)
     if(rst)
       sum <= 0;
     else if(strobe_in)
       sum <= sum_int;

   always @(posedge clk) strobe_out <= rst ? 1'b0 : strobe_in;

endmodule // add2_and_clip_reg
module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo);
   parameter bitwidth = 16;
   parameter zwidth = 16;
   parameter shift = 1;
   
   input     clock;
   input     reset;
   input     enable;
   input [bitwidth-1:0] xi,yi;
   input [zwidth-1:0] zi;
   input [zwidth-1:0] constant;
   output [bitwidth-1:0] xo,yo;
   output [zwidth-1:0] zo;
   
   wire z_is_pos = ~zi[zwidth-1];

   reg [bitwidth-1:0] 	 xo,yo;
   reg [zwidth-1:0] zo;
   
   always @(posedge clock)
     if(reset)
       begin
	  xo <= 0;
	  yo <= 0;
	  zo <= 0;
       end
     else //if(enable)
       begin
	  xo <= z_is_pos ?   
		xi - {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]} :
		xi + {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]};
	  yo <= z_is_pos ?   
		yi + {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]} :
		yi - {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]};
	  zo <= z_is_pos ?   
		zi - constant :
		zi + constant;
       end
endmodule
module add2_and_round_reg
  #(parameter WIDTH=16)
    (input clk,
     input [WIDTH-1:0] in1,
     input [WIDTH-1:0] in2,
     output reg [WIDTH-1:0] sum);

   wire [WIDTH-1:0] sum_int;
   
   add2_and_round #(.WIDTH(WIDTH)) add2_n_rnd (.in1(in1),.in2(in2),.sum(sum_int));

   always @(posedge clk)
     sum <= sum_int;
   
endmodule // add2_and_round_reg
module sign_extend (in,out);
	parameter bits_in=0;  // FIXME Quartus insists on a default
	parameter bits_out=0;
	
	input [bits_in-1:0] in;
	output [bits_out-1:0] out;
	
	assign out = {{(bits_out-bits_in){in[bits_in-1]}},in};
	
endmodule
module round_sd #(
  parameter WIDTH_IN=18,
  parameter WIDTH_OUT=16,
  parameter DISABLE_SD=0
)(
  input clk, input reset,
  input [WIDTH_IN-1:0] in, input strobe_in,
  output reg [WIDTH_OUT-1:0] out, output reg strobe_out
);

  localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1;

  wire [ERR_WIDTH-1:0] err;
  wire [WIDTH_IN-1:0]  err_ext, sum;
  wire [WIDTH_OUT-1:0] out_pre;
  wire                 strobe_pre;

  sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext));

  add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg (
    .clk(clk), .rst(reset), .in1(in), .in2((DISABLE_SD == 0) ? err_ext : {WIDTH_IN{1'b0}}), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_pre));

  round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out_pre), .err(err));

  always @(posedge clk) begin
    if (reset) begin
      strobe_out <= 1'b0;
    end else begin
      strobe_out <= strobe_pre;
      if (strobe_pre) begin
        out <= out_pre;
      end
    end
  end

endmodule // round_sd
module clip_reg
  #(parameter bits_in=0,
    parameter bits_out=0,
    parameter STROBED=1'b0)
    (input clk,
     input reset,
     input [bits_in-1:0] in,
     output reg [bits_out-1:0] out,
     input strobe_in,
     output reg strobe_out);
   
   wire [bits_out-1:0] temp;

   clip #(.bits_in(bits_in),.bits_out(bits_out)) clip (.in(in),.out(temp));

   always @(posedge clk) strobe_out <= reset ? 1'b0 : strobe_in;
   
   always @(posedge clk)
     if(strobe_in | ~STROBED)
       out <= temp;
   
endmodule // clip_reg
module rx_frontend
  #(parameter BASE = 0,
    parameter IQCOMP_EN = 1)
   (input clk, input rst,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    input [15:0] adc_a, input adc_ovf_a,
    input [15:0] adc_b, input adc_ovf_b,

    output [23:0] i_out, output [23:0] q_out,
    input run,
    output [31:0] debug
    );
   
   reg [15:0] 	  adc_i, adc_q;
   wire [23:0] 	  adc_i_ofs, adc_q_ofs;
   wire [35:0] 	  corr_i, corr_q; 
   wire [17:0] 	  mag_corr,phase_corr;
   wire 	  swap_iq;
   
   setting_reg #(.my_addr(BASE), .width(1)) sr_8
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(swap_iq),.changed());

   always @(posedge clk)
     if(swap_iq) // Swap
       {adc_i,adc_q} <= {adc_b,adc_a};
     else
       {adc_i,adc_q} <= {adc_a,adc_b};
       
   setting_reg #(.my_addr(BASE+1),.width(18)) sr_1
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(mag_corr),.changed());
   
   setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(phase_corr),.changed());

   rx_dcoffset #(.WIDTH(24),.ADDR(BASE+3)) rx_dcoffset_i
     (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
      .in({adc_i,8'b00}), .in_stb(1'b1),
      .out(adc_i_ofs), .out_stb());
   
   rx_dcoffset #(.WIDTH(24),.ADDR(BASE+4)) rx_dcoffset_q
     (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
      .in({adc_q,8'b00}), .in_stb(1'b1),
      .out(adc_q_ofs), .out_stb());
   
   generate
      if(IQCOMP_EN == 1)
	begin
	   reg [23:0] adc_i_ofs_dly, adc_q_ofs_dly;
	   always @(posedge clk) begin
	     adc_i_ofs_dly <= adc_i_ofs;
	     adc_q_ofs_dly <= adc_q_ofs;
	   end

	   MULT18X18S mult_mag_corr
	     (.P(corr_i), .A(adc_i_ofs[23:6]), .B(mag_corr), .C(clk), .CE(1'b1), .R(rst) ); 
	   
	   MULT18X18S mult_phase_corr
	     (.P(corr_q), .A(adc_i_ofs[23:6]), .B(phase_corr), .C(clk), .CE(1'b1), .R(rst) );
	   
	   add2_and_clip_reg #(.WIDTH(24)) add_clip_i
	     (.clk(clk), .rst(rst), 
	      .in1(adc_i_ofs_dly), .in2(corr_i[35:12]), .strobe_in(1'b1),
	      .sum(i_out), .strobe_out());
	   
	   add2_and_clip_reg #(.WIDTH(24)) add_clip_q
	     (.clk(clk), .rst(rst), 
	      .in1(adc_q_ofs_dly), .in2(corr_q[35:12]), .strobe_in(1'b1),
	      .sum(q_out), .strobe_out());
	end // if (IQCOMP_EN == 1)
      else
	begin
	   assign i_out = adc_i_ofs;
	   assign q_out = adc_q_ofs;
	end // else: !if(IQCOMP_EN == 1)
   endgenerate
   
endmodule // rx_frontend
module cic_decim
  #(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7)
    (input clock,
     input reset,
     input enable,
     input [7:0] rate,
     input strobe_in,
     input strobe_out,
     input [bw-1:0] signal_in,
     output reg [bw-1:0] signal_out);

   localparam 	     maxbitgain = N * log2_of_max_rate;
   
   wire [bw+maxbitgain-1:0] signal_in_ext;
   reg [bw+maxbitgain-1:0]  integrator [0:N-1];
   reg [bw+maxbitgain-1:0]  differentiator [0:N-1];
   reg [bw+maxbitgain-1:0]  pipeline [0:N-1];
   reg [bw+maxbitgain-1:0]  sampler;
   
   integer 		    i;
   
   sign_extend #(bw,bw+maxbitgain) 
     ext_input (.in(signal_in),.out(signal_in_ext));
   
   always @(posedge clock)
     if(~enable)
       for(i=0;i<N;i=i+1)
	 integrator[i] <= 0;
     else if (strobe_in)
       begin
	  integrator[0] <= integrator[0] + signal_in_ext;
	  for(i=1;i<N;i=i+1)
	    integrator[i] <= integrator[i] + integrator[i-1];
       end	
   
   always @(posedge clock)
     if(~enable)
       begin
	  sampler <= 0;
	  for(i=0;i<N;i=i+1)
	    begin
	       pipeline[i] <= 0;
	       differentiator[i] <= 0;
	    end
       end
     else if (strobe_out)
       begin
	  sampler <= integrator[N-1];
	  differentiator[0] <= sampler;
	  pipeline[0] <= sampler - differentiator[0];
	  for(i=1;i<N;i=i+1)
	    begin
	       differentiator[i] <= pipeline[i-1];
	       pipeline[i] <= pipeline[i-1] - differentiator[i];
	    end
       end // if (enable && strobe_out)
   
   wire [bw-1:0] signal_out_unreg;
   
   cic_dec_shifter #(bw)
     cic_dec_shifter(rate,pipeline[N-1],signal_out_unreg);

   always @(posedge clock)
     signal_out <= signal_out_unreg;
   
endmodule // cic_decim
module add2_and_round
  #(parameter WIDTH=16)
    (input [WIDTH-1:0] in1,
     input [WIDTH-1:0] in2,
     output [WIDTH-1:0] sum);

   wire [WIDTH:0] 	sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
   assign 		sum = sum_int[WIDTH:1] + (sum_int[WIDTH] & sum_int[0]);
   
endmodule // add2_and_round
module add2
  #(parameter WIDTH=16)
    (input [WIDTH-1:0] in1,
     input [WIDTH-1:0] in2,
     output [WIDTH-1:0] sum);

   wire [WIDTH:0] 	sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
   assign 		sum = sum_int[WIDTH:1];  // Note -- will have some bias
   
endmodule // add2
module rx_frontend_tb();
   
   reg clk, rst;

   initial rst = 1;
   initial #1000 rst = 0;
   initial clk = 0;
   always #5 clk = ~clk;
   
   initial $dumpfile("rx_frontend_tb.vcd");
   initial $dumpvars(0,rx_frontend_tb);

   reg [15:0] adc_in;
   wire [23:0] adc_out;

   always @(posedge clk)
     begin
	if(adc_in[15])
	  $write("-%d,",-adc_in);
	else
	  $write("%d,",adc_in);
	if(adc_out[23])
	  $write("-%d\n",-adc_out);
	else
	  $write("%d\n",adc_out);
     end	
   
   rx_frontend #(.BASE(0), .IQCOMP_EN(1)) rx_frontend
     (.clk(clk),.rst(rst),
      .set_stb(0),.set_addr(0),.set_data(0),
      .adc_a(adc_in), .adc_ovf_a(0),
      .adc_b(0), .adc_ovf_b(0),
      .i_out(adc_out),.q_out(),
      .run(), .debug());

   always @(posedge clk)
     if(rst)
       adc_in <= 0;
     else
       adc_in <= adc_in + 4;
   //adc_in <= (($random % 473) + 23)/4;
   
endmodule // rx_frontend_tb
module srl
  #(parameter WIDTH=18)
    (input clk,
     input rst,
     input write,
     input [WIDTH-1:0] in,
     input [3:0] addr,
     output [WIDTH-1:0] out);
   
   genvar 		i;
   generate
      for (i=0;i<WIDTH;i=i+1)
	begin : gen_srl
	   SRL16E
	     srl16e(.Q(out[i]),
		    .A0(addr[0]),.A1(addr[1]),.A2(addr[2]),.A3(addr[3]),
		    .CE(write|rst),.CLK(clk),.D(in[i]));
	end
   endgenerate

endmodule // srl
module hb47_int_tb();

   wire GSR, GTS;
   glbl glbl( );

   reg 	clk = 0;
   reg 	rst;
   reg 	bypass;
   reg 	run;

   wire stb_in;
   reg 	stb_out;
   reg [7:0] cpo;

   reg [17:0] data_in;

   wire [17:0] data_out_dsp48a; 
   wire [17:0] data_out_dsp48e;
   
   reg [15:0]  freq = 500;

   integer     x = 0, y =0;



   always #100 clk = ~clk;

   // SPARTAN6 / DSP48A
    hb47_int
      #(.WIDTH(18),
	.DEVICE("SPARTAN6"))
	hb47_int_i0
	(
	 .clk(clk),
	 .rst(rst),
	 .bypass(bypass),
	 .stb_in(stb_in),
	 .data_in(data_in),
	 .output_rate(cpo),
	 .stb_out(stb_out),
	 .data_out(data_out_dsp48a)
	 );

   // SERIES7 / DSP48E
    hb47_int
      #(.WIDTH(18),
	.DEVICE("7SERIES"))
	hb47_int_i1
	(
	 .clk(clk),
	 .rst(rst),
	 .bypass(bypass),
	 .stb_in(stb_in),
	 .data_in(data_in),
	 .output_rate(cpo),
	 .stb_out(stb_out),
	 .data_out(data_out_dsp48e)
	 );

   always @(negedge clk)
     if (data_out_dsp48a !== data_out_dsp48e)
       $display("Output missmatch at %t",$time);
   

   
  cic_strober #(.WIDTH(2))
     hb1_strober(.clock(clk),.reset(rst),.enable(run),.rate(2'd2),
		 .strobe_fast(stb_out),.strobe_slow(stb_in) );

   initial
     begin
	rst <= 1;
	bypass <= 0;
	run <= 0;
	data_in <= 0;
	stb_out <= 1;
	cpo <= 1;

	repeat(10) @(posedge clk);
	rst <= 0;
	run <= 1;

	for (x=0; x<100000; x=x+1) begin
	   for (y=0; y<10000; y=y+1)
	     begin
		while (stb_in == 1'b0) @(posedge clk);
		triangle_wave(freq,data_in);
		@(posedge clk);

	     end
	   freq = freq * 2;
	end

	$finish;
     end // initial begin




   reg signed [18:0] phase_acc = 0;
   reg 	      direction = 0;


   task triangle_wave;
      input [15:0] inc;
      output [17:0] data_out;

      begin
	 if (direction) begin
	    phase_acc = phase_acc - inc;
	    if (phase_acc < -19'sh20000) begin
	       direction = 0;
	       phase_acc = phase_acc + inc;
	    end
	 end else begin
	    phase_acc = phase_acc + inc;
	    if (phase_acc > 19'sh1ffff) begin
	       direction = 1;
	       phase_acc = phase_acc - inc;
	    end
	 end
	 data_out = phase_acc[17:0];
      end

   endtask // triangle_wave



endmodule // hb47_int_tb