dakies/OSS_Verilog huggingface dataset:
module dsp_tx_glue
#(
    //the dsp unit number: 0, 1, 2...
    parameter DSPNO = 0,

    //frontend bus width
    parameter WIDTH = 24
)
(
    //control signals
    input clock, input reset, input clear, input enable,

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate outputs directly to the TX frontend
    output [WIDTH-1:0] frontend_i,
    output [WIDTH-1:0] frontend_q,

    //full rate outputs directly from the DUC chain
    input [WIDTH-1:0] duc_out_i,
    input [WIDTH-1:0] duc_out_q,

    //strobed samples {I16,Q16} to the TX DUC chain
    output [31:0] duc_in_sample,
    input duc_in_strobe, //this is a backpressure signal
    output duc_in_enable, //enables DUC module

    //strobbed baseband samples {I16,Q16} to this module
    input [31:0] bb_sample,
    output bb_strobe, //this is a backpressure signal

    //debug output (optional)
    output [31:0] debug
);

    generate
        if (DSPNO==0) begin
            `ifndef TX_DSP0_MODULE
            assign frontend_i = duc_out_i;
            assign frontend_q = duc_out_q;
            assign duc_in_sample = bb_sample;
            assign bb_strobe = duc_in_strobe;
            assign duc_in_enable = enable;
            `else
            `TX_DSP0_MODULE #(.WIDTH(WIDTH)) tx_dsp0_custom
            (
                .clock(clock), .reset(reset), .clear(clear), .enable(enable),
                .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
                .frontend_i(frontend_i), .frontend_q(frontend_q),
                .duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
                .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
                .bb_sample(bb_sample), .bb_strobe(bb_strobe)
            );
            `endif
        end
        else begin
            `ifndef TX_DSP1_MODULE
            assign frontend_i = duc_out_i;
            assign frontend_q = duc_out_q;
            assign duc_in_sample = bb_sample;
            assign bb_strobe = duc_in_strobe;
            assign duc_in_enable = enable;
            `else
            `TX_DSP1_MODULE #(.WIDTH(WIDTH)) tx_dsp1_custom
            (
                .clock(clock), .reset(reset), .clear(clear), .enable(enable),
                .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
                .frontend_i(frontend_i), .frontend_q(frontend_q),
                .duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
                .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
                .bb_sample(bb_sample), .bb_strobe(bb_strobe)
            );
            `endif
        end
    endgenerate

endmodule //dsp_tx_glue
module ddc_chain_tb();
   
   reg clk, rst;

   initial rst = 1;
   initial #1000 rst = 0;
   initial clk = 0;
   always #5 clk = ~clk;
   
   initial $dumpfile("ddc_chain_tb.vcd");
   initial $dumpvars(0,ddc_chain_tb);
   
   reg signed [23:0] adc_in;
   wire signed [15:0] adc_out_i, adc_out_q;

   always @(posedge clk)
     begin
	$display(adc_in);
	$display(adc_out_i);
	$display(adc_out_q);
     end	

   reg run;
   reg set_stb;
   reg [7:0] set_addr;
   reg [31:0] set_data;
   
   ddc_chain #(.BASE(0)) ddc_chain
     (.clk(clk),.rst(rst),
      .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
      .adc_i(adc_in), .adc_ovf_i(0),
      .adc_q(0), .adc_ovf_q(0),
      .sample({adc_out_i,adc_out_q}),
      .run(run), .strobe(), .debug());

   initial
     begin
	run <= 0;
	@(negedge rst);
	@(posedge clk);
	set_addr <= 1;
	set_data <= {16'd64,16'd64};  // set gains
	set_stb <= 1;
	@(posedge clk);
	set_addr <= 2;
	set_data <= {16'd0,8'd3,8'd1}; // set decim
	set_stb <= 1;
	@(posedge clk);
	set_addr <= 0;
	//set_data <= {32'h0000_0000};
	set_data <= {32'h01CA_C083}; // 700 kHz
	set_stb <= 1;
	@(posedge clk);
	set_stb <= 0;
	@(posedge clk);
	run <= 1;
     end

   always @(posedge clk)
     //adc_in <= 24'd1000000;
     adc_in <= 24'h80_0000;
   
   /*
   always @(posedge clk)
     if(rst)
       adc_in <= 0;
     else
       adc_in <= adc_in + 4;
   //adc_in <= (($random % 473) + 23)/4;
*/   
endmodule // ddc_chain_tb
module small_hb_dec
  #(parameter WIDTH=18)
    (input clk,
     input rst,
     input bypass,
     input run,
     input stb_in,
     input [WIDTH-1:0] data_in,
     output reg stb_out,
     output reg [WIDTH-1:0] data_out);

   // Round off inputs to 17 bits because of 18 bit multipliers
   localparam INTWIDTH = 17;
   wire [INTWIDTH-1:0] 	data_rnd;
   wire 		stb_rnd;
   
   round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
     (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
   	
   
   reg 			stb_rnd_d1;
   reg [INTWIDTH-1:0] 	data_rnd_d1;
   always @(posedge clk) stb_rnd_d1 <= stb_rnd;
   always @(posedge clk) data_rnd_d1 <= data_rnd;
   
   wire 		go;
   reg 			phase, go_d1, go_d2, go_d3, go_d4;
   always @(posedge clk)
     if(rst | ~run)
       phase <= 0;
     else if(stb_rnd_d1)
       phase <= ~phase;
   assign 		go = stb_rnd_d1 & phase;
   always @(posedge clk) 
     if(rst | ~run)
       begin
	  go_d1 <= 0;
	  go_d2 <= 0;
	  go_d3 <= 0;
	  go_d4 <= 0;
       end
     else
       begin
	  go_d1 <= go;
	  go_d2 <= go_d1;
	  go_d3 <= go_d2;
	  go_d4 <= go_d3;
       end

   wire [17:0] 		coeff_a = -10690;
   wire [17:0] 		coeff_b = 75809;
   
   reg [INTWIDTH-1:0] 	d1, d2, d3, d4 , d5, d6;
   always @(posedge clk)
     if(stb_rnd_d1 | rst)
       begin
	  d1 <= data_rnd_d1;
	  d2 <= d1;
	  d3 <= d2;
	  d4 <= d3;
	  d5 <= d4;
	  d6 <= d5;
       end

   reg [17:0] sum_a, sum_b, middle, middle_d1;

   always @(posedge clk)
     if(go)
       begin
	  sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6};
	  sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4};
	  //middle <= {d3[INTWIDTH-1],d3};
	  middle <= {d3,1'b0};
       end

   always @(posedge clk)
     if(go_d1)
       middle_d1 <= middle;
   
   wire [17:0] sum = go_d1 ? sum_b : sum_a;
   wire [17:0] coeff = go_d1 ? coeff_b : coeff_a;
   wire [35:0] 	 prod;   
   MULT18X18S mult(.C(clk), .CE(go_d1 | go_d2), .R(rst), .P(prod), .A(coeff), .B(sum) );

   localparam ACCWIDTH = 30;
   reg [ACCWIDTH-1:0] 	 accum;
   
   wire [ACCWIDTH-1:0] prod_acc_rnd;
   round #(.bits_in(36),.bits_out(ACCWIDTH),
           .round_to_zero(1),.round_to_nearest(0),.trunc(0)) round_prod
     (.in(prod), .out(prod_acc_rnd));

   always @(posedge clk)
     if(rst)
       accum <= 0;
     else if(go_d2)
       accum <= {middle_d1[17],middle_d1[17],middle_d1,{(16+ACCWIDTH-36){1'b0}}} + prod_acc_rnd;
     else if(go_d3)
       accum <= accum + prod_acc_rnd;
   
   wire [WIDTH:0] 	 accum_rnd;
   wire [WIDTH-1:0] 	 accum_rnd_clip;
   
   wire 	 stb_round;
   
   round_sd #(.WIDTH_IN(ACCWIDTH),.WIDTH_OUT(WIDTH+1)) round_acc 
     (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round));

   clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip));
   
   // Output
   always @(posedge clk)
     begin
	stb_out  <= bypass ? stb_in : stb_round;
	data_out <= bypass ? data_in : accum_rnd_clip;
     end


endmodule // small_hb_dec
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 [WIDTH-1:0] in, 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;
   wire [WIDTH-1:0]    quantized;

   always @(posedge clk)
     if(rst)
       begin
	  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)
       integrator <= integrator +  {{(alpha_shift){out[WIDTH-1]}},out};

   round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd
     (.clk(clk), .reset(rst), .in(integrator), .strobe_in(1'b1), .out(quantized), .strobe_out());
   
   add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg
     (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(1'b1), .sum(out), .strobe_out());

endmodule // rx_dcoffset
module rssi (input clock, input reset, input enable,
	     input [11:0] adc, output [15:0] rssi, output [15:0] over_count);

   wire 		  over_hi = (adc == 12'h7FF);
   wire 		  over_lo = (adc == 12'h800);
   wire 		  over = over_hi | over_lo;

   reg [25:0] 		  over_count_int;
   always @(posedge clock)
     if(reset | ~enable)
       over_count_int <= #1 26'd0;
     else
       over_count_int <= #1 over_count_int + (over ? 26'd65535 : 26'd0) - over_count_int[25:10];
   
   assign      over_count = over_count_int[25:10];
   
   wire [11:0] abs_adc = adc[11] ? ~adc : adc;

   reg [25:0]  rssi_int;
   always @(posedge clock)
     if(reset | ~enable)
       rssi_int <= #1 26'd0;
     else
       rssi_int <= #1 rssi_int + abs_adc - rssi_int[25:10];

   assign      rssi = rssi_int[25:10];
   
endmodule // rssi
module duc(input clock,
			input reset,
			input enable,
			input [3:0] rate1,
			input [3:0] rate2,
			output strobe,
			input [31:0] freq,
			input [15:0] i_in,
			input [15:0] q_in,
			output [15:0] i_out,
			output [15:0] q_out
			);
   parameter bw = 16;
   parameter zw = 16;
   
	wire [15:0] i_interp_out, q_interp_out;
	wire [31:0] phase;

	wire strobe1, strobe2;
	reg [3:0] strobe_ctr1,strobe_ctr2;

	always @(posedge clock)
		if(reset | ~enable)
			strobe_ctr2 <= #1 4'd0;
		else if(strobe2)
			strobe_ctr2 <= #1 4'd0;
		else	
			strobe_ctr2 <= #1 strobe_ctr2 + 4'd1;
				
	always @(posedge clock)
		if(reset | ~enable)
			strobe_ctr1 <= #1 4'd0;
		else if(strobe1)
			strobe_ctr1 <= #1 4'd0;
		else if(strobe2)
			strobe_ctr1 <= #1 strobe_ctr1 + 4'd1;
				

	assign strobe2 = enable & ( strobe_ctr2 == rate2 );
	assign strobe1 = strobe2 & ( strobe_ctr1 == rate1 );

	assign strobe = strobe1;

	function [2:0] log_ceil;
	input [3:0] val;
	
		log_ceil = val[3] ? 3'd4 : val[2] ? 3'd3 : val[1] ? 3'd2 : 3'd1; 
	endfunction	
	
	wire [2:0] shift1 = log_ceil(rate1);
	wire [2:0] shift2 = log_ceil(rate2);
	
	cordic #(.bitwidth(bw),.zwidth(zw),.stages(16))
		cordic(.clock(clock), .reset(reset), .enable(enable),
			.xi(i_interp_out), .yi(q_interp_out), .zi(phase[31:32-zw]), 
			.xo(i_out), .yo(q_out), .zo()  );
		
	cic_interp_2stage #(.bw(bw),.N(4)) 
		interp_i(.clock(clock),.reset(reset),.enable(enable),
			.strobe1(strobe1),.strobe2(strobe2),.strobe3(1'b1),.shift1(shift1),.shift2(shift2),
			.signal_in(i_in),.signal_out(i_interp_out));

	cic_interp_2stage #(.bw(bw),.N(4)) 
		interp_q(.clock(clock),.reset(reset),.enable(enable),
			.strobe1(strobe1),.strobe2(strobe2),.strobe3(1'b1),.shift1(shift1),.shift2(shift2),
			.signal_in(q_in),.signal_out(q_interp_out));
	
	phase_acc #(.resolution(32))
		nco (.clk(clock),.reset(reset),.enable(enable),
			.freq(freq),.phase(phase));
		
endmodule
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 		   phase;
   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(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_out])) ? 0 :
				 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 ddc(input clock,
			input reset,
			input enable,
			input [3:0] rate1,
			input [3:0] rate2,
			output strobe,
			input [31:0] freq,
			input [15:0] i_in,
			input [15:0] q_in,
			output [15:0] i_out,
			output [15:0] q_out
			);
   parameter bw = 16;
   parameter zw = 16;

	wire [15:0] i_cordic_out, q_cordic_out;
	wire [31:0] phase;

	wire strobe1, strobe2;
	reg [3:0] strobe_ctr1,strobe_ctr2;

	always @(posedge clock)
		if(reset | ~enable)
			strobe_ctr2 <= #1 4'd0;
		else if(strobe2)
			strobe_ctr2 <= #1 4'd0;
		else	
			strobe_ctr2 <= #1 strobe_ctr2 + 4'd1;
				
	always @(posedge clock)
		if(reset | ~enable)
			strobe_ctr1 <= #1 4'd0;
		else if(strobe1)
			strobe_ctr1 <= #1 4'd0;
		else if(strobe2)
			strobe_ctr1 <= #1 strobe_ctr1 + 4'd1;
				

	assign strobe2 = enable & ( strobe_ctr2 == rate2 );
	assign strobe1 = strobe2 & ( strobe_ctr1 == rate1 );

	assign strobe = strobe1;

	function [2:0] log_ceil;
	input [3:0] val;
	
		log_ceil = val[3] ? 3'd4 : val[2] ? 3'd3 : val[1] ? 3'd2 : 3'd1; 
	endfunction	
	
	wire [2:0] shift1 = log_ceil(rate1);
	wire [2:0] shift2 = log_ceil(rate2);
	
	cordic #(.bitwidth(bw),.zwidth(zw),.stages(16))
		cordic(.clock(clock), .reset(reset), .enable(enable),
			.xi(i_in), .yi(q_in), .zi(phase[31:32-zw]), 
			.xo(i_cordic_out), .yo(q_cordic_out), .zo()  );
		
	cic_decim_2stage #(.bw(bw),.N(4)) 
		decim_i(.clock(clock),.reset(reset),.enable(enable),
			.strobe1(1'b1),.strobe2(strobe2),.strobe3(strobe1),.shift1(shift2),.shift2(shift1),
			.signal_in(i_cordic_out),.signal_out(i_out));
			
	cic_decim_2stage #(.bw(bw),.N(4)) 
		decim_q(.clock(clock),.reset(reset),.enable(enable),
			.strobe1(1'b1),.strobe2(strobe2),.strobe3(strobe1),.shift1(shift2),.shift2(shift1),
			.signal_in(q_cordic_out),.signal_out(q_out));
	
	phase_acc #(.resolution(32))
		nco (.clk(clock),.reset(reset),.enable(enable),
			.freq(freq),.phase(phase));
		
endmodule
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 <= strobe_in;
   
endmodule // add2_and_clip_reg
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 [WIDTH_OUT-1:0] out, output strobe_out);

   localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1;

   wire [ERR_WIDTH-1:0]  err;
   wire [WIDTH_IN-1:0] 	 err_ext, sum;
  
   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 : 0), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_out));
   
   round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out), .err(err));
   
endmodule // round_sd
module halfband_ideal (
    input                           clock,
    input                           reset,
    input                           enable,
    input                           strobe_in,
    input   wire    signed  [17:0]  data_in,
    output  reg                     strobe_out,
    output  reg     signed  [17:0]  data_out
) ;

    parameter                       decim   = 1 ;
    parameter                       rate    = 2 ;

    reg signed              [40:0]  temp ;
    reg signed              [17:0]  delay[30:0] ;
    reg signed              [17:0]  coeffs[30:0] ;
    reg                     [7:0]   count ;
    integer                         i ;

    initial begin
        for( i = 0 ; i < 31 ; i = i + 1 ) begin
            coeffs[i] = 18'd0 ;
        end
        coeffs[0]   = -1390 ;
        coeffs[2]   = 1604 ;
        coeffs[4]   = -1896 ;
        coeffs[6]   = 2317 ;
        coeffs[8]   = -2979 ;
        coeffs[10]  = 4172 ;
        coeffs[12]  = -6953 ;
        coeffs[14]  = 20860 ;
        coeffs[15]  = 32768 ;
        coeffs[16]  = 20860 ;
        coeffs[18]  = -6953 ;
        coeffs[20]  = 4172 ;
        coeffs[22]  = -2979 ;
        coeffs[24]  = 2317 ;
        coeffs[26]  = -1896 ;
        coeffs[28]  = 1604 ;
        coeffs[30]  = -1390 ;
    end

    always @(posedge clock) begin
        if( reset ) begin
            count <= 0 ;
            for( i = 0 ; i < 31 ; i = i + 1 ) begin
                delay[i] <= 18'd0 ;
            end
            temp        <= 41'd0 ;
            data_out    <= 18'd0 ;
            strobe_out  <= 1'b0 ;
        end else if( enable ) begin

            if( (decim && (count == rate-1)) || !decim ) 
                strobe_out <= strobe_in ;
            else
                strobe_out <= 1'b0 ;
            

            if( strobe_in ) begin
                // Increment decimation count
                count <= count + 1 ;

                // Shift the input
                for( i = 30 ; i > 0 ; i = i - 1 ) begin
                    delay[i] = delay[i-1] ;
                end
                delay[0] = data_in ;

                // clear the temp reg
                temp = 18'd0 ;
                if( (decim && (count == rate-1)) || !decim ) begin
                    count <= 0 ;
                    for( i = 0 ; i < 31 ; i = i + 1 ) begin
                        // Multiply Accumulate
                        temp = temp + delay[i]*coeffs[i] ;
                    end
                    // Assign data output
                    data_out <= temp >>> 15 ;
                end
            end
        end
    end
endmodule
module clip_reg
  #(parameter bits_in=0,
    parameter bits_out=0,
    parameter STROBED=1'b0)
    (input clk,
     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 <= strobe_in;
   
   always @(posedge clk)
     if(strobe_in | ~STROBED)
       out <= temp;
   
endmodule // clip_reg
module rx_dcoffset_tb();
   
   reg clk, rst;

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

   reg [13:0] adc_in;
   wire [13:0] adc_out;

   always @(posedge clk)
     begin
	if(adc_in[13])
	  $write("-%d,",-adc_in);
	else
	  $write("%d,",adc_in);
	if(adc_out[13])
	  $write("-%d\n",-adc_out);
	else
	  $write("%d\n",adc_out);
     end	
   
   rx_dcoffset #(.WIDTH(14),.ADDR(0), .alpha_shift(8))
     rx_dcoffset(.clk(clk),.rst(rst),.set_stb(0),.set_addr(0),.set_data(0),
		 .in(adc_in),.out(adc_out));

   always @(posedge clk)
     adc_in <= (($random % 473) + 23)/4;
   
endmodule // longfifo_tb
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 [17: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());

   generate
      if(IQCOMP_EN == 1)
	begin
	   reg [17: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

	   rx_dcoffset #(.WIDTH(18),.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,2'b00}),.out(adc_i_ofs));
	   
	   rx_dcoffset #(.WIDTH(18),.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,2'b00}),.out(adc_q_ofs));
	   
	   MULT18X18S mult_mag_corr
	     (.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) ); 
	   
	   MULT18X18S mult_phase_corr
	     (.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
	   
	   add2_and_clip_reg #(.WIDTH(24)) add_clip_i
	     (.clk(clk), .rst(rst), 
	      .in1({adc_i_ofs_dly,6'd0}), .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,6'd0}), .in2(corr_q[35:12]), .strobe_in(1'b1),
	      .sum(q_out), .strobe_out());
	end // if (IQCOMP_EN == 1)
      else
	begin
	   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}),.out(i_out));
	   
	   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}),.out(q_out));
	end // else: !if(IQCOMP_EN == 1)
      endgenerate
   
endmodule // rx_frontend
module round_tb();

   localparam IW=8;
   localparam OW=4;
   localparam EW=IW-OW+1;
   
   reg signed [IW-1:0] in;
   wire signed [OW-1:0] out;
   wire signed [EW-1:0] err;

   round #(.bits_in(IW),
	   .bits_out(OW),
	   .round_to_zero(0),       // original behavior
	   .round_to_nearest(1),    // lowest noise
	   .trunc(0))               // round to negative infinity
   round (.in(in),.out(out),.err(err));

   initial $dumpfile("round_tb.vcd");
   initial $dumpvars(0,round_tb);

   wire signed [IW-1:0] out_round = {out,{IW-OW{1'b0}}};
   
   initial
     begin
	in <= -129;
	#1;
	repeat (260)
	  begin
	     in <= in + 1;
	     #1;
	     $display("In %d, out %d, out_rnd %d, err %d, real err %d",in,out,out_round,-err,out_round-in);
	     #1;
	  end
	$finish;
     end
     
endmodule // round
module pipectrl
  #(parameter STAGES = 2, 
    parameter TAGWIDTH = 1)
   (input clk,
    input reset,
    input src_rdy_i,
    output dst_rdy_o,
    output src_rdy_o,
    input dst_rdy_i,
    output [STAGES-1:0] strobes,
    output [STAGES-1:0] valids,
    input [TAGWIDTH-1:0] tag_i,
    output [TAGWIDTH-1:0] tag_o);

   wire 		new_input = src_rdy_i & dst_rdy_o;
   wire 		new_output = src_rdy_o & dst_rdy_i;
   wire [TAGWIDTH-1:0] 	tags [STAGES-1:0];

   assign dst_rdy_o = ~valids[0] | strobes[1];

   pipestage #(.TAGWIDTH(TAGWIDTH)) head
     (.clk(clk),.reset(reset), .stb_in(strobes[0]), .stb_out(strobes[1]),.valid(valids[0]),
      .tag_in(tag_i), .tag_out(tags[0]));
   assign strobes[0] = src_rdy_i & (~valids[0] | strobes[1]);

   genvar 		i;
   generate
      for(i = 1; i < STAGES - 1; i = i + 1)
	begin : gen_stages
	   pipestage #(.TAGWIDTH(TAGWIDTH)) pipestage
	     (.clk(clk),.reset(reset), .stb_in(strobes[i]),.stb_out(strobes[i+1]),.valid(valids[i]),
	      .tag_in(tags[i-1]),.tag_out(tags[i]));
	   assign strobes[i] = valids[i-1] & (~valids[i] | strobes[i+1]);
	end
   endgenerate

   pipestage #(.TAGWIDTH(TAGWIDTH)) tail
     (.clk(clk),.reset(reset), .stb_in(strobes[STAGES-1]), .stb_out(dst_rdy_i),.valid(valids[STAGES-1]),
      .tag_in(tags[STAGES-2]), .tag_out(tags[STAGES-1]));
   assign strobes[STAGES-1] = valids[STAGES-2] & (~valids[STAGES-1] | new_output);
   
   assign src_rdy_o = valids[STAGES-1];

   assign tag_o = tags[STAGES-1];
   
endmodule // pipectrl
module clip_and_round_reg
  #(parameter bits_in=0,
    parameter bits_out=0,
    parameter clip_bits=0)
    (input clk,
     input [bits_in-1:0] in,
     output reg [bits_out-1:0] out);

   wire [bits_out-1:0] 	   temp;

   clip_and_round #(.bits_in(bits_in),.bits_out(bits_out),.clip_bits(clip_bits))
     clip_and_round (.in(in),.out(temp));

   always@(posedge clk)
     out <= temp;
   
endmodule // clip_and_round_reg
module integrate
  #(parameter INPUTW = 16,
    parameter ACCUMW = 32,
    parameter OUTPUTW = 16)

   (input clk_i,
    input rst_i,
    input ena_i,

    input dump_i,
    input [INPUTW-1:0] data_i,

    output reg stb_o,
    output reg [OUTPUTW-1:0] integ_o
   );
   
   wire [ACCUMW-1:0] data_ext = {{ACCUMW-INPUTW{data_i[INPUTW-1]}},data_i};
   reg  [ACCUMW-1:0] accum;

   always @(posedge clk_i)
     if (rst_i | ~ena_i)
       begin
	  accum <= 0;
	  integ_o <= 0;
       end
     else
       if (dump_i)
	 begin
	    integ_o <= accum[ACCUMW-1:ACCUMW-OUTPUTW];
	    accum <= data_ext;
	 end
       else
	 accum <= accum + data_ext;

   always @(posedge clk_i)
     stb_o <= dump_i;
   
endmodule // integrate
module dummy_rx
  (input clk, input rst,
   input set_stb, input [7:0] set_addr, input [31:0] set_data,

   input [13:0] adc_a, input adc_ovf_a,
   input [13:0] adc_b, input adc_ovf_b,
   
   output [31:0] sample,
   input run,
   output strobe
   );

   wire [15:0] scale_i, scale_q;
   wire [31:0] phase_inc;
   reg [31:0]  phase;

   wire [23:0] i_decim, q_decim;
   wire [7:0]  decim_rate;
   
   setting_reg #(.my_addr(`DSP_CORE_RX_BASE+0)) sr_0
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(phase_inc),.changed());
   
   setting_reg #(.my_addr(`DSP_CORE_RX_BASE+1)) sr_1
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out({scale_i,scale_q}),.changed());
   
   setting_reg #(.my_addr(`DSP_CORE_RX_BASE+2)) sr_2
     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(decim_rate),.changed());
   
   strobe_gen strobe_gen(.clock(clk),.reset(rst),.enable(run),.rate(decim_rate),
			 .strobe_in(1),.strobe(strobe) );

   reg [15:0] i_out, q_out;
   assign      sample = {i_out,q_out};

   always @(posedge clk)
     if(rst)
       i_out <= 0;
     else if(~run)
       i_out <= 0;
     else if(strobe)
       i_out <= i_out + 1;

   reg 	       run_d1;
   always @(posedge clk)
     if(rst)
       run_d1 <= 0;
     else
       run_d1 <= run;

   always @(posedge clk)
     if(rst)
       q_out <= 0;
     else if (run & ~run_d1)
       q_out <= q_out + 1;
       
   
endmodule // ddc_chain
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 [17:0] adc_out;

   always @(posedge clk)
     begin
	if(adc_in[13])
	  $write("-%d,",-adc_in);
	else
	  $write("%d,",adc_in);
	if(adc_out[13])
	  $write("-%d\n",-adc_out);
	else
	  $write("%d\n",adc_out);
     end	
   
   rx_frontend #(.BASE(0)) 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 dsp_rx_glue
#(
    //the dsp unit number: 0, 1, 2...
    parameter DSPNO = 0,

    //frontend bus width
    parameter WIDTH = 24
)
(
    //control signals
    input clock, input reset, input clear, input enable,

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate inputs directly from the RX frontend
    input [WIDTH-1:0] frontend_i,
    input [WIDTH-1:0] frontend_q,

    //full rate outputs directly to the DDC chain
    output [WIDTH-1:0] ddc_in_i,
    output [WIDTH-1:0] ddc_in_q,

    //strobed samples {I16,Q16} from the RX DDC chain
    input [31:0] ddc_out_sample,
    input ddc_out_strobe, //high on valid sample
    output ddc_out_enable, //enables DDC module

    //strobbed baseband samples {I16,Q16} from this module
    output [31:0] bb_sample,
    output bb_strobe, //high on valid sample

    //debug output (optional)
    output [31:0] debug
);

    generate
        if (DSPNO==0) begin
            `ifndef RX_DSP0_MODULE
            assign ddc_in_i = frontend_i;
            assign ddc_in_q = frontend_q;
            assign bb_sample = ddc_out_sample;
            assign bb_strobe = ddc_out_strobe;
            assign ddc_out_enable = enable;
            `else
            `RX_DSP0_MODULE #(.WIDTH(WIDTH)) rx_dsp0_custom
            (
                .clock(clock), .reset(reset), .clear(clear), .enable(enable),
                .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
                .frontend_i(frontend_i), .frontend_q(frontend_q),
                .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
                .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
                .bb_sample(bb_sample), .bb_strobe(bb_strobe)
            );
            `endif
        end
        else begin
            `ifndef RX_DSP1_MODULE
            assign ddc_in_i = frontend_i;
            assign ddc_in_q = frontend_q;
            assign bb_sample = ddc_out_sample;
            assign bb_strobe = ddc_out_strobe;
            assign ddc_out_enable = enable;
            `else
            `RX_DSP1_MODULE #(.WIDTH(WIDTH)) rx_dsp1_custom
            (
                .clock(clock), .reset(reset), .clear(clear), .enable(enable),
                .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
                .frontend_i(frontend_i), .frontend_q(frontend_q),
                .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
                .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
                .bb_sample(bb_sample), .bb_strobe(bb_strobe)
            );
            `endif
        end
    endgenerate

endmodule //dsp_rx_glue
module pipestage
  #(parameter TAGWIDTH = 1)
   (input clk,
    input reset,
    input stb_in,
    input stb_out,
    output reg valid,
    input [TAGWIDTH-1:0] tag_in,
    output reg [TAGWIDTH-1:0] tag_out);

   always @(posedge clk)
     if(reset)
       begin
	  valid <= 0;
	  tag_out <= 0;
       end
     else if(stb_in)
       begin
	  valid <= 1;
	  tag_out <= tag_in;
       end
     else if(stb_out)
       begin
	  valid <= 0;
	  tag_out <= 0;
       end
   
endmodule // pipestage
module med_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);

   localparam coeff_a = -597;
   localparam coeff_b = 4283;
   localparam coeff_c = -17516;
   localparam coeff_d = 79365;
   
   reg 	      phase;
   reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6, d7, d8;
   
   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(stb_in)
       begin
	  d1 <= data_in;
	  d2 <= d1;
	  d3 <= d2;
	  d4 <= d3;
	  d5 <= d4;
	  d6 <= d5;
	  d7 <= d6;
	  d8 <= d7;
       end

   wire [WIDTH-1:0] sum_a, sum_b, sum_c, sum_d;
   add2_and_round_reg #(.WIDTH(WIDTH)) add_a (.clk(clk),.in1(d1),.in2(d8),.sum(sum_a));
   add2_and_round_reg #(.WIDTH(WIDTH)) add_b (.clk(clk),.in1(d2),.in2(d7),.sum(sum_b));
   add2_and_round_reg #(.WIDTH(WIDTH)) add_c (.clk(clk),.in1(d3),.in2(d6),.sum(sum_c));
   add2_and_round_reg #(.WIDTH(WIDTH)) add_d (.clk(clk),.in1(d4),.in2(d5),.sum(sum_d));

   MULT18X18S mult1(.C(clk), .CE(1), .R(rst), .P(prod1), .A(stbin_d[1] ? coeff_a : coeff_b), 
		    .B(stbin_d[1] ? sum_a : sum_b) );
   MULT18X18S mult2(.C(clk), .CE(1), .R(rst), .P(prod2), .A(stbin_d[1] ? coeff_c : coeff_d), 
		    .B(stbin_d[1] ? sum_c : sum_d) );

   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),.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 power_trig_tb();
   initial $dumpfile("power_trig_tb.vcd");
   initial $dumpvars(0,power_trig_tb);

   reg clk = 0;
   always #10 clk <= ~clk;
   reg rst = 1;
   initial #100 rst <= 0;

   initial
     begin
	set_stb <= 0;
	#1000;
	set_stb <= 1;
     end
   
   reg [31:0] sample_in;
   reg 	      strobe_in;
   wire [31:0] sample_out;
   wire        strobe_out;
   reg 	       set_stb, run;
   
   power_trig #(.BASE(0)) power_trig
     (.clk(clk), .reset(rst), .enable(1),
      .set_stb(set_stb), .set_addr(0), .set_data(32'h000B_B000),
      .run(run),

      .ddc_out_sample(sample_in), .ddc_out_strobe(strobe_in),
      .bb_sample(sample_out), .bb_strobe(strobe_out));

   initial sample_in <= 32'h0100_0300;
   
   always @(posedge clk)
     if(~strobe_in)
       sample_in <= sample_in + 32'h0001_0001;

   initial
     #100000 $finish;

   initial 
     begin
	run <= 0;
	#2000 run <= 1;
	#30000 run <= 0;
     end

   always @(posedge clk)
     if(rst | ~run)
       strobe_in <= 0;
     else
       strobe_in <= ~strobe_in;
   
endmodule // power_trig_tb
module power_trig
#(
    //frontend bus width
    parameter WIDTH = 24,
    parameter BASE = 0
)
(
    //control signals
    input clock, //dsp clock
    input reset, //active high synchronous reset
    input clear, //active high on packet control init
    input enable, //active high when streaming enabled

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate inputs directly from the RX frontend
    input [WIDTH-1:0] frontend_i,
    input [WIDTH-1:0] frontend_q,

    //full rate outputs directly to the DDC chain
    output [WIDTH-1:0] ddc_in_i,
    output [WIDTH-1:0] ddc_in_q,

    //strobed samples {I16,Q16} from the RX DDC chain
    input [31:0] ddc_out_sample,
    input ddc_out_strobe, //high on valid sample
    output ddc_out_enable, //enables DDC module

    //strobbed baseband samples {I16,Q16} from this module
    output [31:0] bb_sample,
    output bb_strobe //high on valid sample
);

    //leave frontend tied to existing ddc chain
    assign ddc_in_i = frontend_i;
    assign ddc_in_q = frontend_q;

    //ddc enable remains tied to global enable
    assign ddc_out_enable = enable;

    //below we implement a power trigger between baseband samples and ddc output...

   reg [8:0] 	  wr_addr;
   wire [8:0] 	  rd_addr;
   reg 		  triggered, triggerable;
   wire 	  trigger;
   
   wire [31:0] 	  delayed_sample;
   wire [31:0] 	  thresh;
   
   setting_reg #(.my_addr(BASE+0)) sr_0
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
      .in(set_data),.out(thresh),.changed());

   assign rd_addr = wr_addr + 1; // FIXME adjustable delay

   ram_2port  #(.DWIDTH(32),.AWIDTH(9)) delay_line
     (.clka(clk),.ena(1),.wea(ddc_out_strobe),.addra(wr_addr),.dia(ddc_out_sample),.doa(),
      .clkb(clk),.enb(ddc_out_strobe),.web(1'b0),.addrb(rd_addr),.dib(32'hFFFF),.dob(delayed_sample));

   always @(posedge clock)
     if(reset | ~enable)
       wr_addr <= 0;
     else
       if(ddc_out_strobe)
	 wr_addr <= wr_addr + 1;

   always @(posedge clock)
     if(reset | ~enable)
       triggerable <= 0;
     else if(wr_addr == 9'h1FF)  // Wait till we're nearly full
       triggerable <= 1;
   

   reg 			      stb_d1, stb_d2;
   always @(posedge clock) stb_d1 <= ddc_out_strobe;
   always @(posedge clock) stb_d2 <= stb_d1;
   
   assign bb_sample = delayed_sample;
   assign bb_strobe = stb_d1 & triggered;

   // Compute Mag
   wire [17:0] 		      mult_in = stb_d1 ? { ddc_out_sample[15],ddc_out_sample[15:0], 1'b0 } : 
			      { ddc_out_sample[31], ddc_out_sample[31:16], 1'b0 };
   wire [35:0] 		      prod;
   reg [31:0] 		      sum;
   
   MULT18X18S mult (.P(prod), .A(mult_in), .B(mult_in), .C(clock), .CE(ddc_out_strobe | stb_d1), .R(reset) );

   always @(posedge clock)
     if(stb_d1)
       sum <= prod[35:4];
     else if(stb_d2)
       sum <= sum + prod[35:4];

   always @(posedge clock)
     if(reset | ~enable | ~triggerable)
       triggered <= 0;
     else if(trigger)
       triggered <= 1;

   assign trigger = (sum > thresh);
   
endmodule // power_trig
module custom_engine_rx
#(
    //buffer size for ram interface engine
    parameter BUF_SIZE = 10
)
(
    //control signals
    input clock, input reset, input clear,

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //ram interface for engine
    output access_we,
    output access_stb,
    input access_ok,
    output access_done,
    output access_skip_read,
    output [BUF_SIZE-1:0] access_adr,
    input [BUF_SIZE-1:0] access_len,
    output [35:0] access_dat_o,
    input [35:0] access_dat_i
);

    assign access_done = access_ok;

endmodule //custom_engine_rx
module custom_engine_tx
#(
    //buffer size for ram interface engine
    parameter BUF_SIZE = 10,

    //the number of 32bit lines between start of buffer and vita header
    //the metadata before the header should be preserved by the engine
    parameter HEADER_OFFSET = 0
)
(
    //control signals
    input clock, input reset, input clear,

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //ram interface for engine
    output access_we,
    output access_stb,
    input access_ok,
    output access_done,
    output access_skip_read,
    output [BUF_SIZE-1:0] access_adr,
    input [BUF_SIZE-1:0] access_len,
    output [35:0] access_dat_o,
    input [35:0] access_dat_i
);

    assign access_done = access_ok;

endmodule //custom_engine_tx
module custom_dsp_tx
#(
    //frontend bus width
    parameter WIDTH = 24
)
(
    //control signals
    input clock, //dsp clock
    input reset, //active high synchronous reset
    input clear, //active high on packet control init
    input enable, //active high when streaming enabled

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate outputs directly to the TX frontend
    output [WIDTH-1:0] frontend_i,
    output [WIDTH-1:0] frontend_q,

    //full rate outputs directly from the DUC chain
    input [WIDTH-1:0] duc_out_i,
    input [WIDTH-1:0] duc_out_q,

    //strobed samples {I16,Q16} to the TX DUC chain
    output [31:0] duc_in_sample,
    input duc_in_strobe, //this is a backpressure signal
    output duc_in_enable, //enables DUC module

    //strobbed baseband samples {I16,Q16} to this module
    input [31:0] bb_sample,
    output bb_strobe //this is a backpressure signal
);

    assign frontend_i = duc_out_i;
    assign frontend_q = duc_out_q;
    assign duc_in_sample = bb_sample;
    assign bb_strobe = duc_in_strobe;
    assign duc_in_enable = enable;

endmodule //custom_dsp_tx
module custom_dsp_rx
#(
    //frontend bus width
    parameter WIDTH = 24
)
(
    //control signals
    input clock, //dsp clock
    input reset, //active high synchronous reset
    input clear, //active high on packet control init
    input enable, //active high when streaming enabled

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate inputs directly from the RX frontend
    input [WIDTH-1:0] frontend_i,
    input [WIDTH-1:0] frontend_q,

    //full rate outputs directly to the DDC chain
    output [WIDTH-1:0] ddc_in_i,
    output [WIDTH-1:0] ddc_in_q,

    //strobed samples {I16,Q16} from the RX DDC chain
    input [31:0] ddc_out_sample,
    input ddc_out_strobe, //high on valid sample
    output ddc_out_enable, //enables DDC module

    //strobbed baseband samples {I16,Q16} from this module
    output [31:0] bb_sample,
    output bb_strobe //high on valid sample
);

    assign ddc_in_i = frontend_i;
    assign ddc_in_q = frontend_q;
    assign bb_sample = ddc_out_sample;
    assign bb_strobe = ddc_out_strobe;
    assign ddc_out_enable = enable;

endmodule //custom_dsp_rx
module serdes_fc_rx
  #(parameter LWMARK = 64,
    parameter HWMARK = 320)
    (input clk, input rst,
     input [15:0] fifo_space, 
     output reg send_xon,
     output reg send_xoff,
     input sent);
    
   reg [15:0] 	  countdown;
   reg 		  send_xon_int, send_xoff_int;
   
   always @(posedge clk)
     if(rst)
       begin
	  send_xon_int <= 0;
	  send_xoff_int <= 0;
	  countdown <= 0;
       end
     else 
       begin
	  send_xon_int <= 0;
	  send_xoff_int <= 0;
	  if(countdown == 0)
	    if(fifo_space < LWMARK)
	      begin
		 send_xoff_int <= 1;
		 countdown <= 240;
	      end
	    else
	      ;
	  else
	    if(fifo_space > HWMARK)
	      begin
		 send_xon_int <= 1;
		 countdown <= 0;
	      end
	    else
	      countdown <= countdown - 1;
       end // else: !if(rst)

   // If we are between the high and low water marks, we let the countdown expire

   always @(posedge clk)
     if(rst)
       send_xon <= 0;
     else if(send_xon_int)
       send_xon <= 1;
     else if(sent)
       send_xon <= 0;

   always @(posedge clk)
     if(rst)
       send_xoff <= 0;
     else if(send_xoff_int)
       send_xoff <= 1;
     else if(sent)
       send_xoff <= 0;
   
endmodule // serdes_fc_rx
module serdes
  #(parameter TXFIFOSIZE = 9,
    parameter RXFIFOSIZE = 9)
    (input clk, input rst,
     // TX side
     output ser_tx_clk, output [15:0] ser_t, output ser_tklsb, output ser_tkmsb,
     input [31:0] rd_dat_i, input [3:0] rd_flags_i, output rd_ready_o, input rd_ready_i,
     // RX side
     input ser_rx_clk, input [15:0] ser_r, input ser_rklsb, input ser_rkmsb,
     output [31:0] wr_dat_o, output [3:0] wr_flags_o, output wr_ready_o, input wr_ready_i,

     output [15:0] tx_occupied, output tx_full, output tx_empty,
     output [15:0] rx_occupied, output rx_full, output rx_empty,

     output serdes_link_up,
     
     output [31:0] debug0, 
     output [31:0] debug1);

   wire [15:0] fifo_space;
   wire        xon_rcvd, xoff_rcvd, inhibit_tx, send_xon, send_xoff, sent;
   wire [31:0] debug_rx, debug_tx;

   serdes_tx #(.FIFOSIZE(TXFIFOSIZE)) serdes_tx
     (.clk(clk),.rst(rst),
      .ser_tx_clk(ser_tx_clk),.ser_t(ser_t),.ser_tklsb(ser_tklsb),.ser_tkmsb(ser_tkmsb),
      .rd_dat_i(rd_dat_i),.rd_flags_i(rd_flags_i),.rd_ready_o(rd_ready_o),.rd_ready_i(rd_ready_i),
      .inhibit_tx(inhibit_tx), .send_xon(send_xon), .send_xoff(send_xoff), .sent(sent),
      .fifo_occupied(tx_occupied),.fifo_full(tx_full),.fifo_empty(tx_empty),
      .debug(debug_tx) );
   
   serdes_rx #(.FIFOSIZE(RXFIFOSIZE)) serdes_rx
     (.clk(clk),.rst(rst),
      .ser_rx_clk(ser_rx_clk),.ser_r(ser_r),.ser_rklsb(ser_rklsb),.ser_rkmsb(ser_rkmsb),
      .wr_dat_o(wr_dat_o),.wr_flags_o(wr_flags_o),.wr_ready_o(wr_ready_o),.wr_ready_i(wr_ready_i),
      .fifo_space(fifo_space), .xon_rcvd(xon_rcvd), .xoff_rcvd(xoff_rcvd),
      .fifo_occupied(rx_occupied),.fifo_full(rx_full),.fifo_empty(rx_empty),
      .serdes_link_up(serdes_link_up), .debug(debug_rx) );

   serdes_fc_tx serdes_fc_tx
     (.clk(clk),.rst(rst),
      .xon_rcvd(xon_rcvd),.xoff_rcvd(xoff_rcvd),.inhibit_tx(inhibit_tx) );

   serdes_fc_rx #(.LWMARK(32),.HWMARK(128)) serdes_fc_rx
     (.clk(clk),.rst(rst),
      .fifo_space(fifo_space),.send_xon(send_xon),.send_xoff(send_xoff),.sent(sent) );

   //assign      debug = { fifo_space, send_xon, send_xoff, debug_rx[13:0] };
   //assign      debug = debug_rx;

   assign      debug0 = { { 2'b00, rd_ready_o, rd_ready_i, rd_flags_i[3:0]},
			  { debug_tx[5:4] /* full,empty */ , inhibit_tx, send_xon, send_xoff, sent, ser_tkmsb, ser_tklsb},
			  { ser_t[15:8] },
			  { ser_t[7:0] } };
   
   assign      debug1 = { { debug_rx[7:0] }, /*  odd,xfer_active,sop_i,eop_i,error_i,state[2:0] */
			  { wr_flags_o[1:0], wr_ready_i, wr_ready_o,  xon_rcvd, xoff_rcvd, ser_rkmsb, ser_rklsb },
			  { ser_r[15:8] },
			  { ser_r[7:0] } };
endmodule // serdes
module serdes_fc_tx
  (input clk, input rst,
   input xon_rcvd, input xoff_rcvd, output reg inhibit_tx);

   // XOFF means stop sending, XON means start sending
   // clock domain stuff happens elsewhere, everything here is on main clk

   reg [15:0] state;
   always @(posedge clk)
     if(rst)
       state <= 0;
     else if(xoff_rcvd)
       state <= 255;
     else if(xon_rcvd)
       state <= 0;
     else if(state !=0)
       state <= state - 1;

   always @(posedge clk)
     inhibit_tx <= (state != 0);
   
endmodule // serdes_fc_tx
module MULT18X18S
  (output reg signed [35:0] P,
   input signed [17:0] A,
   input signed [17:0] B,
   input C,    // Clock
   input CE,   // Clock Enable
   input R     // Synchronous Reset
   );
   
   always @(posedge C)
     if(R)
       P <= 36'sd0;
     else if(CE)
       P <= A * B;

endmodule // MULT18X18S