diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/fosphor')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/axi_logpwr.v | 102 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/delay.v | 140 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_avg.v | 117 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_binmap.v | 139 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_core.v | 609 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_eoseq.v | 78 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_histo_mem.v | 287 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_line_mem.v | 67 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_logpwr.v | 504 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_maxhold.v | 71 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_packetizer.v | 136 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_rise_decay.v | 160 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v | 189 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v | 169 | ||||
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/rng.v | 87 |
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 |