aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/fosphor
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/fosphor')
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/axi_logpwr.v102
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/delay.v140
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_avg.v117
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_binmap.v139
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_core.v609
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_eoseq.v78
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_histo_mem.v287
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_line_mem.v67
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_logpwr.v504
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_maxhold.v71
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_packetizer.v136
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_rise_decay.v160
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v189
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v169
-rw-r--r--fpga/usrp3/lib/rfnoc/fosphor/rng.v87
15 files changed, 2855 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/axi_logpwr.v b/fpga/usrp3/lib/rfnoc/fosphor/axi_logpwr.v
new file mode 100644
index 000000000..037c33563
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/axi_logpwr.v
@@ -0,0 +1,102 @@
+/*
+ * axi_logpwr.v
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module axi_logpwr #(
+ parameter [1:0] RANDOM_MODE = 2'b11
+)(
+ input clk, input reset,
+ input [31:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [15:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
+);
+
+ // Signals
+ reg ready;
+ reg valid_1;
+ wire valid_12;
+ wire last_12;
+
+ wire [31:0] rng;
+
+ wire [15:0] in_real_0;
+ wire [15:0] in_imag_0;
+ wire [15:0] out_logpwr_12;
+
+ wire [16:0] fifo_di;
+ wire [16:0] fifo_do;
+ wire fifo_wren;
+ wire fifo_afull;
+ wire fifo_rden;
+ wire fifo_empty;
+
+ // Input control
+ assign in_real_0 = i_tdata[31:16];
+ assign in_imag_0 = i_tdata[15:0];
+
+ always @(posedge clk)
+ begin
+ ready <= ~fifo_afull | o_tready;
+ valid_1 <= i_tvalid & ready;
+ end
+
+ assign i_tready = ready;
+
+ // Delays
+ delay_bit #(11) dl_valid (valid_1, valid_12, clk);
+ delay_bit #(12) dl_last (i_tlast, last_12, clk);
+
+ // RNG Instance
+ rng rng_I (
+ .out(rng),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // logpwr Instance
+ f15_logpwr logpwr_I (
+ .in_real_0(in_real_0),
+ .in_imag_0(in_imag_0),
+ .out_12(out_logpwr_12),
+ .rng(rng),
+ .random_mode(RANDOM_MODE),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Output FIFO
+ assign fifo_di = { last_12, out_logpwr_12 };
+ assign fifo_wren = { valid_12 };
+
+ fifo_srl #(
+ .WIDTH(17),
+ .LOG2_DEPTH(6),
+ .AFULL_LEVEL(49)
+ ) fifo_I (
+ .di(fifo_di),
+ .wren(fifo_wren),
+ .afull(fifo_afull),
+ .do(fifo_do),
+ .rden(fifo_rden),
+ .empty(fifo_empty),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ assign o_tdata = fifo_do[15:0];
+ assign o_tlast = fifo_do[16];
+ assign o_tvalid = ~fifo_empty;
+
+ assign fifo_rden = ~fifo_empty & o_tready;
+
+endmodule // axi_logpwr
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/delay.v b/fpga/usrp3/lib/rfnoc/fosphor/delay.v
new file mode 100644
index 000000000..44c043642
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/delay.v
@@ -0,0 +1,140 @@
+/*
+ * delay.v
+ *
+ * Generates a delay line/bus using a combination of SRL and Register
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+// ---------------------------------------------------------------------------
+// Single line delay
+// ---------------------------------------------------------------------------
+
+module delay_bit #(
+ parameter integer DELAY = 1
+)(
+ input wire d,
+ output wire q,
+ input wire clk
+);
+
+ // Signals
+ wire [4:0] addr = DELAY - 2;
+ wire ff_in;
+
+ // Generate SRL if needed (or bypass if not)
+ generate
+ if (DELAY > 17) begin
+ SRLC32E srl_I (
+ .Q(ff_in),
+ .A(addr),
+ .CE(1'b1),
+ .CLK(clk),
+ .D(d)
+ );
+ end else if (DELAY > 1) begin
+ SRL16E srl_I (
+ .Q(ff_in),
+ .A0(addr[0]),
+ .A1(addr[1]),
+ .A2(addr[2]),
+ .A3(addr[3]),
+ .CE(1'b1),
+ .CLK(clk),
+ .D(d)
+ );
+ end else begin
+ assign ff_in = d;
+ end
+ endgenerate
+
+ // Generate flip-flop if needed (or bypass if not)
+ generate
+ if (DELAY > 0) begin
+ FDRE ff_I (
+ .Q(q),
+ .C(clk),
+ .CE(1'b1),
+ .D(ff_in),
+ .R(1'b0)
+ );
+ end else begin
+ assign q = ff_in;
+ end
+ endgenerate
+
+endmodule // delay_bit
+
+
+// ---------------------------------------------------------------------------
+// Bus delay
+// ---------------------------------------------------------------------------
+
+module delay_bus #(
+ parameter integer DELAY = 1,
+ parameter integer WIDTH = 1
+)(
+ input wire [WIDTH-1:0] d,
+ output wire [WIDTH-1:0] q,
+ input wire clk
+);
+ genvar i;
+
+ // Variables / Signals
+ wire [4:0] addr = DELAY - 2;
+ wire [WIDTH-1:0] ff_in;
+
+ // Generate SRL if needed (or bypass if not)
+ generate
+ if (DELAY > 17) begin
+ for (i=0; i<WIDTH; i=i+1)
+ SRLC32E srl_I (
+ .Q(ff_in[i]),
+ .A(addr),
+ .CE(1'b1),
+ .CLK(clk),
+ .D(d[i])
+ );
+ end else if (DELAY > 1) begin
+ for (i=0; i<WIDTH; i=i+1)
+ SRL16E srl_I (
+ .Q(ff_in[i]),
+ .A0(addr[0]),
+ .A1(addr[1]),
+ .A2(addr[2]),
+ .A3(addr[3]),
+ .CE(1'b1),
+ .CLK(clk),
+ .D(d[i])
+ );
+ end else begin
+ assign ff_in = d;
+ end
+ endgenerate
+
+ // Generate flip-flop if needed (or bypass if not)
+ generate
+ if (DELAY > 0) begin
+ for (i=0; i<WIDTH; i=i+1)
+ FDRE ff_I (
+ .Q(q[i]),
+ .C(clk),
+ .CE(1'b1),
+ .D(ff_in[i]),
+ .R(1'b0)
+ );
+ end else begin
+ assign q = ff_in;
+ end
+ endgenerate
+
+endmodule // delay_bus
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_avg.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_avg.v
new file mode 100644
index 000000000..30123ee20
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_avg.v
@@ -0,0 +1,117 @@
+/*
+ * f15_avg.v
+ *
+ * Applies the y(t+1) = alpha * y(t) + (1 - alpha) * x(t)
+ * to compute an IIR average
+ *
+ * Copyright (C) 2015 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_avg #(
+ parameter integer Y_WIDTH = 12,
+ parameter integer X_WIDTH = 16
+)(
+ input wire [Y_WIDTH-1:0] yin_0,
+ input wire [X_WIDTH-1:0] x_0,
+ input wire [15:0] rng_0,
+ input wire [15:0] alpha_0,
+ input wire clear_0,
+ output wire [Y_WIDTH-1:0] yout_4,
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ wire [X_WIDTH-1:0] x_2;
+ wire clear_3;
+ wire [47:0] pout_4;
+
+ // Main DSP Instance
+ DSP48E1 #(
+ .A_INPUT("DIRECT"),
+ .B_INPUT("DIRECT"),
+ .USE_DPORT("TRUE"),
+ .USE_MULT("MULTIPLY"),
+ .AUTORESET_PATDET("NO_RESET"),
+ .MASK(48'h3fffffffffff),
+ .PATTERN(48'h000000000000),
+ .SEL_MASK("MASK"),
+ .SEL_PATTERN("PATTERN"),
+ .USE_PATTERN_DETECT("PATDET"),
+ .ACASCREG(1),
+ .ADREG(1),
+ .ALUMODEREG(1),
+ .AREG(1),
+ .BCASCREG(1),
+ .BREG(2),
+ .CARRYINREG(1),
+ .CARRYINSELREG(1),
+ .CREG(1),
+ .DREG(1),
+ .INMODEREG(1),
+ .MREG(1),
+ .OPMODEREG(1),
+ .PREG(1),
+ .USE_SIMD("ONE48")
+ )
+ dsp_avg_I (
+ .P(pout_4),
+ .ACIN(30'h0),
+ .BCIN(18'h0),
+ .CARRYCASCIN(1'h0),
+ .MULTSIGNIN(1'h0),
+ .PCIN(48'h000000000000),
+ .ALUMODE(4'b0000), // Z + X + Y + CIN
+ .CARRYINSEL(3'h0),
+ .CEINMODE(1'b1),
+ .CLK(clk),
+ .INMODE(5'b01100), // B=B2, A=D-A2
+ .OPMODE(7'b0110101), // X=M1, Y=M2, Z=C
+ .RSTINMODE(rst),
+ .A({{(30-X_WIDTH){1'b0}}, x_0}),
+ .B({2'h0, alpha_0}),
+ .C({{(32-X_WIDTH){1'b0}}, x_2, 16'h8000}),
+ .CARRYIN(1'b0),
+ .D({{(25-X_WIDTH){1'b0}}, yin_0, rng_0[X_WIDTH-Y_WIDTH-1:0]}),
+ .CEA1(1'b0),
+ .CEA2(1'b1),
+ .CEAD(1'b1),
+ .CEALUMODE(1'b1),
+ .CEB1(1'b1),
+ .CEB2(1'b1),
+ .CEC(1'b1),
+ .CECARRYIN(1'b1),
+ .CECTRL(1'b1),
+ .CED(1'b1),
+ .CEM(1'b1),
+ .CEP(1'b1),
+ .RSTA(rst),
+ .RSTALLCARRYIN(rst),
+ .RSTALUMODE(rst),
+ .RSTB(rst),
+ .RSTC(rst),
+ .RSTCTRL(rst),
+ .RSTD(rst),
+ .RSTM(rst),
+ .RSTP(clear_3)
+ );
+
+ // Delay x for the C input
+ delay_bus #(2, X_WIDTH) dl_x (x_0, x_2, clk);
+
+ // Delay clear to use as reset for P
+ delay_bit #(3) dl_clear (clear_0, clear_3, clk);
+
+ // Map the output
+ assign yout_4 = pout_4[X_WIDTH+15:X_WIDTH-Y_WIDTH+16];
+
+endmodule // f15_avg
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_binmap.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_binmap.v
new file mode 100644
index 000000000..36935a0e9
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_binmap.v
@@ -0,0 +1,139 @@
+/*
+ * f15_binmap.v
+ *
+ * Maps a log pwr value to an histogram bin
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_binmap #(
+ parameter integer BIN_WIDTH = 6,
+ parameter integer SCALE_FRAC_BITS = 8
+)(
+ input wire [15:0] in_0,
+ input wire [15:0] offset_0, // unsigned
+ input wire [15:0] scale_0, // unsigned
+ output reg [BIN_WIDTH-1:0] bin_5, // bin number
+ output reg sat_ind_5, // saturation indicator
+ input wire clk,
+ input wire rst
+);
+ localparam integer TBI = 15 + SCALE_FRAC_BITS; // Top-Bit-Index
+
+ // Signals
+ wire [47:0] dsp_pout_4;
+ wire dsp_pat_match_4;
+
+
+ // Main DSP
+ // --------
+ // computes (in - cfg_offset) * cfg_scale
+
+ DSP48E1 #(
+ .A_INPUT("DIRECT"),
+ .B_INPUT("DIRECT"),
+ .USE_DPORT("TRUE"),
+ .USE_MULT("MULTIPLY"),
+ .AUTORESET_PATDET("NO_RESET"),
+ .MASK({1'b1, {(46-TBI){1'b0}}, {(TBI+1){1'b1}}}),
+ .PATTERN(48'h000000000000),
+ .SEL_MASK("MASK"),
+ .SEL_PATTERN("PATTERN"),
+ .USE_PATTERN_DETECT("PATDET"),
+ .ACASCREG(1),
+ .ADREG(1),
+ .ALUMODEREG(1),
+ .AREG(1),
+ .BCASCREG(2),
+ .BREG(2),
+ .CARRYINREG(1),
+ .CARRYINSELREG(1),
+ .CREG(1),
+ .DREG(1),
+ .INMODEREG(1),
+ .MREG(1),
+ .OPMODEREG(1),
+ .PREG(1),
+ .USE_SIMD("ONE48")
+ )
+ dsp_binmap_I (
+ .PATTERNDETECT(dsp_pat_match_4),
+ .P(dsp_pout_4),
+ .ACIN(30'h0),
+ .BCIN(18'h0),
+ .CARRYCASCIN(1'h0),
+ .MULTSIGNIN(1'h0),
+ .PCIN(48'h000000000000),
+ .ALUMODE(4'b0000), // Z + X + Y + CIN
+ .CARRYINSEL(3'h0),
+ .CEINMODE(1'b1),
+ .CLK(clk),
+ .INMODE(5'b01100), // B=B2, A=D-A2
+ .OPMODE(7'b0000101), // X=M1, Y=M2, Z=0
+ .RSTINMODE(rst),
+ .A({14'h0, offset_0}),
+ .B({ 2'h0, scale_0}),
+ .C({48'h0}),
+ .CARRYIN(1'b0),
+ .D({ 9'h0, in_0}),
+ .CEA1(1'b0),
+ .CEA2(1'b1),
+ .CEAD(1'b1),
+ .CEALUMODE(1'b1),
+ .CEB1(1'b1),
+ .CEB2(1'b1),
+ .CEC(1'b1),
+ .CECARRYIN(1'b1),
+ .CECTRL(1'b1),
+ .CED(1'b1),
+ .CEM(1'b1),
+ .CEP(1'b1),
+ .RSTA(rst),
+ .RSTALLCARRYIN(rst),
+ .RSTALUMODE(rst),
+ .RSTB(rst),
+ .RSTC(rst),
+ .RSTCTRL(rst),
+ .RSTD(rst),
+ .RSTM(rst),
+ .RSTP(rst)
+ );
+
+
+ // Post-DSP mapping & saturation
+ // -----------------------------
+
+ always @(posedge clk)
+ begin
+ if (rst == 1) begin
+ bin_5 <= 0;
+ sat_ind_5 <= 0;
+ end else begin
+ // Undeflow
+ if (dsp_pout_4[47] == 1) begin
+ bin_5 <= {BIN_WIDTH{1'b0}};
+ sat_ind_5 <= 1;
+
+ // Overflow
+ end else if (dsp_pat_match_4 == 0) begin
+ bin_5 <= {BIN_WIDTH{1'b1}};
+ sat_ind_5 <= 1;
+
+ // In-range
+ end else begin
+ bin_5 <= dsp_pout_4[TBI:TBI-BIN_WIDTH+1];
+ sat_ind_5 <= 0;
+ end
+ end
+ end
+
+endmodule // f15_binmap
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_core.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_core.v
new file mode 100644
index 000000000..003fd1d50
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_core.v
@@ -0,0 +1,609 @@
+/*
+ * f15_core.v
+ *
+ * Core of the fosphor IP
+ *
+ * Copyright (C) 2014,2015 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_core (
+ input clk, input reset,
+ input clear_req,
+ input [ 1:0] cfg_random,
+ input [15:0] cfg_offset, input [15:0] cfg_scale,
+ input [15:0] cfg_trise, input [15:0] cfg_tdecay,
+ input [15:0] cfg_alpha, input [15:0] cfg_epsilon,
+ input [11:0] cfg_decim, input cfg_decim_changed,
+ input [ 1:0] cfg_wf_div, input cfg_wf_mode,
+ input [ 7:0] cfg_wf_decim, input cfg_wf_decim_changed,
+ input [31:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [31:0] o_hist_tdata, output o_hist_tlast, output o_hist_tvalid, input o_hist_tready, output o_hist_teob,
+ output [31:0] o_wf_tdata, output o_wf_tlast, output o_wf_tvalid, input o_wf_tready
+);
+ // Signals
+ reg [31:0] in_data;
+ reg in_last;
+ reg in_valid;
+ reg in_ready;
+
+ wire [15:0] proc_real_0, proc_imag_0;
+ wire [15:0] proc_logpwr_12, proc_logpwr_end;
+ wire proc_last_0, proc_last_12, proc_last_end;
+ wire proc_valid_0, proc_valid_12, proc_valid_end;
+
+ reg [5:0] proc_binscan_addr_end;
+ reg proc_binscan_last_end;
+ reg proc_clear_end;
+ reg clear_pending;
+
+ wire rise_last_0, rise_last_15;
+ wire rise_valid_0, rise_valid_15, rise_valid_24;
+ wire [15:0] rise_logpwr_0;
+ wire [5:0] rise_pwrbin_5, rise_pwrbin_15;
+ reg [9:0] rise_addr_lsb_15;
+ wire [15:0] rise_addr_15, rise_addr_24;
+ wire [8:0] rise_intensity_18, rise_intensity_23;
+ reg [8:0] rise_intensity_24;
+
+ wire decay_last_0, decay_last_9;
+ wire decay_valid_0, decay_valid_9;
+ reg [ 9:0] decay_addr_lsb_0;
+ wire [15:0] decay_addr_0, decay_addr_9;
+ wire [8:0] decay_intensity_3, decay_intensity_8;
+ reg [8:0] decay_intensity_9;
+ wire decay_clear_0, decay_clear_9;
+
+ reg [10:0] sls_addr_0;
+ wire [10:0] sls_addr_6;
+ wire [35:0] sls_data_2, sls_data_6;
+ wire sls_last_0;
+ wire sls_valid_0, sls_valid_6;
+
+ wire [15:0] avgmh_logpwr_0, avgmh_logpwr_2;
+ wire avgmh_clear_0, avgmh_clear_2;
+ wire [11:0] avgmh_avg_2, avgmh_avg_6, avgmh_avg_9;
+ wire [11:0] avgmh_max_2, avgmh_max_6, avgmh_max_9;
+
+ wire [5:0] out_binaddr_0, out_binaddr_9;
+ wire out_binlast_0, out_binlast_9;
+ wire [33:0] out_hist_fifo_di;
+ wire out_hist_fifo_wren;
+ wire out_hist_fifo_afull;
+ wire [33:0] out_hist_fifo_do;
+ wire out_hist_fifo_rden;
+ wire out_hist_fifo_empty;
+
+ wire [11:0] wf_data_2, wf_data_5, wf_data_6;
+ wire [15:0] wf_logpwr_0, wf_logpwr_2;
+ wire [ 7:0] wf_out_data_5;
+ wire wf_last_0, wf_last_2, wf_out_last_5;
+ wire wf_valid_0, wf_valid_2, wf_out_valid_5;
+
+ reg [ 1:0] out_wf_cnt;
+ reg [32:0] out_wf_fifo_di;
+ reg out_wf_fifo_wren;
+ wire out_wf_fifo_afull;
+ wire [32:0] out_wf_fifo_do;
+ wire out_wf_fifo_rden;
+ wire out_wf_fifo_empty;
+
+ wire [31:0] rng;
+
+
+ // -----------------------------------------------------------------------
+ // Input
+ // -----------------------------------------------------------------------
+
+ always @(posedge clk)
+ begin
+ // Control
+ if (reset) begin
+ in_valid <= 1'b0;
+ in_ready <= 1'b0;
+ end else begin
+ // Valid flag
+ in_valid <= i_tvalid & i_tready;
+
+ // We know we can get a sample if :
+ // - Both outputs consumed a sample
+ // - Both FIFOs have enough space
+ in_ready <= (o_hist_tready & o_wf_tready) |
+ (~out_hist_fifo_afull & ~out_wf_fifo_afull);
+ end
+
+ // Data pipeline
+ in_data <= i_tdata;
+ in_last <= i_tlast;
+ end
+
+ assign i_tready = in_ready;
+
+
+ // -----------------------------------------------------------------------
+ // Processing chain
+ // -----------------------------------------------------------------------
+
+ // Input to this stage
+ assign proc_real_0 = in_data[31:16];
+ assign proc_imag_0 = in_data[15:0];
+ assign proc_last_0 = in_last;
+ assign proc_valid_0 = in_valid;
+
+ // Log power
+ f15_logpwr logpwr_I (
+ .in_real_0(proc_real_0),
+ .in_imag_0(proc_imag_0),
+ .out_12(proc_logpwr_12),
+ .rng(rng),
+ .random_mode(cfg_random),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Aggregation
+ // Not supported ATM but this is where it would be
+
+ // Flag propagation
+ delay_bit #(12) dl_proc_last (proc_last_0, proc_last_12, clk);
+ delay_bit #(12) dl_proc_valid (proc_valid_0, proc_valid_12, clk);
+
+ // Even/Odd resequencing
+ f15_eoseq #(
+ .WIDTH(16)
+ ) eoseq_I (
+ .in_data(proc_logpwr_12),
+ .in_valid(proc_valid_12),
+ .in_last(proc_last_12),
+ .out_data(proc_logpwr_end),
+ .out_valid(proc_valid_end),
+ .out_last(proc_last_end),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Bin address counter and clear process
+ // We do this here so we can propagate to every other stage with
+ // just delay lines
+ always @(posedge clk)
+ begin
+ if (reset) begin
+ proc_binscan_addr_end <= 6'd0;
+ proc_binscan_last_end <= 1'b0;
+ end else if (proc_valid_end & proc_last_end) begin
+ proc_binscan_addr_end <= proc_binscan_addr_end + 1;
+ proc_binscan_last_end <= (proc_binscan_addr_end == 6'h3e);
+ end
+ end
+
+ always @(posedge clk)
+ begin
+ if (reset) begin
+ clear_pending <= 1'b0;
+ proc_clear_end <= 1'b0;
+ end else begin
+ if (proc_valid_end & proc_last_end & proc_binscan_last_end) begin
+ clear_pending <= 1'b0;
+ proc_clear_end <= clear_pending;
+ end else begin
+ clear_pending <= clear_pending | clear_req;
+ end
+ end
+ end
+
+
+ // -----------------------------------------------------------------------
+ // Rise
+ // -----------------------------------------------------------------------
+
+ // Input of this stage
+ assign rise_last_0 = proc_last_end;
+ assign rise_valid_0 = proc_valid_end;
+ assign rise_logpwr_0 = proc_logpwr_end;
+
+ // Power Bin mapping
+ f15_binmap #(
+ .BIN_WIDTH(6),
+ .SCALE_FRAC_BITS(8)
+ ) binmap_I (
+ .in_0(rise_logpwr_0),
+ .offset_0(cfg_offset),
+ .scale_0(cfg_scale),
+ .bin_5(rise_pwrbin_5),
+ .sat_ind_5(), // FIXME: Could be use to disable write ena (configurable)
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Delay
+ // (We need to make sure rise doesn't conflict with decay)
+ delay_bus #(10, 6) dl_pwrbin (rise_pwrbin_5, rise_pwrbin_15, clk);
+ delay_bit #(15) dl_valid (rise_valid_0, rise_valid_15, clk);
+ delay_bit #(15) dl_last (rise_last_0, rise_last_15, clk);
+
+ // Address
+ always @(posedge clk)
+ begin
+ if (reset)
+ rise_addr_lsb_15[9:0] <= 9'd0;
+ else if (rise_valid_15)
+ if (rise_last_15)
+ rise_addr_lsb_15 <= 9'd0;
+ else
+ rise_addr_lsb_15 <= rise_addr_lsb_15[9:0] + 1;
+ end
+
+ assign rise_addr_15 = { rise_pwrbin_15, rise_addr_lsb_15 };
+
+ // Exponential rise
+ f15_rise_decay #(
+ .WIDTH(9)
+ ) rise_I (
+ .in_0(rise_intensity_18),
+ .out_5(rise_intensity_23),
+ .k_0(cfg_trise),
+ .ena_0(1'b1),
+ .mode_0(1'b0),
+ .rng(rng[15:0]),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Need one more stage just for proper even/odd interlacing
+ always @(posedge clk)
+ rise_intensity_24 <= rise_intensity_23;
+
+ // Propagate control
+ delay_bit #(9) dl_rise_valid2 (rise_valid_15, rise_valid_24, clk);
+ delay_bus #(9, 16) dl_rise_addr2 (rise_addr_15, rise_addr_24, clk);
+
+
+ // -----------------------------------------------------------------------
+ // State storage
+ // -----------------------------------------------------------------------
+
+ f15_histo_mem #(
+ .ADDR_WIDTH(16)
+ ) mem_I (
+ // Rise readout
+ .addr_AR(rise_addr_15),
+ .data_AR(rise_intensity_18),
+ .ena_AR(rise_valid_15),
+
+ // Rise writeback
+ .addr_AW(rise_addr_24),
+ .data_AW(rise_intensity_24),
+ .ena_AW(rise_valid_24),
+
+ // Decay readout
+ .addr_BR(decay_addr_0),
+ .data_BR(decay_intensity_3),
+ .ena_BR(decay_valid_0),
+
+ // Decay writeback
+ .addr_BW(decay_addr_9),
+ .data_BW(decay_intensity_9),
+ .ena_BW(decay_valid_9),
+
+ // Common
+ .clk(clk),
+ .rst(reset)
+ );
+
+
+ // -----------------------------------------------------------------------
+ // Decay & Clear
+ // -----------------------------------------------------------------------
+
+ // Input of this stage
+ assign decay_last_0 = proc_last_end;
+ assign decay_valid_0 = proc_valid_end;
+ assign decay_clear_0 = proc_clear_end;
+
+ // Address generation
+ always @(posedge clk)
+ begin
+ if (reset)
+ decay_addr_lsb_0 <= 10'd0;
+ else if (decay_valid_0)
+ if (decay_last_0)
+ decay_addr_lsb_0 <= 10'd0;
+ else
+ decay_addr_lsb_0 <= decay_addr_lsb_0 + 1;
+ end
+
+ assign decay_addr_0 = { proc_binscan_addr_end, decay_addr_lsb_0 };
+
+ // Exponential decay
+ f15_rise_decay #(
+ .WIDTH(9)
+ ) decay_I (
+ .in_0(decay_intensity_3),
+ .out_5(decay_intensity_8),
+ .k_0(cfg_tdecay),
+ .ena_0(1'b1),
+ .mode_0(1'b1),
+ .rng(rng[15:0]),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Need one more stage just for proper even/odd interlacing
+ // Also do the clear in there
+ always @(posedge clk)
+ if (decay_clear_9)
+ decay_intensity_9 <= 9'd0;
+ else
+ decay_intensity_9 <= decay_intensity_8;
+
+ // Propagate control
+ delay_bit #(9) dl_decay_valid (decay_valid_0, decay_valid_9, clk);
+ delay_bit #(9) dl_decay_last (decay_last_0, decay_last_9, clk);
+ delay_bit #(9) dl_decay_clear (decay_clear_0, decay_clear_9, clk);
+ delay_bus #(9, 16) dl_decay_addr (decay_addr_0, decay_addr_9, clk);
+
+
+ // -----------------------------------------------------------------------
+ // Shared line-storage
+ // -----------------------------------------------------------------------
+ // This is shared between the average/max-hold spectrum lines and the
+ // waterfall aggregation
+
+ // Input of this stage
+ assign sls_last_0 = proc_last_end;
+ assign sls_valid_0 = proc_valid_end;
+
+ // Address
+ always @(posedge clk)
+ begin
+ if (reset)
+ sls_addr_0 <= 11'd0;
+ else if (sls_valid_0)
+ if (sls_last_0)
+ sls_addr_0 <= 11'd0;
+ else
+ sls_addr_0 <= sls_addr_0 + 1;
+ end
+
+ delay_bus #(6, 11) dl_sls_addr (sls_addr_0, sls_addr_6, clk);
+ delay_bit #(6) dl_sls_valid (sls_valid_0, sls_valid_6, clk);
+
+ // Storage
+ f15_line_mem #(
+ .AWIDTH(11),
+ .DWIDTH(36)
+ ) line_mem_I (
+ .rd_addr(sls_addr_0),
+ .rd_data(sls_data_2),
+ .rd_ena(sls_valid_0),
+ .wr_addr(sls_addr_6),
+ .wr_data(sls_data_6),
+ .wr_ena(sls_valid_6),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Data mapping
+ assign avgmh_avg_2 = sls_data_2[11: 0];
+ assign avgmh_max_2 = sls_data_2[23:12];
+ assign wf_data_2 = sls_data_2[35:24];
+
+ assign sls_data_6[11: 0] = avgmh_avg_6;
+ assign sls_data_6[23:12] = avgmh_max_6;
+ assign sls_data_6[35:24] = wf_data_6;
+
+
+ // -----------------------------------------------------------------------
+ // Average and Max-Hold
+ // -----------------------------------------------------------------------
+
+ // Input of this stage
+ assign avgmh_logpwr_0 = proc_logpwr_end;
+ assign avgmh_clear_0 = proc_clear_end;
+
+ // Modify stage: Average
+ f15_avg #(
+ .Y_WIDTH(12),
+ .X_WIDTH(16)
+ ) avg_I (
+ .yin_0(avgmh_avg_2),
+ .x_0(avgmh_logpwr_2),
+ .rng_0(rng[15:0]),
+ .alpha_0(cfg_alpha),
+ .clear_0(avgmh_clear_2),
+ .yout_4(avgmh_avg_6),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Modify stage: Max Hold
+ f15_maxhold #(
+ .Y_WIDTH(12),
+ .X_WIDTH(16),
+ .FRAC_WIDTH(8)
+ ) maxhold_I (
+ .yin_0(avgmh_max_2),
+ .x_0(avgmh_logpwr_2),
+ .rng_0(rng[15:0]),
+ .epsilon_0(cfg_epsilon),
+ .clear_0(avgmh_clear_2),
+ .yout_4(avgmh_max_6),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Delays
+ delay_bus #(2, 16) dl_avgmh_logpwr (avgmh_logpwr_0, avgmh_logpwr_2, clk);
+ delay_bit #(2) dl_avgmh_clear (avgmh_clear_0, avgmh_clear_2, clk);
+ delay_bus #(3, 12) dl_avgmh_max (avgmh_max_6, avgmh_max_9, clk);
+ delay_bus #(3, 12) dl_avgmh_avg (avgmh_avg_6, avgmh_avg_9, clk);
+
+
+ // -----------------------------------------------------------------------
+ // Histogram Output
+ // -----------------------------------------------------------------------
+
+ // For the 'tap' to work, we need avmh and decay blocks to have the
+ // same number of pipeline stage and be right after proc.
+
+ // Input of this stage
+ assign out_binaddr_0 = proc_binscan_addr_end;
+ assign out_binlast_0 = proc_binscan_last_end;
+
+ // Delays
+ delay_bus #(9, 6) dl_out_binaddr (out_binaddr_0, out_binaddr_9, clk);
+ delay_bit #(9) dl_out_binlast (out_binlast_0, out_binlast_9, clk);
+
+ // Packetizer
+ f15_packetizer #(
+ .BIN_WIDTH(6),
+ .DECIM_WIDTH(12)
+ ) packetizer_I (
+ .in_bin_addr(out_binaddr_9),
+ .in_bin_last(out_binlast_9),
+ .in_histo(decay_intensity_9[8:1]),
+ .in_spectra_max(avgmh_max_9[11:4]),
+ .in_spectra_avg(avgmh_avg_9[11:4]),
+ .in_last(decay_last_9),
+ .in_valid(decay_valid_9),
+ .out_data(out_hist_fifo_di[31:0]),
+ .out_last(out_hist_fifo_di[32]),
+ .out_eob(out_hist_fifo_di[33]),
+ .out_valid(out_hist_fifo_wren),
+ .cfg_decim(cfg_decim),
+ .cfg_decim_changed(cfg_decim_changed),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // FIFO
+ fifo_srl #(
+ .WIDTH(34),
+ .LOG2_DEPTH(6),
+ .AFULL_LEVEL(20)
+ ) out_hist_fifo_I (
+ .di(out_hist_fifo_di),
+ .wren(out_hist_fifo_wren),
+ .afull(out_hist_fifo_afull),
+ .do(out_hist_fifo_do),
+ .rden(out_hist_fifo_rden),
+ .empty(out_hist_fifo_empty),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // AXI mapping
+ assign o_hist_tdata = out_hist_fifo_do[31:0];
+ assign o_hist_tlast = out_hist_fifo_do[32];
+ assign o_hist_teob = out_hist_fifo_do[33];
+ assign o_hist_tvalid = ~out_hist_fifo_empty;
+ assign out_hist_fifo_rden = ~out_hist_fifo_empty && o_hist_tready;
+
+
+ // -----------------------------------------------------------------------
+ // Waterfall Output
+ // -----------------------------------------------------------------------
+
+ // Input to this stage (synced to SLS)
+ assign wf_logpwr_0 = proc_logpwr_end;
+ assign wf_last_0 = proc_last_end;
+ assign wf_valid_0 = proc_valid_end;
+
+ // Delay some input signals
+ delay_bus #(2, 16) dl_wf_logpwr (wf_logpwr_0, wf_logpwr_2, clk);
+ delay_bit #(2) dl_wf_last (wf_last_0, wf_last_2, clk);
+ delay_bit #(2) dl_wf_valid (wf_valid_0, wf_valid_2, clk);
+
+ // Decimation / Aggregation
+ f15_wf_agg #(
+ .Y_WIDTH(12),
+ .X_WIDTH(16),
+ .DECIM_WIDTH(8)
+ ) dut_wf (
+ .yin_0(wf_data_2),
+ .x_0(wf_logpwr_2),
+ .valid_0(wf_valid_2),
+ .last_0(wf_last_2),
+ .rng_0(rng[15:0]),
+ .yout_3(wf_data_5),
+ .zout_3(wf_out_data_5),
+ .zvalid_3(wf_out_valid_5),
+ .cfg_div(cfg_wf_div),
+ .cfg_mode(cfg_wf_mode),
+ .cfg_decim(cfg_wf_decim),
+ .cfg_decim_changed(cfg_wf_decim_changed),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // Delay some output signals
+ delay_bus #(1, 12) dl_wf_data (wf_data_5, wf_data_6, clk);
+ delay_bit #(3) dl_wf_out_last (wf_last_2, wf_out_last_5, clk);
+
+ // Pack into 32 bits words
+ always @(posedge clk)
+ begin
+ if (reset) begin
+ out_wf_fifo_di <= 0;
+ out_wf_fifo_wren <= 1'b0;
+ out_wf_cnt <= 2'b00;
+ end else begin
+ if (wf_out_valid_5) begin
+ if (wf_out_last_5) begin
+ out_wf_fifo_di <= { 1'b1, out_wf_fifo_di[23:0], wf_out_data_5 };
+ out_wf_fifo_wren <= 1'b1;
+ out_wf_cnt <= 2'b00;
+ end else begin
+ out_wf_fifo_di <= { 1'b0, out_wf_fifo_di[23:0], wf_out_data_5 };
+ out_wf_fifo_wren <= (out_wf_cnt == 2'b11);
+ out_wf_cnt <= out_wf_cnt + 1;
+ end
+ end else begin
+ out_wf_fifo_wren <= 1'b0;
+ end
+ end
+ end
+
+ // FIFO
+ fifo_srl #(
+ .WIDTH(33),
+ .LOG2_DEPTH(6),
+ .AFULL_LEVEL(20)
+ ) out_wf_fifo_I (
+ .di(out_wf_fifo_di),
+ .wren(out_wf_fifo_wren),
+ .afull(out_wf_fifo_afull),
+ .do(out_wf_fifo_do),
+ .rden(out_wf_fifo_rden),
+ .empty(out_wf_fifo_empty),
+ .clk(clk),
+ .rst(reset)
+ );
+
+ // AXI mapping
+ assign o_wf_tdata = out_wf_fifo_do[31:0];
+ assign o_wf_tlast = out_wf_fifo_do[32];
+ assign o_wf_tvalid = ~out_wf_fifo_empty;
+ assign out_wf_fifo_rden = ~out_wf_fifo_empty && o_wf_tready;
+
+
+ // -----------------------------------------------------------------------
+ // Misc
+ // -----------------------------------------------------------------------
+
+ // RNG
+`ifdef SIM
+ assign rng = 0;
+`else
+ rng rng_I (rng, clk, reset);
+`endif
+
+endmodule // f15_core
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_eoseq.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_eoseq.v
new file mode 100644
index 000000000..6d209cd16
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_eoseq.v
@@ -0,0 +1,78 @@
+/*
+ * f15_eoseq.v
+ *
+ * Resequence a data flow with data/valid/last ensuring EVEN/ODD
+ * sequencing (even data on even cycles, odd data on odd cycles)
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_eoseq #(
+ parameter integer WIDTH = 16
+)(
+ input wire [WIDTH-1:0] in_data,
+ input wire in_valid,
+ input wire in_last,
+ output reg [WIDTH-1:0] out_data,
+ output reg out_valid,
+ output reg out_last,
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ reg [WIDTH-1:0] buf_data;
+ reg buf_valid;
+ reg buf_last;
+
+ wire flip;
+ reg odd;
+ reg sel;
+
+ // Control
+ always @(posedge clk)
+ if (rst)
+ odd <= 1'b0;
+ else
+ odd <= ~(in_last & in_valid) & (odd ^ in_valid);
+
+ always @(posedge clk)
+ if (rst)
+ sel <= 1'b0;
+ else if (flip)
+ sel <= ~sel;
+
+ assign flip = ~in_valid | (in_last & ~odd);
+
+ // Buffer
+ always @(posedge clk)
+ begin
+ buf_data <= in_data;
+ buf_valid <= in_valid;
+ buf_last <= in_last;
+ end
+
+ // Output
+ always @(posedge clk)
+ begin
+ if (sel) begin
+ out_data <= buf_data;
+ out_valid <= buf_valid;
+ out_last <= buf_last;
+ end else begin
+ out_data <= in_data;
+ out_valid <= in_valid;
+ out_last <= in_last;
+ end
+ end
+
+endmodule // f15_eoseq
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_histo_mem.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_histo_mem.v
new file mode 100644
index 000000000..7a7f7e279
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_histo_mem.v
@@ -0,0 +1,287 @@
+/*
+ * f15_histo_mem.v
+ *
+ * Histogram State storage. Basically a memory with 2 R/W ports where
+ * each port can do read & write at different address at the same time
+ * if those address are inteleaved (like read at odd address when writing
+ * to even address).
+ *
+ * This allows two independent process to do READ/MODIFY/WRITE.
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_histo_mem #(
+ parameter integer ADDR_WIDTH = 16
+)(
+ // Port A Read
+ input wire [ADDR_WIDTH-1:0] addr_AR,
+ output reg [8:0] data_AR,
+ input wire ena_AR,
+
+ // Port A Write
+ input wire [ADDR_WIDTH-1:0] addr_AW,
+ input wire [8:0] data_AW,
+ input wire ena_AW,
+
+ // Port B Read
+ input wire [ADDR_WIDTH-1:0] addr_BR,
+ output reg [8:0] data_BR,
+ input wire ena_BR,
+
+ // Port B Write
+ input wire [ADDR_WIDTH-1:0] addr_BW,
+ input wire [8:0] data_BW,
+ input wire ena_BW,
+
+ // Error detection
+ output reg conflict_A,
+ output reg conflict_B,
+
+ // Common
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ // Memory banks IF
+ wire [ADDR_WIDTH-2:0] even_addra, odd_addra;
+ wire [ADDR_WIDTH-2:0] even_addrb, odd_addrb;
+ wire [8:0] even_dia, odd_dia;
+ wire [8:0] even_dib, odd_dib;
+ wire [8:0] even_doa, odd_doa;
+ wire [8:0] even_dob, odd_dob;
+ wire even_wea, odd_wea;
+ wire even_web, odd_web;
+ wire even_rea, odd_rea;
+ wire even_reb, odd_reb;
+
+ // Control
+ wire sel_A, sel_B;
+
+
+ // Mux selection
+ assign sel_A = ena_AR ? addr_AR[0] : ~addr_AW[0];
+ assign sel_B = ena_BR ? addr_BR[0] : ~addr_BW[0];
+
+ // Conflict detection
+ always @(posedge clk)
+ begin
+ conflict_A <= !(addr_AR[0] ^ addr_AW[0]) & ena_AR & ena_AW;
+ conflict_B <= !(addr_BR[0] ^ addr_BW[0]) & ena_BR & ena_BW;
+ end
+
+ // Control signals
+ assign even_wea = sel_A & ena_AW;
+ assign odd_wea = !sel_A & ena_AW;
+ assign even_web = sel_B & ena_BW;
+ assign odd_web = !sel_B & ena_BW;
+ assign even_rea = !sel_A & ena_AR;
+ assign odd_rea = sel_A & ena_AR;
+ assign even_reb = !sel_B & ena_BR;
+ assign odd_reb = sel_B & ena_BR;
+
+ // Address path mapping
+ assign even_addra = sel_A ? addr_AW[ADDR_WIDTH-1:1] : addr_AR[ADDR_WIDTH-1:1];
+ assign even_addrb = sel_B ? addr_BW[ADDR_WIDTH-1:1] : addr_BR[ADDR_WIDTH-1:1];
+ assign odd_addra = sel_A ? addr_AR[ADDR_WIDTH-1:1] : addr_AW[ADDR_WIDTH-1:1];
+ assign odd_addrb = sel_B ? addr_BR[ADDR_WIDTH-1:1] : addr_BW[ADDR_WIDTH-1:1];
+
+ // Data path mapping
+ assign even_dia = data_AW;
+ assign odd_dia = data_AW;
+ assign even_dib = data_BW;
+ assign odd_dib = data_BW;
+
+ always @(posedge clk)
+ begin
+ data_AR <= even_doa | odd_doa;
+ data_BR <= even_dob | odd_dob;
+ end
+
+ // Instanciate memory banks
+ f15_histo_mem_bank #(
+ .ADDR_WIDTH(ADDR_WIDTH-1)
+ ) mem_even (
+ .addra(even_addra),
+ .addrb(even_addrb),
+ .dia(even_dia),
+ .dib(even_dib),
+ .doa(even_doa),
+ .dob(even_dob),
+ .wea(even_wea),
+ .web(even_web),
+ .rea(even_rea),
+ .reb(even_reb),
+ .clk(clk),
+ .rst(rst)
+ );
+
+ f15_histo_mem_bank #(
+ .ADDR_WIDTH(ADDR_WIDTH-1)
+ ) mem_odd (
+ .addra(odd_addra),
+ .addrb(odd_addrb),
+ .dia(odd_dia),
+ .dib(odd_dib),
+ .doa(odd_doa),
+ .dob(odd_dob),
+ .wea(odd_wea),
+ .web(odd_web),
+ .rea(odd_rea),
+ .reb(odd_reb),
+ .clk(clk),
+ .rst(rst)
+ );
+
+endmodule // f15_histo_mem
+
+
+module f15_histo_mem_bank #(
+ parameter integer ADDR_WIDTH = 15
+)(
+ input wire [ADDR_WIDTH-1:0] addra,
+ input wire [ADDR_WIDTH-1:0] addrb,
+ input wire [8:0] dia,
+ input wire [8:0] dib,
+ output reg [8:0] doa,
+ output reg [8:0] dob,
+ input wire wea,
+ input wire web,
+ input wire rea,
+ input wire reb,
+ input wire clk,
+ input wire rst
+);
+ localparam integer N_BRAMS = 1 << (ADDR_WIDTH - 12);
+ genvar i;
+ integer j;
+
+ // Signals
+ // Direct RAM connections
+ wire [15:0] ramb_addra;
+ wire [15:0] ramb_addrb;
+ wire [31:0] ramb_dia;
+ wire [31:0] ramb_dib;
+ wire [ 3:0] ramb_dipa;
+ wire [ 3:0] ramb_dipb;
+ wire [31:0] ramb_doa[0:N_BRAMS-1];
+ wire [31:0] ramb_dob[0:N_BRAMS-1];
+ wire [ 3:0] ramb_dopa[0:N_BRAMS-1];
+ wire [ 3:0] ramb_dopb[0:N_BRAMS-1];
+ wire ramb_wea[0:N_BRAMS-1];
+ wire ramb_web[0:N_BRAMS-1];
+ reg ramb_rstdoa[0:N_BRAMS-1];
+ reg ramb_rstdob[0:N_BRAMS-1];
+
+ // Control
+ reg onehota[0:N_BRAMS-1];
+ reg onehotb[0:N_BRAMS-1];
+
+ // Map address LSB and data inputs
+ assign ramb_addra = { 1'b0, addra[11:0], 3'b000 };
+ assign ramb_addrb = { 1'b0, addrb[11:0], 3'b000 };
+
+ assign ramb_dia = { 16'h0000, dia[8:1] };
+ assign ramb_dib = { 16'h0000, dib[8:1] };
+ assign ramb_dipa = { 3'b000, dia[0] };
+ assign ramb_dipb = { 3'b000, dib[0] };
+
+ // OR all the RAMB outputs
+ always @*
+ begin
+ doa = 9'h0;
+ dob = 9'h0;
+ for (j=0; j<N_BRAMS; j=j+1) begin
+ doa = doa | { ramb_doa[j][7:0], ramb_dopa[j][0] };
+ dob = dob | { ramb_dob[j][7:0], ramb_dopb[j][0] };
+ end
+ end
+
+ // Generate array
+ generate
+ for (i=0; i<N_BRAMS; i=i+1) begin
+
+ // Decode address MSB to one-hot signal
+ always @(addra,addrb)
+ begin
+ onehota[i] <= (addra[ADDR_WIDTH-1:12] == i) ? 1'b1 : 1'b0;
+ onehotb[i] <= (addrb[ADDR_WIDTH-1:12] == i) ? 1'b1 : 1'b0;
+ end
+
+ // If no read, then reset the output reg to zero
+ always @(posedge clk)
+ begin
+ ramb_rstdoa[i] <= !(onehota[i] & rea);
+ ramb_rstdob[i] <= !(onehotb[i] & reb);
+ end
+
+ // Mask the write enable with decoded address
+ assign ramb_wea[i] = onehota[i] & wea;
+ assign ramb_web[i] = onehotb[i] & web;
+
+ // Instantiate RAM Block
+ RAMB36E1 #(
+ .RDADDR_COLLISION_HWCONFIG("PERFORMANCE"),
+ .SIM_COLLISION_CHECK("NONE"),
+ .DOA_REG(1),
+ .DOB_REG(1),
+ .EN_ECC_READ("FALSE"),
+ .EN_ECC_WRITE("FALSE"),
+ .RAM_EXTENSION_A("NONE"),
+ .RAM_EXTENSION_B("NONE"),
+ .RAM_MODE("TDP"),
+ .READ_WIDTH_A(9),
+ .READ_WIDTH_B(9),
+ .WRITE_WIDTH_A(9),
+ .WRITE_WIDTH_B(9),
+ .RSTREG_PRIORITY_A("RSTREG"),
+ .RSTREG_PRIORITY_B("RSTREG"),
+ .SIM_DEVICE("7SERIES"),
+ .SRVAL_A(36'h000000000),
+ .SRVAL_B(36'h000000000),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST")
+ )
+ mem_elem_I (
+ .DOADO(ramb_doa[i]),
+ .DOPADOP(ramb_dopa[i]),
+ .DOBDO(ramb_dob[i]),
+ .DOPBDOP(ramb_dopb[i]),
+ .CASCADEINA(1'b0),
+ .CASCADEINB(1'b0),
+ .INJECTDBITERR(1'b0),
+ .INJECTSBITERR(1'b0),
+ .ADDRARDADDR(ramb_addra),
+ .CLKARDCLK(clk),
+ .ENARDEN(1'b1),
+ .REGCEAREGCE(1'b1),
+ .RSTRAMARSTRAM(rst),
+ .RSTREGARSTREG(ramb_rstdoa[i]),
+ .WEA({3'b0, ramb_wea[i]}),
+ .DIADI(ramb_dia),
+ .DIPADIP(ramb_dipa),
+ .ADDRBWRADDR(ramb_addrb),
+ .CLKBWRCLK(clk),
+ .ENBWREN(1'b1),
+ .REGCEB(1'b1),
+ .RSTRAMB(rst),
+ .RSTREGB(ramb_rstdob[i]),
+ .WEBWE({7'b0, ramb_web[i]}),
+ .DIBDI(ramb_dib),
+ .DIPBDIP(ramb_dipb)
+ );
+
+ end
+ endgenerate
+
+endmodule // f15_histo_mem_bank
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_line_mem.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_line_mem.v
new file mode 100644
index 000000000..7a98d5c6e
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_line_mem.v
@@ -0,0 +1,67 @@
+/*
+ * f15_line_mem.v
+ *
+ * Memory for a single line to compute max-hold / average
+ * Read latency is 2 and if read is not enabled, output data is forced
+ * to zero.
+ *
+ * Copyright (C) 2015 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_line_mem #(
+ parameter integer AWIDTH = 12,
+ parameter integer DWIDTH = 18
+)(
+ input wire [AWIDTH-1:0] rd_addr,
+ output reg [DWIDTH-1:0] rd_data,
+ input wire rd_ena,
+
+ input wire [AWIDTH-1:0] wr_addr,
+ input wire [DWIDTH-1:0] wr_data,
+ input wire wr_ena,
+
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
+ reg [DWIDTH-1:0] rd_data_r;
+ reg rd_ena_r;
+
+`ifdef SIM
+ integer i;
+ initial
+ for (i=0; i<(1<<AWIDTH); i=i+1)
+ ram[i] = 0;
+`endif
+
+ always @(posedge clk)
+ begin
+ // Read
+ rd_data_r <= ram[rd_addr];
+
+ // Write
+ if (wr_ena)
+ ram[wr_addr] <= wr_data;
+
+ // Register the enable flag
+ rd_ena_r <= rd_ena;
+
+ // Final read register
+ if (rd_ena_r)
+ rd_data <= rd_data_r;
+ else
+ rd_data <= 0;
+ end
+
+endmodule // f15_line_mem
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_logpwr.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_logpwr.v
new file mode 100644
index 000000000..cd10bc56a
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_logpwr.v
@@ -0,0 +1,504 @@
+/*
+ * f15_logpwr.v
+ *
+ * Log Power computation
+ * Take a complex 16 bits input and outputs a 16 bits estimate
+ * of 2048 * log2(i^2+q^2).
+ *
+ * Fully-pipelined, 12 levels
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_logpwr(
+ input wire [15:0] in_real_0,
+ input wire [15:0] in_imag_0,
+ output wire [15:0] out_12,
+ input wire [31:0] rng,
+ input wire [ 1:0] random_mode, /* [0] = lsb random ena, [1] = random add */
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ // Randomness control
+ reg [7:0] rng_lsb;
+ wire [6:0] opmode;
+
+ // Power squared
+ wire [47:0] dsp_pchain_3;
+ wire [47:0] dsp_pout_4;
+
+ wire [4:0] msb_check;
+ wire [31:0] pwr_4;
+ reg [31:0] pwr_5, pwr_6, pwr_7, pwr_8, pwr_9;
+ reg [4:0] log2_5, log2_6, log2_7, log2_8, log2_9;
+
+ // LUT
+ wire [15:0] lut_addr_9;
+ wire [31:0] lut_do_11;
+
+ wire msb_9, msb_11;
+ wire [4:0] lsbs_9, lsbs_11;
+ wire [4:0] log2_11;
+
+ // Final value
+ reg [20:0] final_12;
+
+
+ // -------------
+ // Power squared
+ // -------------
+ // Output is (in_real * in_real) + (in_imag * in_imag)
+ // with possibly some random lsb filled in for in_{real,imag} and some
+ // noise added to the result.
+
+ // Randomness control
+ always @(posedge clk)
+ if (random_mode[0])
+ rng_lsb <= rng[31:24];
+ else
+ rng_lsb <= 8'h00;
+
+ assign opmode = random_mode[1] ? 7'b0110101 : 7'b0000101;
+
+ // Square of in_real + noise
+ DSP48E1 #(
+ .A_INPUT("DIRECT"),
+ .B_INPUT("DIRECT"),
+ .USE_DPORT("FALSE"),
+ .USE_MULT("MULTIPLY"),
+ .AUTORESET_PATDET("NO_RESET"),
+ .MASK(48'h3fffffffffff),
+ .PATTERN(48'h000000000000),
+ .SEL_MASK("MASK"),
+ .SEL_PATTERN("PATTERN"),
+ .USE_PATTERN_DETECT("NO_PATDET"),
+ .ACASCREG(1),
+ .ADREG(0),
+ .ALUMODEREG(1),
+ .AREG(1),
+ .BCASCREG(1),
+ .BREG(1),
+ .CARRYINREG(1),
+ .CARRYINSELREG(1),
+ .CREG(1),
+ .DREG(0),
+ .INMODEREG(1),
+ .MREG(1),
+ .OPMODEREG(1),
+ .PREG(1),
+ .USE_SIMD("ONE48")
+ )
+ dsp_real_sq_I (
+ .PCOUT(dsp_pchain_3),
+ .ACIN(30'h0000),
+ .BCIN(18'h000),
+ .CARRYCASCIN(1'h0),
+ .MULTSIGNIN(1'h0),
+ .PCIN(48'h000000000000),
+ .ALUMODE(4'b0000), // Z + X + Y + CIN
+ .CARRYINSEL(3'h0),
+ .CEINMODE(1'b1),
+ .CLK(clk),
+ .INMODE(5'b00000), // B=B2, A=A2
+ .OPMODE(opmode), // X=M1, Y=M2, Z=(random_mode[1] ? C : 0)
+ .RSTINMODE(rst),
+ .A({{12{in_real_0[15]}}, in_real_0, rng_lsb[7:6]}),
+ .B({ in_real_0, rng_lsb[5:4]}),
+ .C({{41{1'b0}},rng[6:0]}),
+ .CARRYIN(1'b0),
+ .D(25'h0000),
+ .CEA1(1'b0),
+ .CEA2(1'b1),
+ .CEAD(1'b0),
+ .CEALUMODE(1'b1),
+ .CEB1(1'b0),
+ .CEB2(1'b1),
+ .CEC(1'b1),
+ .CECARRYIN(1'b1),
+ .CECTRL(1'b1),
+ .CED(1'b0),
+ .CEM(1'b1),
+ .CEP(1'b1),
+ .RSTA(rst),
+ .RSTALLCARRYIN(rst),
+ .RSTALUMODE(rst),
+ .RSTB(rst),
+ .RSTC(rst),
+ .RSTCTRL(rst),
+ .RSTD(rst),
+ .RSTM(rst),
+ .RSTP(rst)
+ );
+
+ // Square of in_imag and final sum
+ DSP48E1 #(
+ .A_INPUT("DIRECT"),
+ .B_INPUT("DIRECT"),
+ .USE_DPORT("FALSE"),
+ .USE_MULT("MULTIPLY"),
+ .AUTORESET_PATDET("NO_RESET"),
+ .MASK(48'h3fffffffffff),
+ .PATTERN(48'h000000000000),
+ .SEL_MASK("MASK"),
+ .SEL_PATTERN("PATTERN"),
+ .USE_PATTERN_DETECT("NO_PATDET"),
+ .ACASCREG(1),
+ .ADREG(0),
+ .ALUMODEREG(1),
+ .AREG(2),
+ .BCASCREG(1),
+ .BREG(2),
+ .CARRYINREG(1),
+ .CARRYINSELREG(1),
+ .CREG(1),
+ .DREG(0),
+ .INMODEREG(1),
+ .MREG(1),
+ .OPMODEREG(1),
+ .PREG(1),
+ .USE_SIMD("ONE48")
+ )
+ dsp_imag_sq_I (
+ .P(dsp_pout_4),
+ .ACIN(30'h0000),
+ .BCIN(18'h000),
+ .CARRYCASCIN(1'h0),
+ .MULTSIGNIN(1'h0),
+ .PCIN(dsp_pchain_3),
+ .ALUMODE(4'b0000), // Z + X + Y + CIN
+ .CARRYINSEL(3'h0),
+ .CEINMODE(1'b1),
+ .CLK(clk),
+ .INMODE(5'b00000), // B=B2, A=A2
+ .OPMODE(7'b0010101), // X=M1, Y=M2, Z=PCIN
+ .RSTINMODE(rst),
+ .A({{12{in_imag_0[15]}}, in_imag_0, rng_lsb[3:2]}),
+ .B({ in_imag_0, rng_lsb[1:0]}),
+ .C(48'h0000),
+ .CARRYIN(1'b0),
+ .D(25'h0000),
+ .CEA1(1'b1),
+ .CEA2(1'b1),
+ .CEAD(1'b0),
+ .CEALUMODE(1'b1),
+ .CEB1(1'b1),
+ .CEB2(1'b1),
+ .CEC(1'b1),
+ .CECARRYIN(1'b1),
+ .CECTRL(1'b1),
+ .CED(1'b0),
+ .CEM(1'b1),
+ .CEP(1'b1),
+ .RSTA(rst),
+ .RSTALLCARRYIN(rst),
+ .RSTALUMODE(rst),
+ .RSTB(rst),
+ .RSTC(rst),
+ .RSTCTRL(rst),
+ .RSTD(rst),
+ .RSTM(rst),
+ .RSTP(rst)
+ );
+
+ assign pwr_4 = dsp_pout_4[35:4];
+
+
+ // ----------------------------------
+ // Log2 computation and normalization
+ // ----------------------------------
+ // When shifting, instead of zero filling, we fill with RNG data
+ // Again, this helps reduce the visible quantization effects
+ // for very low power values.
+
+ // First stage
+ assign msb_check[4] = |(pwr_4[31:16]);
+
+ always @(posedge clk)
+ begin
+ if (msb_check[4])
+ pwr_5 <= pwr_4;
+ else
+ pwr_5 <= { pwr_4[15:0], rng[31:16] };
+
+ log2_5 <= { msb_check[4], 4'b0000 };
+ end
+
+ // Second stage
+ assign msb_check[3] = |(pwr_5[31:24]);
+
+ always @(posedge clk)
+ begin
+ if (msb_check[3])
+ pwr_6 <= pwr_5;
+ else
+ pwr_6 <= { pwr_5[23:0], rng[15:8] };
+
+ log2_6 <= { log2_5[4], msb_check[3], 3'b000 };
+ end
+
+ // Third stage
+ assign msb_check[2] = |(pwr_6[31:28]);
+
+ always @(posedge clk)
+ begin
+ if (msb_check[2])
+ pwr_7 <= pwr_6;
+ else
+ pwr_7 <= { pwr_6[27:0], rng[7:4] };
+
+ log2_7 <= { log2_6[4:3], msb_check[2], 2'b00 };
+ end
+
+ // Fourth stage
+ assign msb_check[1] = |(pwr_7[31:30]);
+
+ always @(posedge clk)
+ begin
+ if (msb_check[1])
+ pwr_8 <= pwr_7;
+ else
+ pwr_8 <= { pwr_7[29:0], rng[3:2] };
+
+ log2_8 <= { log2_7[4:2], msb_check[1], 1'b0 };
+ end
+
+ // Final stage
+ assign msb_check[0] = pwr_8[31];
+
+ always @(posedge clk)
+ begin
+ if (msb_check[0])
+ pwr_9 <= pwr_8;
+ else
+ pwr_9 <= { pwr_8[30:0], rng[1] };
+
+ log2_9 <= { log2_8[4:1], msb_check[0] };
+ log2_9 <= { log2_8[4:1], msb_check[0] };
+ end
+
+
+ // ----------
+ // LUT lookup
+ // ----------
+
+ // Address mapping
+ assign lut_addr_9 = { 1'b0, pwr_9[30:20], 4'h0 };
+
+ // Actual LUT
+ RAMB36E1 #(
+ .RDADDR_COLLISION_HWCONFIG("PERFORMANCE"),
+ .SIM_COLLISION_CHECK("NONE"),
+ .DOA_REG(1),
+ .DOB_REG(1),
+ .EN_ECC_READ("FALSE"),
+ .EN_ECC_WRITE("FALSE"),
+ .INIT_00(256'h02b202840256022801fa01cd019f01710143011500e700b8008a005c002e0000),
+ .INIT_01(256'h058c055f0531050404d604a9047b044e042003f203c503970369033b030e02e0),
+ .INIT_02(256'h08610834080707da07ad077f0752072506f806ca069d06700642061505e705ba),
+ .INIT_03(256'h0b310b040ad70aaa0a7d0a500a2409f709ca099d09700943091608e908bc088e),
+ .INIT_04(256'h0dfb0dce0da20d750d490d1c0cef0cc30c960c6a0c3d0c100be40bb70b8a0b5d),
+ .INIT_05(256'h10bf10931067103b100e0fe20fb60f8a0f5d0f310f050ed90eac0e800e530e27),
+ .INIT_06(256'h137e1353132712fb12cf12a31277124b121f11f311c7119b116f1143111710eb),
+ .INIT_07(256'h1639160d15e215b6158a155f1533150814dc14b014851459142d140213d613aa),
+ .INIT_08(256'h18ed18c21897186c1841181517ea17bf17941768173d171216e616bb168f1664),
+ .INIT_09(256'h1b9d1b731b481b1d1af21ac71a9c1a711a461a1b19f019c5199a196f19441919),
+ .INIT_0A(256'h1e481e1e1df31dc91d9e1d741d491d1e1cf41cc91c9e1c731c491c1e1bf31bc8),
+ .INIT_0B(256'h20ee20c4209a20702045201b1ff11fc61f9c1f721f471f1d1ef21ec81e9d1e73),
+ .INIT_0C(256'h23902366233c231222e822be2294226a2240221621ec21c12197216d21432119),
+ .INIT_0D(256'h262c260325d925af2586255c2532250824df24b5248b24612437240d23e423ba),
+ .INIT_0E(256'h28c4289b28712848281e27f527cc27a22779274f272626fc26d326a9267f2656),
+ .INIT_0F(256'h2b572b2e2b052adc2ab32a8a2a612a372a0e29e529bc299229692940291728ed),
+ .INIT_10(256'h2de62dbd2d942d6b2d432d1a2cf12cc82c9f2c762c4d2c242bfb2bd22ba92b80),
+ .INIT_11(256'h30703047301f2ff62fce2fa52f7d2f542f2b2f032eda2eb12e892e602e372e0f),
+ .INIT_12(256'h32f632cd32a5327d3255322c320431dc31b3318b3162313a311230e930c13098),
+ .INIT_13(256'h3577354f352734ff34d734af3487345f3437340f33e733be3396336e3346331e),
+ .INIT_14(256'h37f437cc37a4377d3755372d370536de36b6368e3666363e361635ef35c7359f),
+ .INIT_15(256'h3a6c3a453a1e39f639cf39a7398039583931390938e238ba3892386b3843381b),
+ .INIT_16(256'h3ce13cba3c933c6b3c443c1d3bf63bcf3ba73b803b593b313b0a3ae33abb3a94),
+ .INIT_17(256'h3f513f2a3f033edd3eb63e8f3e683e413e1a3df33dcc3da53d7d3d563d2f3d08),
+ .INIT_18(256'h41be41974170414a412340fc40d540af40884061403a40143fed3fc63f9f3f78),
+ .INIT_19(256'h442643ff43d943b3438c4366433f431942f242cc42a5427f42584231420b41e4),
+ .INIT_1A(256'h468a4664463e461745f145cb45a5457f45584532450c44e544bf44994472444c),
+ .INIT_1B(256'h48ea48c4489e48784853482d480747e147bb4795476f4748472246fc46d646b0),
+ .INIT_1C(256'h4b474b214afb4ad64ab04a8a4a644a3f4a1949f349cd49a84982495c49364910),
+ .INIT_1D(256'h4d9f4d7a4d544d2f4d094ce44cbe4c994c734c4e4c284c034bdd4bb84b924b6c),
+ .INIT_1E(256'h4ff44fcf4faa4f844f5f4f3a4f154eef4eca4ea54e7f4e5a4e354e0f4dea4dc5),
+ .INIT_1F(256'h5245522051fb51d651b1518c51675142511d50f850d350ae50895063503e5019),
+ .INIT_20(256'h5492546e5449542453ff53da53b65391536c5347532252fd52d952b4528f526a),
+ .INIT_21(256'h56dc56b75693566e564a5625560155dc55b85593556e554a5525550054dc54b7),
+ .INIT_22(256'h592258fe58d958b55891586c5848582457ff57db57b75792576e574957255700),
+ .INIT_23(256'h5b645b405b1c5af85ad45ab05a8c5a685a445a2059fb59d759b3598f596a5946),
+ .INIT_24(256'h5da35d805d5c5d385d145cf05ccc5ca85c845c605c3d5c195bf55bd15bad5b89),
+ .INIT_25(256'h5fdf5fbb5f985f745f505f2d5f095ee55ec25e9e5e7a5e565e335e0f5deb5dc7),
+ .INIT_26(256'h621761f461d061ad618961666142611f60fb60d860b46091606d604a60266003),
+ .INIT_27(256'h644c6429640563e263bf639c637863556332630f62eb62c862a56281625e623a),
+ .INIT_28(256'h667d665a6637661465f165ce65ab658865656542651f64fc64d864b56492646f),
+ .INIT_29(256'h68ab688868666843682067fd67da67b767946772674f672c670966e666c366a0),
+ .INIT_2A(256'h6ad66ab36a916a6e6a4b6a296a0669e469c1699e697b69596936691368f168ce),
+ .INIT_2B(256'h6cfd6cdb6cb96c966c746c516c2f6c0c6bea6bc76ba56b836b606b3d6b1b6af8),
+ .INIT_2C(256'h6f226eff6edd6ebb6e996e776e546e326e106dee6dcb6da96d876d646d426d20),
+ .INIT_2D(256'h7143712170ff70dd70bb709970777055703370116fee6fcc6faa6f886f666f44),
+ .INIT_2E(256'h7361733f731d72fb72da72b87296727472527230720e71ec71cb71a971877165),
+ .INIT_2F(256'h757c755a7539751774f574d474b27490746f744d742b740a73e873c673a47383),
+ .INIT_30(256'h779477727751772f770e76ec76cb76aa7688766776457624760275e075bf759d),
+ .INIT_31(256'h79a87987796679457924790278e178c0789e787d785c783a781977f877d677b5),
+ .INIT_32(256'h7bba7b997b787b577b367b157af47ad37ab27a917a707a4e7a2d7a0c79eb79ca),
+ .INIT_33(256'h7dc97da87d887d677d467d257d047ce37cc27ca17c807c5f7c3e7c1d7bfc7bdb),
+ .INIT_34(256'h7fd57fb57f947f737f537f327f117ef07ed07eaf7e8e7e6d7e4d7e2c7e0b7dea),
+ .INIT_35(256'h81de81be819d817d815c813c811b80fb80da80ba809980788058803780177ff6),
+ .INIT_36(256'h83e583c483a48384836383438323830282e282c182a1828182608240821f81ff),
+ .INIT_37(256'h85e885c885a88588856785478527850784e784c684a684868466844584258405),
+ .INIT_38(256'h87e987c987a98789876987498729870986e986c986a986898668864886288608),
+ .INIT_39(256'h89e789c789a78987896789488928890888e888c888a888888868884888298809),
+ .INIT_3A(256'h8be28bc28ba28b838b638b438b248b048ae48ac58aa58a858a668a468a268a06),
+ .INIT_3B(256'h8dda8dbb8d9b8d7c8d5c8d3d8d1d8cfe8cde8cbf8c9f8c808c608c408c218c01),
+ .INIT_3C(256'h8fd08fb18f918f728f538f338f148ef58ed58eb68e978e778e588e388e198dfa),
+ .INIT_3D(256'h91c391a49185916691469127910890e990ca90ab908b906c904d902e900e8fef),
+ .INIT_3E(256'h93b39394937693579338931992fa92db92bc929c927d925e923f9220920191e2),
+ .INIT_3F(256'h95a19583956495459526950794e894ca94ab948c946d944e942f941093f193d2),
+ .INIT_40(256'h978d976e974f9731971296f396d596b696979679965a963b961c95fe95df95c0),
+ .INIT_41(256'h997599579938991a98fb98dd98be98a09881986398449826980797e897ca97ab),
+ .INIT_42(256'h9b5c9b3d9b1f9b019ae29ac49aa69a879a699a4a9a2c9a0e99ef99d199b29994),
+ .INIT_43(256'h9d3f9d219d039ce59cc79ca99c8a9c6c9c4e9c309c119bf39bd59bb79b989b7a),
+ .INIT_44(256'h9f219f039ee59ec79ea99e8b9e6d9e4f9e309e129df49dd69db89d9a9d7c9d5e),
+ .INIT_45(256'ha100a0e2a0c4a0a6a088a06aa04ca02ea0119ff39fd59fb79f999f7b9f5d9f3f),
+ .INIT_46(256'ha2dca2bea2a1a283a265a247a22aa20ca1eea1d0a1b3a195a177a159a13ba11e),
+ .INIT_47(256'ha4b6a499a47ba45ea440a422a405a3e7a3c9a3aca38ea371a353a335a318a2fa),
+ .INIT_48(256'ha68ea671a653a636a618a5fba5dda5c0a5a2a585a567a54aa52ca50fa4f1a4d4),
+ .INIT_49(256'ha863a846a829a80ba7eea7d1a7b4a796a779a75ca73ea721a703a6e6a6c9a6ab),
+ .INIT_4A(256'haa36aa19a9fca9dfa9c2a9a5a987a96aa94da930a913a8f5a8d8a8bba89ea881),
+ .INIT_4B(256'hac07abeaabcdabb0ab93ab76ab59ab3cab1fab02aae5aac8aaabaa8eaa71aa53),
+ .INIT_4C(256'hadd6adb9ad9cad7fad62ad45ad28ad0cacefacd2acb5ac98ac7bac5eac41ac24),
+ .INIT_4D(256'hafa2af85af68af4caf2faf12aef5aed9aebcae9fae82ae66ae49ae2cae0fadf2),
+ .INIT_4E(256'hb16cb14fb133b116b0fab0ddb0c0b0a4b087b06ab04eb031b015aff8afdbafbf),
+ .INIT_4F(256'hb334b317b2fbb2deb2c2b2a5b289b26cb250b233b217b1fab1deb1c1b1a5b188),
+ .INIT_50(256'hb4f9b4ddb4c1b4a4b488b46cb44fb433b417b3fab3deb3c2b3a5b389b36cb350),
+ .INIT_51(256'hb6bdb6a1b684b668b64cb630b614b5f7b5dbb5bfb5a3b587b56ab54eb532b515),
+ .INIT_52(256'hb87eb862b846b82ab80eb7f2b7d6b7bab79eb781b765b749b72db711b6f5b6d9),
+ .INIT_53(256'hba3dba21ba05b9e9b9ceb9b2b996b97ab95eb942b926b90ab8eeb8d2b8b6b89a),
+ .INIT_54(256'hbbfabbdebbc3bba7bb8bbb6fbb54bb38bb1cbb00bae4bac8baadba91ba75ba59),
+ .INIT_55(256'hbdb5bd9abd7ebd62bd47bd2bbd0fbcf4bcd8bcbcbca1bc85bc69bc4dbc32bc16),
+ .INIT_56(256'hbf6ebf53bf37bf1cbf00bee5bec9beadbe92be76be5bbe3fbe24be08bdecbdd1),
+ .INIT_57(256'hc125c10ac0eec0d3c0b7c09cc081c065c04ac02ec013bff7bfdcbfc1bfa5bf8a),
+ .INIT_58(256'hc2dac2bfc2a3c288c26dc251c236c21bc200c1e4c1c9c1aec192c177c15cc140),
+ .INIT_59(256'hc48dc472c456c43bc420c405c3eac3cfc3b3c398c37dc362c347c32bc310c2f5),
+ .INIT_5A(256'hc63dc622c607c5ecc5d1c5b6c59bc580c565c54ac52fc514c4f9c4dec4c3c4a8),
+ .INIT_5B(256'hc7ecc7d1c7b7c79cc781c766c74bc730c715c6fac6dfc6c4c6a9c68ec673c658),
+ .INIT_5C(256'hc999c97ec964c949c92ec913c8f9c8dec8c3c8a8c88dc873c858c83dc822c807),
+ .INIT_5D(256'hcb44cb2acb0fcaf4cadacabfcaa4ca8aca6fca54ca3aca1fca04c9e9c9cfc9b4),
+ .INIT_5E(256'hccedccd3ccb8cc9ecc83cc69cc4ecc34cc19cbfecbe4cbc9cbafcb94cb79cb5f),
+ .INIT_5F(256'hce94ce7ace60ce45ce2bce10cdf6cddccdc1cda7cd8ccd72cd57cd3dcd22cd08),
+ .INIT_60(256'hd03ad01fd005cfebcfd1cfb6cf9ccf82cf67cf4dcf33cf18cefecee4cec9ceaf),
+ .INIT_61(256'hd1ddd1c3d1a9d18fd174d15ad140d126d10cd0f1d0d7d0bdd0a3d088d06ed054),
+ .INIT_62(256'hd37fd365d34bd330d316d2fcd2e2d2c8d2aed294d27ad260d246d22cd211d1f7),
+ .INIT_63(256'hd51ed504d4ead4d1d4b7d49dd483d469d44fd435d41bd401d3e7d3cdd3b3d399),
+ .INIT_64(256'hd6bcd6a2d689d66fd655d63bd621d607d5eed5d4d5bad5a0d586d56cd552d538),
+ .INIT_65(256'hd858d83fd825d80bd7f1d7d8d7bed7a4d78bd771d757d73dd723d70ad6f0d6d6),
+ .INIT_66(256'hd9f3d9d9d9bfd9a6d98cd973d959d93fd926d90cd8f2d8d9d8bfd8a5d88cd872),
+ .INIT_67(256'hdb8bdb72db58db3fdb25db0cdaf2dad9dabfdaa6da8cda72da59da3fda26da0c),
+ .INIT_68(256'hdd22dd09dcefdcd6dcbcdca3dc8adc70dc57dc3ddc24dc0adbf1dbd8dbbedba5),
+ .INIT_69(256'hdeb7de9ede84de6bde52de39de1fde06ddedddd3ddbadda1dd87dd6edd55dd3b),
+ .INIT_6A(256'he04ae031e018dfffdfe6dfccdfb3df9adf81df68df4edf35df1cdf03dee9ded0),
+ .INIT_6B(256'he1dce1c3e1aae191e178e15fe145e12ce113e0fae0e1e0c8e0afe096e07de063),
+ .INIT_6C(256'he36ce353e33ae321e308e2efe2d6e2bde2a4e28be272e259e240e227e20ee1f5),
+ .INIT_6D(256'he4fae4e1e4c8e4afe497e47ee465e44ce433e41ae401e3e8e3cfe3b7e39ee385),
+ .INIT_6E(256'he686e66ee655e63ce624e60be5f2e5d9e5c0e5a8e58fe576e55de544e52ce513),
+ .INIT_6F(256'he811e7f9e7e0e7c7e7afe796e77de765e74ce733e71be702e6e9e6d1e6b8e69f),
+ .INIT_70(256'he99be982e96ae951e938e920e907e8efe8d6e8bee8a5e88ce874e85be843e82a),
+ .INIT_71(256'heb22eb0aeaf1ead9eac0eaa8ea90ea77ea5fea46ea2eea15e9fde9e4e9cce9b3),
+ .INIT_72(256'heca8ec90ec78ec5fec47ec2eec16ebfeebe5ebcdebb5eb9ceb84eb6beb53eb3b),
+ .INIT_73(256'hee2dee14edfcede4edccedb3ed9bed83ed6bed52ed3aed22ed09ecf1ecd9ecc1),
+ .INIT_74(256'hefafef97ef7fef67ef4fef37ef1fef06eeeeeed6eebeeea6ee8dee75ee5dee45),
+ .INIT_75(256'hf131f119f101f0e8f0d0f0b8f0a0f088f070f058f040f028f010eff8efe0efc8),
+ .INIT_76(256'hf2b0f298f280f268f251f239f221f209f1f1f1d9f1c1f1a9f191f179f161f149),
+ .INIT_77(256'hf42ef417f3fff3e7f3cff3b7f39ff387f370f358f340f328f310f2f8f2e0f2c8),
+ .INIT_78(256'hf5abf593f57bf564f54cf534f51cf505f4edf4d5f4bdf4a5f48ef476f45ef446),
+ .INIT_79(256'hf726f70ef6f7f6dff6c7f6b0f698f680f669f651f639f622f60af5f2f5daf5c3),
+ .INIT_7A(256'hf8a0f888f870f859f841f82af812f7fbf7e3f7cbf7b4f79cf785f76df755f73e),
+ .INIT_7B(256'hfa18fa00f9e9f9d1f9baf9a2f98bf973f95cf944f92df915f8fef8e6f8cff8b7),
+ .INIT_7C(256'hfb8efb77fb5ffb48fb31fb19fb02faeafad3fabcfaa4fa8dfa75fa5efa46fa2f),
+ .INIT_7D(256'hfd03fcecfcd5fcbdfca6fc8ffc77fc60fc49fc32fc1afc03fbecfbd4fbbdfba5),
+ .INIT_7E(256'hfe77fe60fe48fe31fe1afe03fdecfdd4fdbdfda6fd8ffd77fd60fd49fd32fd1a),
+ .INIT_7F(256'hffe9ffd2ffbbffa4ff8dff75ff5eff47ff30ff19ff02feebfed3febcfea5fe8e),
+ .INIT_A(36'h000000000),
+ .INIT_B(36'h000000000),
+ .INIT_FILE("NONE"),
+ .RAM_MODE("TDP"),
+ .RAM_EXTENSION_A("NONE"),
+ .RAM_EXTENSION_B("NONE"),
+ .READ_WIDTH_A(18),
+ .READ_WIDTH_B(0),
+ .WRITE_WIDTH_A(0),
+ .WRITE_WIDTH_B(36), // the RAMB36E1 model fails without this
+ .RSTREG_PRIORITY_A("RSTREG"),
+ .RSTREG_PRIORITY_B("RSTREG"),
+ .SRVAL_A(36'h000000000),
+ .SRVAL_B(36'h000000000),
+ .SIM_DEVICE("7SERIES"),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST")
+ )
+ log_lut_I (
+ .DOADO(lut_do_11),
+ .CASCADEINA(1'b0),
+ .CASCADEINB(1'b0),
+ .INJECTDBITERR(1'b0),
+ .INJECTSBITERR(1'b0),
+ .ADDRARDADDR(lut_addr_9),
+ .CLKARDCLK(clk),
+ .ENARDEN(1'b1),
+ .REGCEAREGCE(1'b1),
+ .RSTRAMARSTRAM(rst),
+ .RSTREGARSTREG(rst),
+ .WEA(4'h0),
+ .DIADI(32'h00000000),
+ .DIPADIP(4'h0),
+ .ADDRBWRADDR(16'h0000),
+ .CLKBWRCLK(1'b0),
+ .ENBWREN(1'b0),
+ .REGCEB(1'b0),
+ .RSTRAMB(1'b0),
+ .RSTREGB(1'b0),
+ .WEBWE(8'h0),
+ .DIBDI(32'h00000000),
+ .DIPBDIP(4'h0)
+ );
+
+ // LSBs mapping
+ assign msb_9 = pwr_9[31];
+ assign lsbs_9 = pwr_9[19:15];
+
+ // Delay lines to compensate for LUT delay
+ delay_bit #(2) dl_msb (msb_9, msb_11, clk);
+ delay_bus #(2, 5) dl_lsbs (lsbs_9, lsbs_11, clk);
+ delay_bus #(2, 5) dl_log2 (log2_9, log2_11, clk);
+
+
+ // -----------
+ // Final value
+ // -----------
+
+ // Final add & saturation
+ always @(posedge clk)
+ begin
+ if (!msb_11)
+ final_12 <= 16'h0000;
+ else
+ final_12 <= { log2_11, lut_do_11[15:0] } + lsbs_11;
+ end
+
+ // Mapping
+ assign out_12 = final_12[20:5];
+
+endmodule // f15_logpwr
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_maxhold.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_maxhold.v
new file mode 100644
index 000000000..ecd92adfb
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_maxhold.v
@@ -0,0 +1,71 @@
+/*
+ * f15_maxhold.v
+ *
+ * Computes the max hold (with epsilon decay)
+ *
+ * Copyright (C) 2015 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_maxhold #(
+ parameter integer Y_WIDTH = 12,
+ parameter integer X_WIDTH = 16,
+ parameter integer FRAC_WIDTH = 8
+)(
+ input wire [Y_WIDTH-1:0] yin_0,
+ input wire [X_WIDTH-1:0] x_0,
+ input wire [15:0] rng_0,
+ input wire [15:0] epsilon_0,
+ input wire clear_0,
+ output wire [Y_WIDTH-1:0] yout_4,
+ input wire clk,
+ input wire rst
+);
+
+ localparam integer I_WIDTH = X_WIDTH + FRAC_WIDTH;
+
+ // Signals
+ reg [X_WIDTH-1:0] x_1;
+ reg [I_WIDTH :0] y_1;
+ reg [Y_WIDTH :0] d_1;
+ reg clear_1;
+
+ reg [Y_WIDTH-1:0] y_2;
+
+ // Stage 1
+ always @(posedge clk)
+ begin
+ x_1 <= x_0;
+ y_1 <= { 1'b0, yin_0, rng_0[I_WIDTH-Y_WIDTH-1:0] } - epsilon_0;
+ d_1 <= { 1'b0, yin_0 } - { 1'b0, x_0[X_WIDTH-1:X_WIDTH-Y_WIDTH] };
+ clear_1 <= clear_0;
+ end
+
+ // Stage 2
+ always @(posedge clk)
+ begin
+ if (clear_1)
+ y_2 <= 0;
+ else if (d_1[Y_WIDTH])
+ // x is larger, use this
+ y_2 <= x_1[X_WIDTH-1:X_WIDTH-Y_WIDTH];
+ else
+ // y is larger, take old y with small decay
+ if (y_1[I_WIDTH])
+ y_2 <= 0;
+ else
+ y_2 <= y_1[I_WIDTH-1:I_WIDTH-Y_WIDTH];
+ end
+
+ // Apply two more delay to match the avg block
+ delay_bus #(2, Y_WIDTH) dl_y (y_2, yout_4, clk);
+
+endmodule // f15_maxhold
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_packetizer.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_packetizer.v
new file mode 100644
index 000000000..d8ff2ae34
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_packetizer.v
@@ -0,0 +1,136 @@
+/*
+ * f15_packetizer.v
+ *
+ * Copyright (C) 2015 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_packetizer #(
+ parameter integer BIN_WIDTH = 6,
+ parameter integer DECIM_WIDTH = 10
+)(
+ input wire [BIN_WIDTH-1:0] in_bin_addr,
+ input wire in_bin_last,
+ input wire [7:0] in_histo,
+ input wire [7:0] in_spectra_max,
+ input wire [7:0] in_spectra_avg,
+ input wire in_last,
+ input wire in_valid,
+
+ output reg [31:0] out_data,
+ output reg out_last,
+ output reg out_eob,
+ output reg out_valid,
+
+ input wire [DECIM_WIDTH-1:0] cfg_decim,
+ input wire cfg_decim_changed,
+
+ input wire clk,
+ input wire rst
+);
+
+ // FSM
+ localparam
+ ST_WAIT = 0,
+ ST_SEND_HISTO = 1,
+ ST_SEND_MAX = 2,
+ ST_SEND_AVG = 3;
+
+ reg [1:0] state;
+
+ // Signals
+ reg [DECIM_WIDTH:0] decim_cnt;
+ reg [1:0] bcnt;
+
+ // 1-in-N decimation counter
+ always @(posedge clk)
+ begin
+ if (rst)
+ decim_cnt <= 0;
+ else if (cfg_decim_changed)
+ // Force Reload
+ decim_cnt <= { 1'b0, cfg_decim };
+ else if (in_valid & in_bin_last & in_last)
+ if (decim_cnt[DECIM_WIDTH])
+ // Reload
+ decim_cnt <= { 1'b0, cfg_decim };
+ else
+ // Just decrement
+ decim_cnt <= decim_cnt - 1;
+ end
+
+ // FSM
+ always @(posedge clk)
+ begin
+ if (rst)
+ state <= ST_WAIT;
+ else if (in_valid & in_last)
+ case (state)
+ ST_WAIT:
+ if (in_bin_last & decim_cnt[DECIM_WIDTH])
+ state <= ST_SEND_HISTO;
+
+ ST_SEND_HISTO:
+ if (in_bin_last)
+ state <= ST_SEND_MAX;
+
+ ST_SEND_MAX:
+ state <= ST_SEND_AVG;
+
+ ST_SEND_AVG:
+ state <= ST_WAIT;
+ endcase
+ end
+
+ // Byte counter
+ always @(posedge clk)
+ begin
+ if (rst)
+ bcnt <= 2'b00;
+ else if (in_valid)
+ if (in_last | (bcnt == 2'b11))
+ bcnt <= 2'b00;
+ else
+ bcnt <= bcnt + 1;
+ end
+
+ // Input mux & shift register
+ always @(posedge clk)
+ begin
+ if (in_valid)
+ begin
+ // Shift
+ out_data[31:8] <= out_data[23:0];
+
+ // New LSBs
+ case (state)
+ ST_SEND_HISTO: out_data[7:0] <= in_histo;
+ ST_SEND_MAX: out_data[7:0] <= in_spectra_max;
+ ST_SEND_AVG: out_data[7:0] <= in_spectra_avg;
+ endcase
+ end
+ end
+
+ // Output last, eob, valid
+ always @(posedge clk)
+ begin
+ if (rst) begin
+ out_last <= 1'b0;
+ out_eob <= 1'b0;
+ out_valid <= 1'b0;
+ end else begin
+ out_last <= in_last;
+ out_eob <= (state == ST_SEND_AVG);
+ out_valid <= in_valid & (in_last | bcnt == 2'b11) & (state != ST_WAIT);
+ end
+ end
+
+endmodule // f15_packetizer
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_rise_decay.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_rise_decay.v
new file mode 100644
index 000000000..aeba14c7f
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_rise_decay.v
@@ -0,0 +1,160 @@
+/*
+ * f15_rise_decay.v
+ *
+ * Applies the rise or decay to a given value.
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_rise_decay #(
+ parameter integer WIDTH = 9
+)(
+ input wire [WIDTH-1:0] in_0, // input
+ output reg [WIDTH-1:0] out_5, // output
+ input wire [15:0] k_0, // time constant
+ input wire ena_0, // If ena=0, then output original value
+ input wire mode_0, // 0=rise, 1=decay
+ input wire [15:0] rng,
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ reg mode_1;
+ reg [4:0] inmode_1;
+
+ wire [WIDTH-1:0] in_2;
+ wire ena_2;
+ wire [6:0] opmode_2;
+ reg [3:0] alumode_2;
+
+ wire [47:0] pout_4;
+ wire pmatch_4;
+
+
+ // Main DSP
+ // --------
+
+ // Mode control
+ // For rise we have INMODE=00000 (A=A2, B=B2), ALUMODE=0000 (C+M)
+ // For decay we have INMODE=01100 (A=D-A2, B=B2), ALUMODE=0011 (C-M)
+ always @(posedge clk)
+ begin
+ mode_1 <= mode_0;
+
+ if (mode_0)
+ inmode_1 <= 5'b00000;
+ else
+ inmode_1 <= 5'b01100;
+
+ if (mode_1)
+ alumode_2 <= 4'b0011;
+ else
+ alumode_2 <= 4'b0000;
+ end
+
+ // When not enabled, we use OPMODE to do pass-through
+ delay_bit #(2) dl_ena (ena_0, ena_2, clk);
+ assign opmode_2 = ena_2 ? 7'b0110101 : 7'b0110000;
+
+ // Delay for input to C
+ delay_bus #(2, WIDTH) dl_in (in_0, in_2, clk);
+
+ // Instance
+ DSP48E1 #(
+ .A_INPUT("DIRECT"),
+ .B_INPUT("DIRECT"),
+ .USE_DPORT("TRUE"),
+ .USE_MULT("MULTIPLY"),
+ .AUTORESET_PATDET("NO_RESET"),
+ .MASK({1'b1, {(31-WIDTH){1'b0}}, {(WIDTH+16){1'b1}}}),
+ .PATTERN(48'h000000000000),
+ .SEL_MASK("MASK"),
+ .SEL_PATTERN("PATTERN"),
+ .USE_PATTERN_DETECT("PATDET"),
+ .ACASCREG(1),
+ .ADREG(1),
+ .ALUMODEREG(1),
+ .AREG(1),
+ .BCASCREG(2),
+ .BREG(2),
+ .CARRYINREG(1),
+ .CARRYINSELREG(1),
+ .CREG(1),
+ .DREG(1),
+ .INMODEREG(1),
+ .MREG(1),
+ .OPMODEREG(1),
+ .PREG(1),
+ .USE_SIMD("ONE48")
+ )
+ dsp_exp_I (
+ .PATTERNDETECT(pmatch_4),
+ .P(pout_4),
+ .ACIN(30'h0),
+ .BCIN(18'h0),
+ .CARRYCASCIN(1'h0),
+ .MULTSIGNIN(1'h0),
+ .PCIN(48'h000000000000),
+ .ALUMODE(alumode_2),
+ .CARRYINSEL(3'h0),
+ .CEINMODE(1'b1),
+ .CLK(clk),
+ .INMODE(inmode_1),
+ .OPMODE(opmode_2),
+ .RSTINMODE(rst),
+ .A({{(30-WIDTH){1'b0}}, in_0}),
+ .B({ 2'h0, k_0}),
+ .C({{(32-WIDTH){1'b0}}, in_2, rng}),
+ .CARRYIN(1'b0),
+ .D({{(24-WIDTH){1'b0}}, 1'b1, {WIDTH{1'b0}}}),
+ .CEA1(1'b0),
+ .CEA2(1'b1),
+ .CEAD(1'b1),
+ .CEALUMODE(1'b1),
+ .CEB1(1'b1),
+ .CEB2(1'b1),
+ .CEC(1'b1),
+ .CECARRYIN(1'b1),
+ .CECTRL(1'b1),
+ .CED(1'b1),
+ .CEM(1'b1),
+ .CEP(1'b1),
+ .RSTA(rst),
+ .RSTALLCARRYIN(rst),
+ .RSTALUMODE(rst),
+ .RSTB(rst),
+ .RSTC(rst),
+ .RSTCTRL(rst),
+ .RSTD(rst),
+ .RSTM(rst),
+ .RSTP(rst)
+ );
+
+
+ // Saturation
+ // ----------
+
+ always @(posedge clk)
+ begin
+ if (rst == 1)
+ out_5 <= 0;
+ else
+ if (pout_4[47] == 1)
+ out_5 <= {WIDTH{1'b0}};
+ else if (pmatch_4 == 0)
+ out_5 <= {WIDTH{1'b1}};
+ else
+ out_5 <= pout_4[WIDTH+15:16];
+ end
+
+endmodule // f15_rise_decay
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v b/fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v
new file mode 100644
index 000000000..7b12bc4d5
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v
@@ -0,0 +1,189 @@
+/*
+ * f15_wf_agg.v
+ *
+ * Watefall Aggregation
+ *
+ * Copyright (C) 2016 Ettus Corporation LLC
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module f15_wf_agg #(
+ parameter integer Y_WIDTH = 12,
+ parameter integer X_WIDTH = 16,
+ parameter integer DECIM_WIDTH = 8
+)(
+ input wire [Y_WIDTH-1:0] yin_0,
+ input wire [X_WIDTH-1:0] x_0,
+ input wire valid_0,
+ input wire last_0,
+ input wire [15:0] rng_0,
+
+ output wire [Y_WIDTH-1:0] yout_3,
+ output wire [7:0] zout_3,
+ output wire zvalid_3,
+
+ input wire [1:0] cfg_div,
+ input wire cfg_mode, // 0=MaxHold, 1=Average
+ input wire [DECIM_WIDTH-1:0] cfg_decim,
+ input wire cfg_decim_changed,
+
+ input wire clk,
+ input wire rst
+);
+
+ localparam integer R_WIDTH = X_WIDTH + 9;
+
+ // Signals
+ // Data pah
+ reg [R_WIDTH-1:0] xe_1;
+ reg [R_WIDTH-1:0] ye_1;
+
+ wire over_2;
+ reg [R_WIDTH-1:0] r_2;
+ reg [Y_WIDTH-1:0] x_2;
+ reg [Y_WIDTH-1:0] y_2;
+
+ reg [Y_WIDTH-1:0] y_3;
+
+ // Control
+ reg [DECIM_WIDTH:0] decim_cnt;
+ reg init_0;
+ wire init_2;
+ reg init_force_0;
+ reg flush_0;
+ reg zvalid_1;
+
+
+ // Datapath
+ // --------
+
+ // X predivision mux
+ always @(posedge clk)
+ begin
+ case (cfg_div)
+ 2'b00:
+ xe_1 <= { 1'd0, x_0, 8'd0 }; // 1:1
+
+ 2'b01:
+ xe_1 <= { 4'd0, x_0, 5'd0 }; // 1:8
+
+ 2'b10:
+ xe_1 <= { 7'd0, x_0, 2'd0 }; // 1:64
+
+ 2'b11:
+ xe_1 <= { 9'd0, x_0 }; // 1:256
+ endcase
+ end
+
+ // Y register
+ always @(posedge clk)
+ begin
+ if (cfg_mode)
+ // Average
+ ye_1 <= { 1'b0, yin_0, rng_0[R_WIDTH-Y_WIDTH-2:0] };
+ else
+ // Max Hold
+ ye_1 <= { 1'b0, yin_0, {(R_WIDTH-Y_WIDTH-1){1'b0}} };
+ end
+
+ // Adder / Substractor
+ always @(posedge clk)
+ begin
+ if (cfg_mode)
+ // Average
+ r_2 <= ye_1 + xe_1;
+ else
+ // Max-Hold
+ r_2 <= ye_1 - xe_1;
+ end
+
+ assign over_2 = r_2[R_WIDTH-1];
+
+ // Registers for the two branches.
+ always @(posedge clk)
+ begin
+ x_2 <= xe_1[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
+ y_2 <= ye_1[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
+ end
+
+ // Output mux
+ always @(posedge clk)
+ begin
+ // If first : take x_2
+ // If average :
+ // - If overflow = 0 -> take r_2
+ // - If overflow = 1 -> sature to all 1's
+ // If max-hold
+ // - If overflow = 0 -> take y_2
+ // - If overflow = 1 -> take x_2
+ if (init_2)
+ y_3 <= x_2;
+ else if (cfg_mode)
+ y_3 <= over_2 ? { (Y_WIDTH){1'b1} } : r_2[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
+ else
+ y_3 <= over_2 ? x_2 : y_2;
+ end
+
+ assign yout_3 = y_3;
+ assign zout_3 = y_3[Y_WIDTH-1:Y_WIDTH-8];
+
+
+ // Control
+ // -------
+
+ // 1-in-N decimation counter
+ always @(posedge clk)
+ begin
+ if (rst)
+ decim_cnt <= 0;
+ else if (cfg_decim_changed)
+ // Force Reload
+ decim_cnt <= { 1'b0, cfg_decim };
+ else if (valid_0 & last_0)
+ if (decim_cnt[DECIM_WIDTH])
+ // Reload
+ decim_cnt <= { 1'b0, cfg_decim };
+ else
+ // Just decrement
+ decim_cnt <= decim_cnt - 1;
+ end
+
+ // Decimation flush & init states
+ always @(posedge clk)
+ begin
+ if (rst) begin
+ // Initial state
+ flush_0 <= 1'b0;
+ init_0 <= 1'b1;
+ init_force_0 <= 1'b0;
+ end else begin
+ if (valid_0 & last_0) begin
+ // Flushing
+ flush_0 <= decim_cnt[DECIM_WIDTH];
+
+ // Init after flush or if forced
+ init_0 <= flush_0 | init_force_0;
+ end
+
+ // Init forcing after a decim change
+ if (cfg_decim_changed)
+ init_force_0 <= 1'b1;
+ else if (valid_0 & last_0)
+ init_force_0 <= 1'b0;
+ end
+ end
+
+ delay_bit #(2) dl_init(init_0, init_2, clk);
+
+ // Z-output valid
+ always @(posedge clk)
+ zvalid_1 <= valid_0 & flush_0;
+
+ delay_bit #(2) dl_zvalid(zvalid_1, zvalid_3, clk);
+
+endmodule // f15_wf_agg
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v b/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v
new file mode 100644
index 000000000..700da18d3
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v
@@ -0,0 +1,169 @@
+/*
+ * fifo_srl.v
+ *
+ * Very small/light-weight FIFO using SRL.
+ * Only for synchronous design. Has a fixed depth of 15 or 31 entries and
+ * always work in the so-called first-word-fall-thru mode.
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+module fifo_srl #(
+ parameter integer WIDTH = 4,
+ parameter integer LOG2_DEPTH = 5, // 4 or 5
+ parameter integer AFULL_LEVEL = -1 // -1 -> No AFULL
+
+)(
+ input wire [WIDTH-1:0] di,
+ input wire wren,
+ output wire full,
+ output wire afull,
+
+ output reg [WIDTH-1:0] do,
+ input wire rden,
+ output reg empty,
+
+ input wire clk,
+ input wire rst
+);
+
+ genvar i;
+
+ // Signals
+ wire [WIDTH-1:0] srl_q;
+ reg [LOG2_DEPTH-1:0] srl_addr;
+ wire srl_addr_ce;
+
+ wire srl_write;
+ wire srl_read;
+
+ wire srl_full;
+ wire srl_afull;
+ reg srl_empty;
+ wire srl_aempty;
+
+ // Instanciate the SRLs
+ generate
+ if (LOG2_DEPTH == 6) begin
+ wire [WIDTH-1:0] srl0_q31, srl0_q, srl1_q;
+
+ for (i=0; i<WIDTH; i=i+1)
+ begin : srl_64
+ SRLC32E srl_I0 (
+ .Q(srl0_q[i]),
+ .Q31(srl0_q31[i]),
+ .A(srl_addr[4:0]),
+ .CE(srl_write),
+ .CLK(clk),
+ .D(di[i])
+ );
+
+ SRLC32E srl_I1 (
+ .Q(srl1_q[i]),
+ .A(srl_addr[4:0]),
+ .CE(srl_write),
+ .CLK(clk),
+ .D(srl0_q31[i])
+ );
+
+ MUXF7 mux_I (
+ .O(srl_q[i]),
+ .I0(srl0_q[i]),
+ .I1(srl1_q[i]),
+ .S(srl_addr[5])
+ );
+ end
+ end else if (LOG2_DEPTH == 5) begin
+ for (i=0; i<WIDTH; i=i+1)
+ SRLC32E srl_I (
+ .Q(srl_q[i]),
+ .A(srl_addr),
+ .CE(srl_write),
+ .CLK(clk),
+ .D(di[i])
+ );
+ end else if (LOG2_DEPTH == 4) begin
+ for (i=0; i<WIDTH; i=i+1)
+ SRL16E srl_I (
+ .Q(srl_q[i]),
+ .A0(srl_addr[0]),
+ .A1(srl_addr[1]),
+ .A2(srl_addr[2]),
+ .A3(srl_addr[3]),
+ .CE(srl_write),
+ .CLK(clk),
+ .D(di[i])
+ );
+ end
+ endgenerate
+
+ // Address counter
+ assign srl_addr_ce = srl_write ^ srl_read;
+
+ always @(posedge clk)
+ begin
+ if (rst)
+ srl_addr <= {LOG2_DEPTH{1'b1}};
+ else if (srl_addr_ce) begin
+ if (srl_write)
+ srl_addr <= srl_addr + 1;
+ else
+ srl_addr <= srl_addr - 1;
+ end
+ end
+
+ // SRL status
+ assign srl_full = srl_addr == {{(LOG2_DEPTH-1){1'b1}}, 1'b0};
+
+ generate
+ if (AFULL_LEVEL != -1) begin
+ assign srl_afull = (srl_addr >= AFULL_LEVEL) && ~&(srl_addr);
+ end else begin
+ assign srl_afull = 1'b0;
+ end
+ endgenerate
+
+ assign srl_aempty = &(~srl_addr);
+
+ always @(posedge clk)
+ begin
+ if (rst)
+ srl_empty <= 1'b1;
+ else if (srl_addr_ce)
+ srl_empty <= srl_aempty & srl_read;
+ end
+
+ // Output register (to capture whatever comes out from SRL)
+ always @(posedge clk)
+ begin
+ if (srl_read)
+ do <= srl_q;
+ end
+
+ // Control and flag generation
+ // Write/Full is easy
+ assign srl_write = wren;
+ assign full = srl_full;
+ assign afull = srl_afull;
+
+ // Read/Empty is tricky
+ always @(posedge clk)
+ begin
+ if (rst)
+ empty <= 1'b1;
+ else if (rden | srl_read)
+ empty <= srl_empty;
+ end
+
+ assign srl_read = (rden | empty) & ~srl_empty;
+
+endmodule // fifo_srl
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/rng.v b/fpga/usrp3/lib/rfnoc/fosphor/rng.v
new file mode 100644
index 000000000..6d6715fd0
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/fosphor/rng.v
@@ -0,0 +1,87 @@
+/*
+ * rng.v
+ *
+ * Very simple 32-bits PRNG using a few underlying LFSR.
+ *
+ * Copyright (C) 2014 Ettus Corporation LLC
+ * Copyright 2018 Ettus Research, a National Instruments Company
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * vim: ts=4 sw=4
+ */
+
+`ifdef SIM
+`default_nettype none
+`endif
+
+// ---------------------------------------------------------------------------
+// Main RNG
+// ---------------------------------------------------------------------------
+
+module rng(
+ output reg [31:0] out,
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ wire [4:0] out5, out5rev;
+ wire [7:0] out8;
+ wire [11:0] out12;
+ wire [15:0] out16;
+
+ // Instanciate 4 LFSRs of different lengths
+ lfsr #(.WIDTH( 5), .POLY( 5'b01001)) lfsr5 (.out(out5), .clk(clk), .rst(rst));
+ lfsr #(.WIDTH( 8), .POLY( 8'h71 )) lfsr8 (.out(out8), .clk(clk), .rst(rst));
+ lfsr #(.WIDTH(12), .POLY(12'hc11 )) lfsr12 (.out(out12), .clk(clk), .rst(rst));
+ lfsr #(.WIDTH(16), .POLY(16'h6701 )) lfsr16 (.out(out16), .clk(clk), .rst(rst));
+
+ // Reverse the 5 bit LFSR output
+ genvar i;
+ generate
+ for (i=0; i<5; i=i+1)
+ assign out5rev[i] = out5[4-i];
+ endgenerate
+
+ // Combine the outputs 'somehow'
+ always @(posedge clk)
+ out <= {
+ out16[15:11] ^ out5rev, // 5 bits
+ out16[10:2], // 9 bits
+ out16[1:0] ^ out12[11:10], // 2 bits
+ out12[9:2], // 8 bits
+ out12[1:0] ^ out8[7:6], // 2 bits
+ out8[5:0] // 6 bits
+ };
+
+endmodule // rng
+
+
+// ---------------------------------------------------------------------------
+// LFSR sub module
+// ---------------------------------------------------------------------------
+
+module lfsr #(
+ parameter integer WIDTH = 8,
+ parameter POLY = 8'h71
+)(
+ output reg [WIDTH-1:0] out,
+ input wire clk,
+ input wire rst
+);
+
+ // Signals
+ wire fb;
+
+ // Linear Feedback
+ assign fb = ^(out & POLY);
+
+ // Register
+ always @(posedge clk)
+ if (rst)
+ out <= { {(WIDTH-1){1'b0}}, 1'b1 };
+ else
+ out <= { fb, out[WIDTH-1:1] };
+
+endmodule // lfsr