aboutsummaryrefslogtreecommitdiffstats
path: root/host/examples/rfnoc-example/fpga/rfnoc_block_gain
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2021-03-04 16:27:24 -0600
committerWade Fife <wade.fife@ettus.com>2021-03-17 17:46:06 -0500
commitada6a4e46770d22d528b2b6fbc2bdd71e5e3064d (patch)
tree21ba4229fb195da6fc1da4907ec00aed85a07c6c /host/examples/rfnoc-example/fpga/rfnoc_block_gain
parent866df135adb91299d1009c1b1d2053dd3112acda (diff)
downloaduhd-ada6a4e46770d22d528b2b6fbc2bdd71e5e3064d.tar.gz
uhd-ada6a4e46770d22d528b2b6fbc2bdd71e5e3064d.tar.bz2
uhd-ada6a4e46770d22d528b2b6fbc2bdd71e5e3064d.zip
examples: Add IP to OOT RFNoC gain example
This updates the gain example to show how to use RFNoC IP, in-tree Xilinx IP, and out-of-tree Xilinx IP in a custom RFNoC block.
Diffstat (limited to 'host/examples/rfnoc-example/fpga/rfnoc_block_gain')
-rw-r--r--host/examples/rfnoc-example/fpga/rfnoc_block_gain/Makefile26
-rw-r--r--host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain.v132
2 files changed, 124 insertions, 34 deletions
diff --git a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/Makefile b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/Makefile
index 1ff3046ee..0239041b9 100644
--- a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/Makefile
+++ b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/Makefile
@@ -19,24 +19,40 @@ include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
#-------------------------------------------------
# Design Specific
#-------------------------------------------------
+
+# In-tree IP
+LIB_IP_DIR = $(BASE_DIR)/../lib/ip
+include $(LIB_IP_DIR)/complex_multiplier/Makefile.inc
+
+# Out-of-tree IP
+OOT_FPGA_DIR = $(dir $(abspath $(firstword $(MAKEFILE_LIST))))/../
+include $(OOT_FPGA_DIR)/ip/cmplx_mul/Makefile.inc
+
# Include makefiles and sources for the DUT and its
# dependencies.
+include $(BASE_DIR)/../lib/rfnoc/Makefile.srcs
include $(BASE_DIR)/../lib/rfnoc/core/Makefile.srcs
include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs
include Makefile.srcs
-DESIGN_SRCS += $(abspath \
-$(RFNOC_CORE_SRCS) \
-$(RFNOC_UTIL_SRCS) \
-$(RFNOC_OOT_SRCS) \
+DESIGN_SRCS += $(abspath \
+$(RFNOC_SRCS) \
+$(RFNOC_CORE_SRCS) \
+$(RFNOC_UTIL_SRCS) \
+$(RFNOC_OOT_SRCS) \
+$(LIB_IP_CMPLX_MUL_SRCS) \
+$(LIB_IP_COMPLEX_MULTIPLIER_SRCS) \
)
#-------------------------------------------------
# Testbench Specific
#-------------------------------------------------
-SIM_TOP = rfnoc_block_gain_tb
+SIM_TOP = rfnoc_block_gain_tb glbl
SIM_SRCS = \
+$(abspath $(IP_BUILD_DIR)/cmplx_mul/sim/cmplx_mul.vhd) \
+$(abspath $(IP_BUILD_DIR)/complex_multiplier/sim/complex_multiplier.vhd) \
$(abspath rfnoc_block_gain_tb.sv) \
+$(VIVADO_PATH)/data/verilog/src/glbl.v \
#-------------------------------------------------
# Bottom-of-Makefile
diff --git a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain.v b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain.v
index 929439a52..6f050e8bc 100644
--- a/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain.v
+++ b/host/examples/rfnoc-example/fpga/rfnoc_block_gain/rfnoc_block_gain.v
@@ -17,6 +17,11 @@
// CHDR_W : AXIS-CHDR data bus width
// MTU : Maximum transmission unit (i.e., maximum packet size in
// CHDR words is 2**MTU).
+// IP_OPTION : Select which IP to use for the complex multiply. Use one of
+// the following options:
+// HDL_IP = In-tree RFNoC HDL, with a DSP48E1 primitive
+// IN_TREE_IP = In-tree "complex_multiplier" (Xilinx IP)
+// OUT_OF_TREE_IP = Out-of-tree "cmplx_mul" (Xilinx IP)
//
`default_nettype none
@@ -25,7 +30,8 @@
module rfnoc_block_gain #(
parameter [9:0] THIS_PORTID = 10'd0,
parameter CHDR_W = 64,
- parameter [5:0] MTU = 10
+ parameter [5:0] MTU = 10,
+ parameter IP_OPTION = "HDL_IP"
)(
// RFNoC Framework Clocks and Resets
input wire rfnoc_chdr_clk,
@@ -250,36 +256,104 @@ module rfnoc_block_gain #(
wire mult_tvalid;
wire mult_tready;
- // Multiply complex sample by a real-valued gain. Only input the gain
- // (real_tvalid) when we have payload data to go in (cplx_tdata). That way
- // the current gain value always applies to the current sample. This assumes
- // that real_tready and cplx_tready have identical behavior.
+ // Multiply each complex sample by a real-valued gain. Only input the gain
+ // when we have payload data to go in (m_in_payload_tdata). That way the
+ // current gain value always applies to the current sample. This assumes that
+ // the tready of both inputs have identical behavior.
//
// Note that we receive the data with I on bits [31:16] and Q on bits [15:0],
- // but this does not matter to our multiplier.
- //
- mult_rc #(
- .WIDTH_REAL (16),
- .WIDTH_CPLX (16),
- .WIDTH_P (32),
- .DROP_TOP_P (5), // Must be 5 for a normal multiply in DSP48E1
- .LATENCY (4) // Turn on all pipeline registers in the DSP48E1
- ) mult_rc_i (
- .clk (axis_data_clk),
- .reset (axis_data_rst),
- .real_tdata (reg_gain),
- .real_tlast (m_in_payload_tlast),
- .real_tvalid (m_in_payload_tvalid),
- .real_tready (),
- .cplx_tdata (m_in_payload_tdata),
- .cplx_tlast (m_in_payload_tlast),
- .cplx_tvalid (m_in_payload_tvalid),
- .cplx_tready (m_in_payload_tready),
- .p_tdata (mult_tdata),
- .p_tlast (mult_tlast),
- .p_tvalid (mult_tvalid),
- .p_tready (mult_tready)
- );
+ // but the I/Q order does not matter to our complex multiplier.
+
+ generate
+ // Use a generate statement to choose which IP to use for the multiply.
+ // These all do the same thing and we only have multiple options to show
+ // how you can use IP from different locations.
+
+ if (IP_OPTION == "HDL_IP") begin : gen_rfnoc_ip
+ // Use the RFNoC mult_rc Verilog module, which uses a DSP48E1 primitive
+ mult_rc #(
+ .WIDTH_REAL (16),
+ .WIDTH_CPLX (16),
+ .WIDTH_P (32),
+ .DROP_TOP_P (5), // Must be 5 for a normal multiply in DSP48E1
+ .LATENCY (4) // Turn on all pipeline registers in the DSP48E1
+ ) mult_rc_i (
+ .clk (axis_data_clk),
+ .reset (axis_data_rst),
+ .real_tdata (reg_gain),
+ .real_tlast (m_in_payload_tlast),
+ .real_tvalid (m_in_payload_tvalid),
+ .real_tready (),
+ .cplx_tdata (m_in_payload_tdata),
+ .cplx_tlast (m_in_payload_tlast),
+ .cplx_tvalid (m_in_payload_tvalid),
+ .cplx_tready (m_in_payload_tready),
+ .p_tdata (mult_tdata),
+ .p_tlast (mult_tlast),
+ .p_tvalid (mult_tvalid),
+ .p_tready (mult_tready)
+ );
+
+ end else if (IP_OPTION == "IN_TREE_IP") begin : gen_in_tree_ip
+ // Use the in-tree "complex_multiplier" IP, which is a Xilinx Complex
+ // Multiplier LogiCORE IP located in the UHD repository in
+ // fpga/usrp3/lib/ip/.
+
+ // The LSB of the output is clipped in this IP, so double the gain to
+ // compensate. This limits the maximum gain in this version.
+ wire [15:0] gain = 2*reg_gain;
+
+ complex_multiplier complex_multiplier (
+ .aclk (axis_data_clk),
+ .aresetn (~axis_data_rst),
+ .s_axis_a_tdata ({16'b0, gain}),
+ .s_axis_a_tlast (m_in_payload_tlast),
+ .s_axis_a_tvalid (m_in_payload_tvalid),
+ .s_axis_a_tready (),
+ .s_axis_b_tdata (m_in_payload_tdata),
+ .s_axis_b_tlast (m_in_payload_tlast),
+ .s_axis_b_tvalid (m_in_payload_tvalid),
+ .s_axis_b_tready (m_in_payload_tready),
+ .s_axis_ctrl_tdata (8'd0),
+ .s_axis_ctrl_tvalid (1'b1),
+ .s_axis_ctrl_tready (),
+ .m_axis_dout_tdata (mult_tdata),
+ .m_axis_dout_tlast (mult_tlast),
+ .m_axis_dout_tvalid (mult_tvalid),
+ .m_axis_dout_tready (mult_tready)
+ );
+
+ end else if (IP_OPTION == "OUT_OF_TREE_IP") begin : gen_oot_ip
+ // Use the out-of-tree "cmplx_mul" IP, which is a Xilinx Complex
+ // Multiplier LogiCORE IP located in the IP directory of this example.
+
+ // This IP has a 33-bit output, but because it's AXI-Stream, each
+ // component is placed in a 5-byte word. Since our gain is real only,
+ // we'll never need all 33-bits.
+ wire [79:0] m_axis_dout_tdata;
+
+ cmplx_mul cmplx_mul_i (
+ .aclk (axis_data_clk),
+ .aresetn (~axis_data_rst),
+ .s_axis_a_tdata ({16'd0, reg_gain}),
+ .s_axis_a_tlast (m_in_payload_tlast),
+ .s_axis_a_tvalid (m_in_payload_tvalid),
+ .s_axis_a_tready (),
+ .s_axis_b_tdata (m_in_payload_tdata),
+ .s_axis_b_tlast (m_in_payload_tlast),
+ .s_axis_b_tvalid (m_in_payload_tvalid),
+ .s_axis_b_tready (m_in_payload_tready),
+ .m_axis_dout_tdata (m_axis_dout_tdata),
+ .m_axis_dout_tlast (mult_tlast),
+ .m_axis_dout_tvalid (mult_tvalid),
+ .m_axis_dout_tready (mult_tready)
+ );
+
+ assign mult_tdata[31: 0] = m_axis_dout_tdata[31: 0];
+ assign mult_tdata[63:32] = m_axis_dout_tdata[71:40];
+
+ end
+ endgenerate
// Clip the results
axi_clip_complex #(