diff --git a/README.md b/README.md index 18eef6a26..6def17258 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Corundum currently supports devices from both Xilinx and Intel, on boards from s * Xilinx Alveo U200 (Xilinx Virtex UltraScale+ XCU200) * Xilinx Alveo U250 (Xilinx Virtex UltraScale+ XCU250) * Xilinx Alveo U280 (Xilinx Virtex UltraScale+ XCU280) +* Xilinx Kria KR260 (Xilinx Zynq UltraScale+ XCK26) * Xilinx VCU108 (Xilinx Virtex UltraScale XCVU095) * Xilinx VCU118 (Xilinx Virtex UltraScale+ XCVU9P) * Xilinx VCU1525 (Xilinx Virtex UltraScale+ XCVU9P) diff --git a/docs/source/devicelist.rst b/docs/source/devicelist.rst index b3aae008b..7181f7a51 100644 --- a/docs/source/devicelist.rst +++ b/docs/source/devicelist.rst @@ -184,6 +184,7 @@ This section details SoC targets, which interface with CPU cores on the same dev ============ ================= ==================== ========== Manufacturer Board FPGA Board ID ============ ================= ==================== ========== + Xilinx KR260 XCK26-2SFVC784C 0x10ee9104 Xilinx ZCU102 XCZU9EG-2FFVB1156E 0x10ee9066 Xilinx ZCU106 XCZU7EV-2FFVC1156E 0x10ee906a ============ ================= ==================== ========== @@ -193,6 +194,7 @@ This section details SoC targets, which interface with CPU cores on the same dev ================= ========= ========== =============================== ===== Board PCIe IF Network IF DDR HBM ================= ========= ========== =============================== ===== + KR260 \- 1x SFP+ \- \- ZCU102 \- 4x SFP+ 512 MB DDR4 2400 (256M x16) \- ZCU106 Gen 3 x4 2x SFP+ 2 GB DDR4 2400 (256M x64) \- ================= ========= ========== =============================== ===== @@ -202,6 +204,7 @@ This section details SoC targets, which interface with CPU cores on the same dev ================= ============ ============ ========== Board I2C :sup:`1` MAC :sup:`2` FW update ================= ============ ============ ========== + KR260 N N N ZCU102 Y Y :sup:`3` N ZCU106 Y Y :sup:`3` N ================= ============ ============ ========== @@ -215,6 +218,7 @@ This section details SoC targets, which interface with CPU cores on the same dev ================= ========================= ==== ======= ==== ===== Board Design IFxP RXQ/TXQ MAC Sched ================= ========================= ==== ======= ==== ===== + KR260 mqnic/fpga/fpga 1x1 32/32 10G RR ZCU102 mqnic/fpga/fpga 2x1 32/32 10G RR ZCU106 mqnic/fpga_zynqmp/fpga 2x1 32/32 10G RR ================= ========================= ==== ======= ==== ===== diff --git a/docs/source/index.rst b/docs/source/index.rst index d72357cd1..069a50b5f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -31,6 +31,7 @@ Corundum currently supports devices from both Xilinx and Intel, on boards from s * Xilinx Alveo U200 (Xilinx Virtex UltraScale+ XCU200) * Xilinx Alveo U250 (Xilinx Virtex UltraScale+ XCU250) * Xilinx Alveo U280 (Xilinx Virtex UltraScale+ XCU280) +* Xilinx Kria KR260 (Xilinx Zynq UltraScale+ XCK26) * Xilinx VCU108 (Xilinx Virtex UltraScale XCVU095) * Xilinx VCU118 (Xilinx Virtex UltraScale+ XCVU9P) * Xilinx VCU1525 (Xilinx Virtex UltraScale+ XCVU9P) diff --git a/fpga/mqnic/KR260/fpga/README.md b/fpga/mqnic/KR260/fpga/README.md new file mode 100644 index 000000000..328cc44a3 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/README.md @@ -0,0 +1,30 @@ +# Corundum mqnic for KR260 + +## Introduction + +This design targets the Xilinx KR260 FPGA board. + +* FPGA: K26 SoM (xck26-sfvc784-2LV-c) +* PHY: 10G BASE-R PHY IP core and internal GTH transceiver + +## Quick start for Ubuntu + +### Build FPGA bitstream + +Run `make app` in the `fpga` subdirectory to build the bitstream, `.xsa` file, and device tree overlay. Ensure that the Xilinx Vivado toolchain components are in PATH (source `settings64.sh` in Vivado installation directory). + +### Installation + +Download an Ubuntu image for the KR260 here: https://ubuntu.com/download/amd-xilinx. Write the image to an SD card with `dd`, for example: + + xzcat ubuntu.img.xz | dd of=/dev/sdX + +Copy files in `fpga/app` to `/lib/firmware/xilinx/mqnic` on the KR260. Also make a copy of the source repo on the KR260 from which the kernel module and userspace tools can be built. + +### Build driver and userspace tools + +On the KR260, run `make` in `modules/mqnic` to build the driver. Ensure the headers for the running kernel are installed, otherwise the driver cannot be compiled. Then run `make` in `utils` to build the userspace tools. + +### Testing + +On the KR260, run `sudo xmutil unloadapp` to unload the FPGA, then `sudo xmutil loadapp mqnic` to load the configuration. Then, build the kernel module and userspace tools by running `make` in `modules/mqnic` and `utils`. Finally, load the kernel module with `insmod mqnic.ko`. Check `dmesg` for output from driver initialization. Run `mqnic-dump -d /dev/mqnic0` to dump the internal state. diff --git a/fpga/mqnic/KR260/fpga/app b/fpga/mqnic/KR260/fpga/app new file mode 120000 index 000000000..4d46690fb --- /dev/null +++ b/fpga/mqnic/KR260/fpga/app @@ -0,0 +1 @@ +../../../app/ \ No newline at end of file diff --git a/fpga/mqnic/KR260/fpga/common/vivado.mk b/fpga/mqnic/KR260/fpga/common/vivado.mk new file mode 100644 index 000000000..302e74568 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/common/vivado.mk @@ -0,0 +1,141 @@ +################################################################### +# +# Xilinx Vivado FPGA Makefile +# +# Copyright (c) 2016 Alex Forencich +# +################################################################### +# +# Parameters: +# FPGA_TOP - Top module name +# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale) +# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e) +# SYN_FILES - space-separated list of source files +# INC_FILES - space-separated list of include files +# XDC_FILES - space-separated list of timing constraint files +# XCI_FILES - space-separated list of IP XCI files +# +# Example: +# +# FPGA_TOP = fpga +# FPGA_FAMILY = VirtexUltrascale +# FPGA_DEVICE = xcvu095-ffva2104-2-e +# SYN_FILES = rtl/fpga.v +# XDC_FILES = fpga.xdc +# XCI_FILES = ip/pcspma.xci +# include ../common/vivado.mk +# +################################################################### + +# phony targets +.PHONY: fpga vivado tmpclean clean distclean + +# prevent make from deleting intermediate files and reports +.PRECIOUS: %.xpr %.bit %.bin %.mcs %.prm +.SECONDARY: + +CONFIG ?= config.mk +-include ../$(CONFIG) + +FPGA_TOP ?= fpga +PROJECT ?= $(FPGA_TOP) + +SYN_FILES_REL = $(foreach p,$(SYN_FILES),$(if $(filter /% ./%,$p),$p,../$p)) +INC_FILES_REL = $(foreach p,$(INC_FILES),$(if $(filter /% ./%,$p),$p,../$p)) +XCI_FILES_REL = $(foreach p,$(XCI_FILES),$(if $(filter /% ./%,$p),$p,../$p)) +IP_TCL_FILES_REL = $(foreach p,$(IP_TCL_FILES),$(if $(filter /% ./%,$p),$p,../$p)) +CONFIG_TCL_FILES_REL = $(foreach p,$(CONFIG_TCL_FILES),$(if $(filter /% ./%,$p),$p,../$p)) + +ifdef XDC_FILES + XDC_FILES_REL = $(foreach p,$(XDC_FILES),$(if $(filter /% ./%,$p),$p,../$p)) +else + XDC_FILES_REL = $(PROJECT).xdc +endif + +################################################################### +# Main Targets +# +# all: build everything +# clean: remove output files and project files +################################################################### + +all: fpga + +fpga: $(PROJECT).bit + +vivado: $(PROJECT).xpr + vivado $(PROJECT).xpr + +tmpclean:: + -rm -rf *.log *.jou *.cache *.gen *.hbs *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v + -rm -rf create_project.tcl update_config.tcl run_synth.tcl run_impl.tcl generate_bit.tcl + +clean:: tmpclean + -rm -rf *.bit *.bin *.ltx *.xsa program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl + -rm -rf *_utilization.rpt *_utilization_hierarchical.rpt + +distclean:: clean + -rm -rf rev + +################################################################### +# Target implementations +################################################################### + +# Vivado project file +create_project.tcl: Makefile $(XCI_FILES_REL) $(IP_TCL_FILES_REL) + rm -rf defines.v + touch defines.v + for x in $(DEFS); do echo '`define' $$x >> defines.v; done + echo "create_project -force -part $(FPGA_PART) $(PROJECT)" > $@ + echo "add_files -fileset sources_1 defines.v $(SYN_FILES_REL)" >> $@ + echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@ + echo "add_files -fileset constrs_1 $(XDC_FILES_REL)" >> $@ + for x in $(XCI_FILES_REL); do echo "import_ip $$x" >> $@; done + for x in $(IP_TCL_FILES_REL); do echo "source $$x" >> $@; done + for x in $(CONFIG_TCL_FILES_REL); do echo "source $$x" >> $@; done + +update_config.tcl: $(CONFIG_TCL_FILES_REL) + echo "open_project -quiet $(PROJECT).xpr" > $@ + for x in $(CONFIG_TCL_FILES_REL); do echo "source $$x" >> $@; done + +$(PROJECT).xpr: create_project.tcl update_config.tcl + vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x) + +# synthesis run +$(PROJECT).runs/synth_1/$(PROJECT).dcp: $(PROJECT).xpr $(SYN_FILES_REL) $(INC_FILES_REL) $(XDC_FILES_REL) $(CONFIG_TCL_FILES_REL) + echo "open_project $(PROJECT).xpr" > run_synth.tcl + echo "reset_run synth_1" >> run_synth.tcl + echo "launch_runs -jobs 4 synth_1" >> run_synth.tcl + echo "wait_on_run synth_1" >> run_synth.tcl + vivado -nojournal -nolog -mode batch -source run_synth.tcl + +# implementation run +$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp + echo "open_project $(PROJECT).xpr" > run_impl.tcl + echo "reset_run impl_1" >> run_impl.tcl + echo "launch_runs -jobs 4 impl_1" >> run_impl.tcl + echo "wait_on_run impl_1" >> run_impl.tcl + echo "open_run impl_1" >> run_impl.tcl + echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl + echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl + vivado -nojournal -nolog -mode batch -source run_impl.tcl + +# bit file +$(PROJECT).bit $(PROJECT).bin $(PROJECT).ltx $(PROJECT).xsa: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp + echo "open_project $(PROJECT).xpr" > generate_bit.tcl + echo "open_run impl_1" >> generate_bit.tcl + echo "write_bitstream -force -bin_file $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl + echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl + echo "write_hw_platform -fixed -force -include_bit $(PROJECT).xsa" >> generate_bit.tcl + vivado -nojournal -nolog -mode batch -source generate_bit.tcl + ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit . + ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bin . + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi + mkdir -p rev + COUNT=100; \ + while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \ + do COUNT=$$((COUNT+1)); done; \ + cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \ + cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bin rev/$(PROJECT)_rev$$COUNT.bin; \ + if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi; \ + cp -pv $(PROJECT).xsa rev/$(PROJECT)_rev$$COUNT.xsa; diff --git a/fpga/mqnic/KR260/fpga/fpga.xdc b/fpga/mqnic/KR260/fpga/fpga.xdc new file mode 100644 index 000000000..509712d76 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/fpga.xdc @@ -0,0 +1,42 @@ +# XDC constraints for the Xilinx KR260 board +# part: xck26-sfvc784-2LV-c + +# General configuration +set_property BITSTREAM.GENERAL.COMPRESS true [current_design] + +# LEDs +set_property -dict {LOC F8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[0]}] ;# HPA14P som240_1_d13 +set_property -dict {LOC E8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[1]}] ;# HPA14N som240_1_d14 + +set_property -dict {LOC G8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_led[0]}] ;# HPA13P som240_1_a12 +set_property -dict {LOC F7 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_led[1]}] ;# HPA13N som240_1_a13 + +set_false_path -to [get_ports {led[*] sfp_led[*]}] +set_output_delay 0 [get_ports {led[*] sfp_led[*]}] + +# SFP+ Interface +set_property -dict {LOC T2 } [get_ports sfp_rx_p] ;# MGTHRXP2_224 GTHE4_CHANNEL_X1Y12 / GTHE4_COMMON_X1Y3 +set_property -dict {LOC T1 } [get_ports sfp_rx_n] ;# MGTHRXN2_224 GTHE4_CHANNEL_X1Y12 / GTHE4_COMMON_X1Y3 +set_property -dict {LOC R4 } [get_ports sfp_tx_p] ;# MGTHTXP2_224 GTHE4_CHANNEL_X1Y12 / GTHE4_COMMON_X1Y3 +set_property -dict {LOC R3 } [get_ports sfp_tx_n] ;# MGTHTXN2_224 GTHE4_CHANNEL_X1Y12 / GTHE4_COMMON_X1Y3 +set_property -dict {LOC Y6 } [get_ports sfp_mgt_refclk_p] ;# MGTREFCLK0P_224 from U90 +set_property -dict {LOC Y5 } [get_ports sfp_mgt_refclk_n] ;# MGTREFCLK0N_224 from U90 +set_property -dict {LOC Y10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_tx_disable] ;# HDB19 som240_2_a47 +set_property -dict {LOC A10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_tx_fault] ;# HDA19 som240_1_c23 +set_property -dict {LOC J12 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_rx_los] ;# HDA10 som240_1_a16 +set_property -dict {LOC W10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_mod_abs] ;# HDB18 som240_2_a46 +set_property -dict {LOC AB11 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_i2c_scl] ;# HDB16 som240_2_b49 +set_property -dict {LOC AC11 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports sfp_i2c_sda] ;# HDB17 som240_2_b50 + +# 156.25 MHz MGT reference clock +create_clock -period 6.400 -name sfp_mgt_refclk [get_ports sfp_mgt_refclk_p] + +set_false_path -to [get_ports {sfp_tx_disable}] +set_output_delay 0 [get_ports {sfp_tx_disable}] +set_false_path -from [get_ports {sfp_tx_fault sfp_rx_los sfp_mod_abs}] +set_input_delay 0 [get_ports {sfp_tx_fault sfp_rx_los sfp_mod_abs}] + +set_false_path -to [get_ports {sfp_i2c_sda sfp_i2c_scl}] +set_output_delay 0 [get_ports {sfp_i2c_sda sfp_i2c_scl}] +set_false_path -from [get_ports {sfp_i2c_sda sfp_i2c_scl}] +set_input_delay 0 [get_ports {sfp_i2c_sda sfp_i2c_scl}] diff --git a/fpga/mqnic/KR260/fpga/fpga/Makefile b/fpga/mqnic/KR260/fpga/fpga/Makefile new file mode 100644 index 000000000..97e2c59e2 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/fpga/Makefile @@ -0,0 +1,160 @@ + +# FPGA settings +FPGA_PART = xck26-sfvc784-2LV-c +FPGA_TOP = fpga +FPGA_ARCH = zynquplus + +# Files for synthesis +SYN_FILES = rtl/fpga.v +SYN_FILES += rtl/fpga_core.v +SYN_FILES += rtl/sync_signal.v +SYN_FILES += rtl/common/mqnic_core_axi.v +SYN_FILES += rtl/common/mqnic_core.v +SYN_FILES += rtl/common/mqnic_dram_if.v +SYN_FILES += rtl/common/mqnic_interface.v +SYN_FILES += rtl/common/mqnic_interface_tx.v +SYN_FILES += rtl/common/mqnic_interface_rx.v +SYN_FILES += rtl/common/mqnic_port.v +SYN_FILES += rtl/common/mqnic_port_tx.v +SYN_FILES += rtl/common/mqnic_port_rx.v +SYN_FILES += rtl/common/mqnic_egress.v +SYN_FILES += rtl/common/mqnic_ingress.v +SYN_FILES += rtl/common/mqnic_l2_egress.v +SYN_FILES += rtl/common/mqnic_l2_ingress.v +SYN_FILES += rtl/common/mqnic_rx_queue_map.v +SYN_FILES += rtl/common/mqnic_ptp.v +SYN_FILES += rtl/common/mqnic_ptp_clock.v +SYN_FILES += rtl/common/mqnic_ptp_perout.v +SYN_FILES += rtl/common/mqnic_rb_clk_info.v +SYN_FILES += rtl/common/mqnic_port_map_phy_xgmii.v +SYN_FILES += rtl/common/cpl_write.v +SYN_FILES += rtl/common/cpl_op_mux.v +SYN_FILES += rtl/common/desc_fetch.v +SYN_FILES += rtl/common/desc_op_mux.v +SYN_FILES += rtl/common/event_mux.v +SYN_FILES += rtl/common/queue_manager.v +SYN_FILES += rtl/common/cpl_queue_manager.v +SYN_FILES += rtl/common/tx_fifo.v +SYN_FILES += rtl/common/rx_fifo.v +SYN_FILES += rtl/common/tx_req_mux.v +SYN_FILES += rtl/common/tx_engine.v +SYN_FILES += rtl/common/rx_engine.v +SYN_FILES += rtl/common/tx_checksum.v +SYN_FILES += rtl/common/rx_hash.v +SYN_FILES += rtl/common/rx_checksum.v +SYN_FILES += rtl/common/rb_drp.v +SYN_FILES += rtl/common/eth_xcvr_phy_10g_gty_wrapper.v +SYN_FILES += rtl/common/eth_xcvr_phy_10g_gty_quad_wrapper.v +SYN_FILES += rtl/common/stats_counter.v +SYN_FILES += rtl/common/stats_collect.v +SYN_FILES += rtl/common/stats_dma_if_axi.v +SYN_FILES += rtl/common/stats_dma_latency.v +SYN_FILES += rtl/common/mqnic_tx_scheduler_block_rr.v +SYN_FILES += rtl/common/tx_scheduler_rr.v +SYN_FILES += rtl/common/tdma_scheduler.v +SYN_FILES += rtl/common/tdma_ber.v +SYN_FILES += rtl/common/tdma_ber_ch.v +SYN_FILES += lib/eth/rtl/eth_mac_10g.v +SYN_FILES += lib/eth/rtl/axis_xgmii_rx_64.v +SYN_FILES += lib/eth/rtl/axis_xgmii_tx_64.v +SYN_FILES += lib/eth/rtl/eth_phy_10g.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_if.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_frame_sync.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_ber_mon.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_watchdog.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx_if.v +SYN_FILES += lib/eth/rtl/xgmii_baser_dec_64.v +SYN_FILES += lib/eth/rtl/xgmii_baser_enc_64.v +SYN_FILES += lib/eth/rtl/lfsr.v +SYN_FILES += lib/eth/rtl/ptp_clock.v +SYN_FILES += lib/eth/rtl/ptp_clock_cdc.v +SYN_FILES += lib/eth/rtl/ptp_perout.v +SYN_FILES += lib/axi/rtl/axil_interconnect.v +SYN_FILES += lib/axi/rtl/axil_crossbar.v +SYN_FILES += lib/axi/rtl/axil_crossbar_addr.v +SYN_FILES += lib/axi/rtl/axil_crossbar_rd.v +SYN_FILES += lib/axi/rtl/axil_crossbar_wr.v +SYN_FILES += lib/axi/rtl/axil_reg_if.v +SYN_FILES += lib/axi/rtl/axil_reg_if_rd.v +SYN_FILES += lib/axi/rtl/axil_reg_if_wr.v +SYN_FILES += lib/axi/rtl/axil_register_rd.v +SYN_FILES += lib/axi/rtl/axil_register_wr.v +SYN_FILES += lib/axi/rtl/arbiter.v +SYN_FILES += lib/axi/rtl/priority_encoder.v +SYN_FILES += lib/axis/rtl/axis_adapter.v +SYN_FILES += lib/axis/rtl/axis_arb_mux.v +SYN_FILES += lib/axis/rtl/axis_async_fifo.v +SYN_FILES += lib/axis/rtl/axis_async_fifo_adapter.v +SYN_FILES += lib/axis/rtl/axis_demux.v +SYN_FILES += lib/axis/rtl/axis_fifo.v +SYN_FILES += lib/axis/rtl/axis_fifo_adapter.v +SYN_FILES += lib/axis/rtl/axis_pipeline_fifo.v +SYN_FILES += lib/axis/rtl/axis_register.v +SYN_FILES += lib/axis/rtl/sync_reset.v +SYN_FILES += lib/pcie/rtl/irq_rate_limit.v +SYN_FILES += lib/pcie/rtl/dma_if_axi.v +SYN_FILES += lib/pcie/rtl/dma_if_axi_rd.v +SYN_FILES += lib/pcie/rtl/dma_if_axi_wr.v +SYN_FILES += lib/pcie/rtl/dma_if_mux.v +SYN_FILES += lib/pcie/rtl/dma_if_mux_rd.v +SYN_FILES += lib/pcie/rtl/dma_if_mux_wr.v +SYN_FILES += lib/pcie/rtl/dma_if_desc_mux.v +SYN_FILES += lib/pcie/rtl/dma_ram_demux_rd.v +SYN_FILES += lib/pcie/rtl/dma_ram_demux_wr.v +SYN_FILES += lib/pcie/rtl/dma_psdpram.v +SYN_FILES += lib/pcie/rtl/dma_client_axis_sink.v +SYN_FILES += lib/pcie/rtl/dma_client_axis_source.v + +# XDC files +XDC_FILES = fpga.xdc +XDC_FILES += lib/axis/syn/vivado/axis_async_fifo.tcl +XDC_FILES += lib/axis/syn/vivado/sync_reset.tcl +XDC_FILES += lib/eth/syn/vivado/ptp_clock_cdc.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_port.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_ptp_clock.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_rb_clk_info.tcl +XDC_FILES += ../../../common/syn/vivado/rb_drp.tcl +XDC_FILES += ../../../common/syn/vivado/eth_xcvr_phy_10g_gty_wrapper.tcl +XDC_FILES += ../../../common/syn/vivado/tdma_ber_ch.tcl + +# IP +IP_TCL_FILES = ip/zynq_ps.tcl +IP_TCL_FILES += ip/eth_xcvr_gth.tcl + +# Configuration +CONFIG_TCL_FILES = ./config.tcl + +include ../common/vivado.mk + +program: $(FPGA_TOP).bit + echo "open_hw" > program.tcl + echo "connect_hw_server" >> program.tcl + echo "open_hw_target" >> program.tcl + echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl + echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl + echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl + echo "program_hw_devices [current_hw_device]" >> program.tcl + echo "exit" >> program.tcl + vivado -nojournal -nolog -mode batch -source program.tcl + +APP_DIR = app + +$(APP_DIR)/shell.json: + @mkdir -p $(@D) + echo '{"shell_type": "XRT_FLAT", "num_slots": "1"}' > $@ + +$(APP_DIR)/$(FPGA_TOP).bin: $(FPGA_TOP).bin + @mkdir -p $(@D) + cp $< $@ + +$(APP_DIR)/overlay.dtbo: ../ps/overlay.dtsi + @mkdir -p $(@D) + dtc -@ -O dtb -o $@ $^ + +.PHONY: app +app: $(APP_DIR)/$(FPGA_TOP).bin $(APP_DIR)/shell.json $(APP_DIR)/overlay.dtbo + +clean:: + -rm -rf $(APP_DIR) diff --git a/fpga/mqnic/KR260/fpga/fpga/config.tcl b/fpga/mqnic/KR260/fpga/fpga/config.tcl new file mode 100644 index 000000000..fc1a7fcf3 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/fpga/config.tcl @@ -0,0 +1,203 @@ +# Copyright 2021, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +set params [dict create] + +# collect build information +set build_date [clock seconds] +set git_hash 00000000 +set git_tag "" + +if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } { + puts "Error running git or project not under version control" +} + +if { [catch {set git_tag [exec git describe --tags HEAD]}] } { + puts "Error running git, project not under version control, or no tag found" +} + +puts "Build date: ${build_date}" +puts "Git hash: ${git_hash}" +puts "Git tag: ${git_tag}" + +if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } { + puts "Failed to extract version from git tag" + set tag_ver 0.0.1 +} + +puts "Tag version: ${tag_ver}" + +# FW and board IDs +set fpga_id [expr 0x4A49093] +set fw_id [expr 0x00000000] +set fw_ver $tag_ver +set board_vendor_id [expr 0x10ee] +set board_device_id [expr 0x9104] +set board_ver 1.0 +set release_info [expr 0x00000000] + +# FW ID block +dict set params FPGA_ID [format "32'h%08x" $fpga_id] +dict set params FW_ID [format "32'h%08x" $fw_id] +dict set params FW_VER [format "32'h%02x%02x%02x%02x" {*}[split $fw_ver .-] 0 0 0 0] +dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id] +dict set params BOARD_VER [format "32'h%02x%02x%02x%02x" {*}[split $board_ver .-] 0 0 0 0] +dict set params BUILD_DATE "32'd${build_date}" +dict set params GIT_HASH "32'h${git_hash}" +dict set params RELEASE_INFO [format "32'h%08x" $release_info] + +# Board configuration +dict set params TDMA_BER_ENABLE "0" + +# Structural configuration +dict set params IF_COUNT "1" +dict set params PORTS_PER_IF "1" +dict set params SCHED_PER_IF [dict get $params PORTS_PER_IF] +dict set params PORT_MASK "0" + +# Clock configuration +dict set params CLK_PERIOD_NS_NUM "4" +dict set params CLK_PERIOD_NS_DENOM "1" + +# PTP configuration +dict set params PTP_CLOCK_PIPELINE "0" +dict set params PTP_CLOCK_CDC_PIPELINE "0" +dict set params PTP_PORT_CDC_PIPELINE "0" +dict set params PTP_PEROUT_ENABLE "1" +dict set params PTP_PEROUT_COUNT "1" + +# Queue manager configuration +dict set params EVENT_QUEUE_OP_TABLE_SIZE "32" +dict set params TX_QUEUE_OP_TABLE_SIZE "32" +dict set params RX_QUEUE_OP_TABLE_SIZE "32" +dict set params TX_CPL_QUEUE_OP_TABLE_SIZE [dict get $params TX_QUEUE_OP_TABLE_SIZE] +dict set params RX_CPL_QUEUE_OP_TABLE_SIZE [dict get $params RX_QUEUE_OP_TABLE_SIZE] +dict set params EVENT_QUEUE_INDEX_WIDTH "2" +dict set params TX_QUEUE_INDEX_WIDTH "5" +dict set params RX_QUEUE_INDEX_WIDTH "5" +dict set params TX_CPL_QUEUE_INDEX_WIDTH [dict get $params TX_QUEUE_INDEX_WIDTH] +dict set params RX_CPL_QUEUE_INDEX_WIDTH [dict get $params RX_QUEUE_INDEX_WIDTH] +dict set params EVENT_QUEUE_PIPELINE "3" +dict set params TX_QUEUE_PIPELINE [expr 3+([dict get $params TX_QUEUE_INDEX_WIDTH] > 12 ? [dict get $params TX_QUEUE_INDEX_WIDTH]-12 : 0)] +dict set params RX_QUEUE_PIPELINE [expr 3+([dict get $params RX_QUEUE_INDEX_WIDTH] > 12 ? [dict get $params RX_QUEUE_INDEX_WIDTH]-12 : 0)] +dict set params TX_CPL_QUEUE_PIPELINE [dict get $params TX_QUEUE_PIPELINE] +dict set params RX_CPL_QUEUE_PIPELINE [dict get $params RX_QUEUE_PIPELINE] + +# TX and RX engine configuration +dict set params TX_DESC_TABLE_SIZE "32" +dict set params RX_DESC_TABLE_SIZE "32" +dict set params RX_INDIR_TBL_ADDR_WIDTH [expr min([dict get $params RX_QUEUE_INDEX_WIDTH], 8)] + +# Scheduler configuration +dict set params TX_SCHEDULER_OP_TABLE_SIZE [dict get $params TX_DESC_TABLE_SIZE] +dict set params TX_SCHEDULER_PIPELINE [dict get $params TX_QUEUE_PIPELINE] +dict set params TDMA_INDEX_WIDTH "6" + +# Interface configuration +dict set params PTP_TS_ENABLE "1" +dict set params TX_CPL_FIFO_DEPTH "32" +dict set params TX_CHECKSUM_ENABLE "1" +dict set params RX_HASH_ENABLE "1" +dict set params RX_CHECKSUM_ENABLE "1" +dict set params TX_FIFO_DEPTH "32768" +dict set params RX_FIFO_DEPTH "32768" +dict set params MAX_TX_SIZE "9214" +dict set params MAX_RX_SIZE "9214" +dict set params TX_RAM_SIZE "32768" +dict set params RX_RAM_SIZE "32768" + +# Application block configuration +dict set params APP_ID "32'h00000000" +dict set params APP_ENABLE "0" +dict set params APP_CTRL_ENABLE "1" +dict set params APP_DMA_ENABLE "1" +dict set params APP_AXIS_DIRECT_ENABLE "1" +dict set params APP_AXIS_SYNC_ENABLE "1" +dict set params APP_AXIS_IF_ENABLE "1" +dict set params APP_STAT_ENABLE "1" + +# AXI DMA interface configuration +open_bd_design [get_files zynq_ps.bd] +set s_axi_dma [get_bd_intf_ports s_axi_dma] +dict set params AXI_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $s_axi_dma] +# dict set params AXI_ADDR_WIDTH [get_property CONFIG.ADDR_WIDTH $s_axi_dma] +dict set params AXI_ADDR_WIDTH 64 +dict set params AXI_ID_WIDTH [get_property CONFIG.ID_WIDTH $s_axi_dma] + +# DMA interface configuration +dict set params DMA_IMM_ENABLE "0" +dict set params DMA_IMM_WIDTH "32" +dict set params DMA_LEN_WIDTH "16" +dict set params DMA_TAG_WIDTH "16" +dict set params RAM_ADDR_WIDTH [expr int(ceil(log(max([dict get $params TX_RAM_SIZE], [dict get $params RX_RAM_SIZE]))/log(2)))] +dict set params RAM_PIPELINE "2" +# NOTE: Querying the BD top-level interface port (or even the ZynqMP's interface +# pin) yields 256 for the maximum burst length, instead of 16, which is +# the actually supported length (due to ZynqMP using AXI3 internally). +#dict set params AXI_DMA_MAX_BURST_LEN [get_property CONFIG.MAX_BURST_LENGTH $s_axi_dma] +dict set params AXI_DMA_MAX_BURST_LEN "16" + +# AXI lite interface configuration (control) +set m_axil_ctrl [get_bd_intf_ports m_axil_ctrl] +dict set params AXIL_CTRL_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $m_axil_ctrl] +dict set params AXIL_CTRL_ADDR_WIDTH 24 + +# AXI lite interface configuration (application control) +set m_axil_app_ctrl [get_bd_intf_ports m_axil_app_ctrl] +dict set params AXIL_APP_CTRL_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $m_axil_app_ctrl] +dict set params AXIL_APP_CTRL_ADDR_WIDTH 24 + +# Interrupt configuration +set irq [get_bd_ports pl_ps_irq0] +dict set params IRQ_COUNT [get_property CONFIG.PortWidth $irq] +close_bd_design [get_bd_designs zynq_ps] +dict set params IRQ_STRETCH "10" + +# Ethernet interface configuration +dict set params AXIS_ETH_TX_PIPELINE "0" +dict set params AXIS_ETH_TX_FIFO_PIPELINE "2" +dict set params AXIS_ETH_TX_TS_PIPELINE "0" +dict set params AXIS_ETH_RX_PIPELINE "0" +dict set params AXIS_ETH_RX_FIFO_PIPELINE "2" + +# Statistics counter subsystem +dict set params STAT_ENABLE "1" +dict set params STAT_DMA_ENABLE "1" +dict set params STAT_AXI_ENABLE "1" +dict set params STAT_INC_WIDTH "24" +dict set params STAT_ID_WIDTH "12" + +# apply parameters to top-level +set param_list {} +dict for {name value} $params { + lappend param_list $name=$value +} + +# set_property generic $param_list [current_fileset] +set_property generic $param_list [get_filesets sources_1] diff --git a/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/Makefile b/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/Makefile new file mode 100644 index 000000000..c45680c45 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/Makefile @@ -0,0 +1,170 @@ + +# FPGA settings +FPGA_PART = xck26-sfvc784-2LV-c +FPGA_TOP = fpga +FPGA_ARCH = zynquplus + +# Files for synthesis +SYN_FILES = rtl/fpga.v +SYN_FILES += rtl/fpga_core.v +SYN_FILES += rtl/sync_signal.v +SYN_FILES += rtl/common/mqnic_core_axi.v +SYN_FILES += rtl/common/mqnic_core.v +SYN_FILES += rtl/common/mqnic_dram_if.v +SYN_FILES += rtl/common/mqnic_interface.v +SYN_FILES += rtl/common/mqnic_interface_tx.v +SYN_FILES += rtl/common/mqnic_interface_rx.v +SYN_FILES += rtl/common/mqnic_port.v +SYN_FILES += rtl/common/mqnic_port_tx.v +SYN_FILES += rtl/common/mqnic_port_rx.v +SYN_FILES += rtl/common/mqnic_egress.v +SYN_FILES += rtl/common/mqnic_ingress.v +SYN_FILES += rtl/common/mqnic_l2_egress.v +SYN_FILES += rtl/common/mqnic_l2_ingress.v +SYN_FILES += rtl/common/mqnic_rx_queue_map.v +SYN_FILES += rtl/common/mqnic_ptp.v +SYN_FILES += rtl/common/mqnic_ptp_clock.v +SYN_FILES += rtl/common/mqnic_ptp_perout.v +SYN_FILES += rtl/common/mqnic_rb_clk_info.v +SYN_FILES += rtl/common/mqnic_port_map_phy_xgmii.v +SYN_FILES += rtl/common/cpl_write.v +SYN_FILES += rtl/common/cpl_op_mux.v +SYN_FILES += rtl/common/desc_fetch.v +SYN_FILES += rtl/common/desc_op_mux.v +SYN_FILES += rtl/common/event_mux.v +SYN_FILES += rtl/common/queue_manager.v +SYN_FILES += rtl/common/cpl_queue_manager.v +SYN_FILES += rtl/common/tx_fifo.v +SYN_FILES += rtl/common/rx_fifo.v +SYN_FILES += rtl/common/tx_req_mux.v +SYN_FILES += rtl/common/tx_engine.v +SYN_FILES += rtl/common/rx_engine.v +SYN_FILES += rtl/common/tx_checksum.v +SYN_FILES += rtl/common/rx_hash.v +SYN_FILES += rtl/common/rx_checksum.v +SYN_FILES += rtl/common/rb_drp.v +SYN_FILES += rtl/common/eth_xcvr_phy_10g_gty_wrapper.v +SYN_FILES += rtl/common/eth_xcvr_phy_10g_gty_quad_wrapper.v +SYN_FILES += rtl/common/stats_counter.v +SYN_FILES += rtl/common/stats_collect.v +SYN_FILES += rtl/common/stats_dma_if_axi.v +SYN_FILES += rtl/common/stats_dma_latency.v +SYN_FILES += rtl/common/mqnic_tx_scheduler_block_rr.v +SYN_FILES += rtl/common/tx_scheduler_rr.v +SYN_FILES += rtl/common/tdma_scheduler.v +SYN_FILES += rtl/common/tdma_ber.v +SYN_FILES += rtl/common/tdma_ber_ch.v +SYN_FILES += app/dma_bench/rtl/mqnic_app_block_dma_bench.v +SYN_FILES += app/dma_bench/rtl/dma_bench.v +SYN_FILES += app/dma_bench/rtl/dram_test_ch.v +SYN_FILES += lib/eth/rtl/eth_mac_10g.v +SYN_FILES += lib/eth/rtl/axis_xgmii_rx_64.v +SYN_FILES += lib/eth/rtl/axis_xgmii_tx_64.v +SYN_FILES += lib/eth/rtl/eth_phy_10g.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_if.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_frame_sync.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_ber_mon.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_rx_watchdog.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx.v +SYN_FILES += lib/eth/rtl/eth_phy_10g_tx_if.v +SYN_FILES += lib/eth/rtl/xgmii_baser_dec_64.v +SYN_FILES += lib/eth/rtl/xgmii_baser_enc_64.v +SYN_FILES += lib/eth/rtl/lfsr.v +SYN_FILES += lib/eth/rtl/ptp_clock.v +SYN_FILES += lib/eth/rtl/ptp_clock_cdc.v +SYN_FILES += lib/eth/rtl/ptp_perout.v +SYN_FILES += lib/axi/rtl/axi_vfifo_raw.v +SYN_FILES += lib/axi/rtl/axi_vfifo_raw_rd.v +SYN_FILES += lib/axi/rtl/axi_vfifo_raw_wr.v +SYN_FILES += lib/axi/rtl/axil_interconnect.v +SYN_FILES += lib/axi/rtl/axil_crossbar.v +SYN_FILES += lib/axi/rtl/axil_crossbar_addr.v +SYN_FILES += lib/axi/rtl/axil_crossbar_rd.v +SYN_FILES += lib/axi/rtl/axil_crossbar_wr.v +SYN_FILES += lib/axi/rtl/axil_reg_if.v +SYN_FILES += lib/axi/rtl/axil_reg_if_rd.v +SYN_FILES += lib/axi/rtl/axil_reg_if_wr.v +SYN_FILES += lib/axi/rtl/axil_register_rd.v +SYN_FILES += lib/axi/rtl/axil_register_wr.v +SYN_FILES += lib/axi/rtl/arbiter.v +SYN_FILES += lib/axi/rtl/priority_encoder.v +SYN_FILES += lib/axis/rtl/axis_adapter.v +SYN_FILES += lib/axis/rtl/axis_arb_mux.v +SYN_FILES += lib/axis/rtl/axis_async_fifo.v +SYN_FILES += lib/axis/rtl/axis_async_fifo_adapter.v +SYN_FILES += lib/axis/rtl/axis_demux.v +SYN_FILES += lib/axis/rtl/axis_fifo.v +SYN_FILES += lib/axis/rtl/axis_fifo_adapter.v +SYN_FILES += lib/axis/rtl/axis_pipeline_fifo.v +SYN_FILES += lib/axis/rtl/axis_register.v +SYN_FILES += lib/axis/rtl/sync_reset.v +SYN_FILES += lib/pcie/rtl/irq_rate_limit.v +SYN_FILES += lib/pcie/rtl/dma_if_axi.v +SYN_FILES += lib/pcie/rtl/dma_if_axi_rd.v +SYN_FILES += lib/pcie/rtl/dma_if_axi_wr.v +SYN_FILES += lib/pcie/rtl/dma_if_mux.v +SYN_FILES += lib/pcie/rtl/dma_if_mux_rd.v +SYN_FILES += lib/pcie/rtl/dma_if_mux_wr.v +SYN_FILES += lib/pcie/rtl/dma_if_desc_mux.v +SYN_FILES += lib/pcie/rtl/dma_ram_demux_rd.v +SYN_FILES += lib/pcie/rtl/dma_ram_demux_wr.v +SYN_FILES += lib/pcie/rtl/dma_psdpram.v +SYN_FILES += lib/pcie/rtl/dma_client_axis_sink.v +SYN_FILES += lib/pcie/rtl/dma_client_axis_source.v + +# XDC files +XDC_FILES = fpga.xdc +XDC_FILES += lib/axi/syn/vivado/axi_vfifo_raw.tcl +XDC_FILES += lib/axi/syn/vivado/axi_vfifo_raw_wr.tcl +XDC_FILES += lib/axi/syn/vivado/axi_vfifo_raw_rd.tcl +XDC_FILES += lib/axis/syn/vivado/axis_async_fifo.tcl +XDC_FILES += lib/axis/syn/vivado/sync_reset.tcl +XDC_FILES += lib/eth/syn/vivado/ptp_clock_cdc.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_port.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_ptp_clock.tcl +XDC_FILES += ../../../common/syn/vivado/mqnic_rb_clk_info.tcl +XDC_FILES += ../../../common/syn/vivado/rb_drp.tcl +XDC_FILES += ../../../common/syn/vivado/eth_xcvr_phy_10g_gty_wrapper.tcl +XDC_FILES += ../../../common/syn/vivado/tdma_ber_ch.tcl +XDC_FILES += app/dma_bench/syn/vivado/dram_test_ch.tcl + +# IP +IP_TCL_FILES = ip/zynq_ps.tcl +IP_TCL_FILES += ip/eth_xcvr_gth.tcl + +# Configuration +CONFIG_TCL_FILES = ./config.tcl + +include ../common/vivado.mk + +program: $(FPGA_TOP).bit + echo "open_hw" > program.tcl + echo "connect_hw_server" >> program.tcl + echo "open_hw_target" >> program.tcl + echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl + echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl + echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl + echo "program_hw_devices [current_hw_device]" >> program.tcl + echo "exit" >> program.tcl + vivado -nojournal -nolog -mode batch -source program.tcl + +APP_DIR = app + +$(APP_DIR)/shell.json: + @mkdir -p $(@D) + echo '{"shell_type": "XRT_FLAT", "num_slots": "1"}' > $@ + +$(APP_DIR)/$(FPGA_TOP).bin: $(FPGA_TOP).bin + @mkdir -p $(@D) + cp $< $@ + +$(APP_DIR)/overlay.dtbo: ../ps/overlay.dtsi + @mkdir -p $(@D) + dtc -@ -O dtb -o $@ $^ + +.PHONY: app +app: $(APP_DIR)/$(FPGA_TOP).bin $(APP_DIR)/shell.json $(APP_DIR)/overlay.dtbo + +clean:: + -rm -rf $(APP_DIR) diff --git a/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/config.tcl b/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/config.tcl new file mode 100644 index 000000000..404c00d65 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/fpga_app_dma_bench/config.tcl @@ -0,0 +1,203 @@ +# Copyright 2021, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +set params [dict create] + +# collect build information +set build_date [clock seconds] +set git_hash 00000000 +set git_tag "" + +if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } { + puts "Error running git or project not under version control" +} + +if { [catch {set git_tag [exec git describe --tags HEAD]}] } { + puts "Error running git, project not under version control, or no tag found" +} + +puts "Build date: ${build_date}" +puts "Git hash: ${git_hash}" +puts "Git tag: ${git_tag}" + +if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } { + puts "Failed to extract version from git tag" + set tag_ver 0.0.1 +} + +puts "Tag version: ${tag_ver}" + +# FW and board IDs +set fpga_id [expr 0x4A49093] +set fw_id [expr 0x00000000] +set fw_ver $tag_ver +set board_vendor_id [expr 0x10ee] +set board_device_id [expr 0x9104] +set board_ver 1.0 +set release_info [expr 0x00000000] + +# FW ID block +dict set params FPGA_ID [format "32'h%08x" $fpga_id] +dict set params FW_ID [format "32'h%08x" $fw_id] +dict set params FW_VER [format "32'h%02x%02x%02x%02x" {*}[split $fw_ver .-] 0 0 0 0] +dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id] +dict set params BOARD_VER [format "32'h%02x%02x%02x%02x" {*}[split $board_ver .-] 0 0 0 0] +dict set params BUILD_DATE "32'd${build_date}" +dict set params GIT_HASH "32'h${git_hash}" +dict set params RELEASE_INFO [format "32'h%08x" $release_info] + +# Board configuration +dict set params TDMA_BER_ENABLE "0" + +# Structural configuration +dict set params IF_COUNT "1" +dict set params PORTS_PER_IF "1" +dict set params SCHED_PER_IF [dict get $params PORTS_PER_IF] +dict set params PORT_MASK "0" + +# Clock configuration +dict set params CLK_PERIOD_NS_NUM "4" +dict set params CLK_PERIOD_NS_DENOM "1" + +# PTP configuration +dict set params PTP_CLOCK_PIPELINE "0" +dict set params PTP_CLOCK_CDC_PIPELINE "0" +dict set params PTP_PORT_CDC_PIPELINE "0" +dict set params PTP_PEROUT_ENABLE "1" +dict set params PTP_PEROUT_COUNT "1" + +# Queue manager configuration +dict set params EVENT_QUEUE_OP_TABLE_SIZE "32" +dict set params TX_QUEUE_OP_TABLE_SIZE "32" +dict set params RX_QUEUE_OP_TABLE_SIZE "32" +dict set params TX_CPL_QUEUE_OP_TABLE_SIZE [dict get $params TX_QUEUE_OP_TABLE_SIZE] +dict set params RX_CPL_QUEUE_OP_TABLE_SIZE [dict get $params RX_QUEUE_OP_TABLE_SIZE] +dict set params EVENT_QUEUE_INDEX_WIDTH "2" +dict set params TX_QUEUE_INDEX_WIDTH "5" +dict set params RX_QUEUE_INDEX_WIDTH "5" +dict set params TX_CPL_QUEUE_INDEX_WIDTH [dict get $params TX_QUEUE_INDEX_WIDTH] +dict set params RX_CPL_QUEUE_INDEX_WIDTH [dict get $params RX_QUEUE_INDEX_WIDTH] +dict set params EVENT_QUEUE_PIPELINE "3" +dict set params TX_QUEUE_PIPELINE [expr 3+([dict get $params TX_QUEUE_INDEX_WIDTH] > 12 ? [dict get $params TX_QUEUE_INDEX_WIDTH]-12 : 0)] +dict set params RX_QUEUE_PIPELINE [expr 3+([dict get $params RX_QUEUE_INDEX_WIDTH] > 12 ? [dict get $params RX_QUEUE_INDEX_WIDTH]-12 : 0)] +dict set params TX_CPL_QUEUE_PIPELINE [dict get $params TX_QUEUE_PIPELINE] +dict set params RX_CPL_QUEUE_PIPELINE [dict get $params RX_QUEUE_PIPELINE] + +# TX and RX engine configuration +dict set params TX_DESC_TABLE_SIZE "32" +dict set params RX_DESC_TABLE_SIZE "32" +dict set params RX_INDIR_TBL_ADDR_WIDTH [expr min([dict get $params RX_QUEUE_INDEX_WIDTH], 8)] + +# Scheduler configuration +dict set params TX_SCHEDULER_OP_TABLE_SIZE [dict get $params TX_DESC_TABLE_SIZE] +dict set params TX_SCHEDULER_PIPELINE [dict get $params TX_QUEUE_PIPELINE] +dict set params TDMA_INDEX_WIDTH "6" + +# Interface configuration +dict set params PTP_TS_ENABLE "1" +dict set params TX_CPL_FIFO_DEPTH "32" +dict set params TX_CHECKSUM_ENABLE "1" +dict set params RX_HASH_ENABLE "1" +dict set params RX_CHECKSUM_ENABLE "1" +dict set params TX_FIFO_DEPTH "32768" +dict set params RX_FIFO_DEPTH "32768" +dict set params MAX_TX_SIZE "9214" +dict set params MAX_RX_SIZE "9214" +dict set params TX_RAM_SIZE "32768" +dict set params RX_RAM_SIZE "32768" + +# Application block configuration +dict set params APP_ID "32'h12348001" +dict set params APP_ENABLE "1" +dict set params APP_CTRL_ENABLE "1" +dict set params APP_DMA_ENABLE "1" +dict set params APP_AXIS_DIRECT_ENABLE "1" +dict set params APP_AXIS_SYNC_ENABLE "1" +dict set params APP_AXIS_IF_ENABLE "1" +dict set params APP_STAT_ENABLE "1" + +# AXI DMA interface configuration +open_bd_design [get_files zynq_ps.bd] +set s_axi_dma [get_bd_intf_ports s_axi_dma] +dict set params AXI_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $s_axi_dma] +# dict set params AXI_ADDR_WIDTH [get_property CONFIG.ADDR_WIDTH $s_axi_dma] +dict set params AXI_ADDR_WIDTH 64 +dict set params AXI_ID_WIDTH [get_property CONFIG.ID_WIDTH $s_axi_dma] + +# DMA interface configuration +dict set params DMA_IMM_ENABLE "0" +dict set params DMA_IMM_WIDTH "32" +dict set params DMA_LEN_WIDTH "16" +dict set params DMA_TAG_WIDTH "16" +dict set params RAM_ADDR_WIDTH [expr int(ceil(log(max([dict get $params TX_RAM_SIZE], [dict get $params RX_RAM_SIZE]))/log(2)))] +dict set params RAM_PIPELINE "2" +# NOTE: Querying the BD top-level interface port (or even the ZynqMP's interface +# pin) yields 256 for the maximum burst length, instead of 16, which is +# the actually supported length (due to ZynqMP using AXI3 internally). +#dict set params AXI_DMA_MAX_BURST_LEN [get_property CONFIG.MAX_BURST_LENGTH $s_axi_dma] +dict set params AXI_DMA_MAX_BURST_LEN "16" + +# AXI lite interface configuration (control) +set m_axil_ctrl [get_bd_intf_ports m_axil_ctrl] +dict set params AXIL_CTRL_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $m_axil_ctrl] +dict set params AXIL_CTRL_ADDR_WIDTH 24 + +# AXI lite interface configuration (application control) +set m_axil_app_ctrl [get_bd_intf_ports m_axil_app_ctrl] +dict set params AXIL_APP_CTRL_DATA_WIDTH [get_property CONFIG.DATA_WIDTH $m_axil_app_ctrl] +dict set params AXIL_APP_CTRL_ADDR_WIDTH 24 + +# Interrupt configuration +set irq [get_bd_ports pl_ps_irq0] +dict set params IRQ_COUNT [get_property CONFIG.PortWidth $irq] +close_bd_design [get_bd_designs zynq_ps] +dict set params IRQ_STRETCH "10" + +# Ethernet interface configuration +dict set params AXIS_ETH_TX_PIPELINE "0" +dict set params AXIS_ETH_TX_FIFO_PIPELINE "2" +dict set params AXIS_ETH_TX_TS_PIPELINE "0" +dict set params AXIS_ETH_RX_PIPELINE "0" +dict set params AXIS_ETH_RX_FIFO_PIPELINE "2" + +# Statistics counter subsystem +dict set params STAT_ENABLE "1" +dict set params STAT_DMA_ENABLE "1" +dict set params STAT_AXI_ENABLE "1" +dict set params STAT_INC_WIDTH "24" +dict set params STAT_ID_WIDTH "12" + +# apply parameters to top-level +set param_list {} +dict for {name value} $params { + lappend param_list $name=$value +} + +# set_property generic $param_list [current_fileset] +set_property generic $param_list [get_filesets sources_1] diff --git a/fpga/mqnic/KR260/fpga/ip/eth_xcvr_gth.tcl b/fpga/mqnic/KR260/fpga/ip/eth_xcvr_gth.tcl new file mode 100644 index 000000000..3209d5d72 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/ip/eth_xcvr_gth.tcl @@ -0,0 +1,129 @@ +# Copyright 2022, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +set base_name {eth_xcvr_gth} + +set preset {GTH-10GBASE-R} + +set freerun_freq {125} +set line_rate {10.3125} +set sec_line_rate {0} +set refclk_freq {156.25} +set qpll_fracn [expr {int(fmod($line_rate*1000/2 / $refclk_freq, 1)*pow(2, 24))}] +set sec_qpll_fracn [expr {int(fmod($sec_line_rate*1000/2 / $refclk_freq, 1)*pow(2, 24))}] +set user_data_width {64} +set int_data_width {32} +set rx_eq_mode {DFE} +set extra_ports [list] +set extra_pll_ports [list] +# DRP connections +lappend extra_ports drpclk_in drpaddr_in drpdi_in drpen_in drpwe_in drpdo_out drprdy_out +lappend extra_pll_ports drpclk_common_in drpaddr_common_in drpdi_common_in drpen_common_in drpwe_common_in drpdo_common_out drprdy_common_out +# PLL reset and power down +lappend extra_pll_ports qpll0reset_in qpll1reset_in +lappend extra_pll_ports qpll0pd_in qpll1pd_in +# PLL clocking +lappend extra_pll_ports gtrefclk00_in qpll0lock_out qpll0outclk_out qpll0outrefclk_out +lappend extra_pll_ports gtrefclk01_in qpll1lock_out qpll1outclk_out qpll1outrefclk_out +# channel reset +lappend extra_ports gttxreset_in txuserrdy_in txpmareset_in txpcsreset_in txresetdone_out txpmaresetdone_out +lappend extra_ports gtrxreset_in rxuserrdy_in rxpmareset_in rxdfelpmreset_in eyescanreset_in rxpcsreset_in rxresetdone_out rxpmaresetdone_out +# channel power down +lappend extra_ports txpd_in txpdelecidlemode_in rxpd_in +# channel clock selection +lappend extra_ports txsysclksel_in txpllclksel_in rxsysclksel_in rxpllclksel_in +# channel polarity +lappend extra_ports txpolarity_in rxpolarity_in +# channel TX driver +lappend extra_ports txelecidle_in txinhibit_in txdiffctrl_in txmaincursor_in txprecursor_in txpostcursor_in +# channel CDR +lappend extra_ports rxcdrlock_out rxcdrhold_in +# channel EQ +lappend extra_ports rxlpmen_in +# channel digital monitor +lappend extra_ports dmonitorout_out +# channel PRBS +lappend extra_ports txprbsforceerr_in txprbssel_in rxprbscntreset_in rxprbssel_in rxprbserr_out rxprbslocked_out +# channel eye scan +lappend extra_ports eyescandataerror_out +# channel loopback +lappend extra_ports loopback_in + +set config [dict create] + +dict set config TX_LINE_RATE $line_rate +dict set config TX_REFCLK_FREQUENCY $refclk_freq +dict set config TX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config TX_USER_DATA_WIDTH $user_data_width +dict set config TX_INT_DATA_WIDTH $int_data_width +dict set config RX_LINE_RATE $line_rate +dict set config RX_REFCLK_FREQUENCY $refclk_freq +dict set config RX_QPLL_FRACN_NUMERATOR $qpll_fracn +dict set config RX_USER_DATA_WIDTH $user_data_width +dict set config RX_INT_DATA_WIDTH $int_data_width +dict set config RX_EQ_MODE $rx_eq_mode +if {$sec_line_rate != 0} { + dict set config SECONDARY_QPLL_ENABLE true + dict set config SECONDARY_QPLL_FRACN_NUMERATOR $sec_qpll_fracn + dict set config SECONDARY_QPLL_LINE_RATE $sec_line_rate + dict set config SECONDARY_QPLL_REFCLK_FREQUENCY $refclk_freq +} else { + dict set config SECONDARY_QPLL_ENABLE false +} +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {CORE} +dict set config LOCATE_RESET_CONTROLLER {EXAMPLE_DESIGN} +dict set config LOCATE_TX_USER_CLOCKING {CORE} +dict set config LOCATE_RX_USER_CLOCKING {CORE} +dict set config LOCATE_USER_DATA_WIDTH_SIZING {CORE} +dict set config FREERUN_FREQUENCY $freerun_freq +dict set config DISABLE_LOC_XDC {1} + +proc create_gtwizard_ip {name preset config} { + create_ip -name gtwizard_ultrascale -vendor xilinx.com -library ip -module_name $name + set ip [get_ips $name] + set_property CONFIG.preset $preset $ip + set config_list {} + dict for {name value} $config { + lappend config_list "CONFIG.${name}" $value + } + set_property -dict $config_list $ip +} + +# variant with channel and common +dict set config ENABLE_OPTIONAL_PORTS [concat $extra_pll_ports $extra_ports] +dict set config LOCATE_COMMON {CORE} + +create_gtwizard_ip "${base_name}_full" $preset $config + +# variant with channel only +dict set config ENABLE_OPTIONAL_PORTS $extra_ports +dict set config LOCATE_COMMON {EXAMPLE_DESIGN} + +create_gtwizard_ip "${base_name}_channel" $preset $config diff --git a/fpga/mqnic/KR260/fpga/ip/zynq_ps.tcl b/fpga/mqnic/KR260/fpga/ip/zynq_ps.tcl new file mode 100644 index 000000000..9049c33bc --- /dev/null +++ b/fpga/mqnic/KR260/fpga/ip/zynq_ps.tcl @@ -0,0 +1,356 @@ +# Copyright 2022, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +# create block design +create_bd_design "zynq_ps" + +# Create blocks + +# Zynq PS +set zynq_ultra_ps [ create_bd_cell -type ip -vlnv xilinx.com:ip:zynq_ultra_ps_e zynq_ultra_ps ] +set_property -dict [list \ + CONFIG.PSU__PRESET_APPLIED {1} \ + CONFIG.PSU_BANK_0_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_1_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_2_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU_BANK_3_IO_STANDARD {LVCMOS18} \ + CONFIG.PSU__GPIO0_MIO__IO {MIO 0 .. 25} \ + CONFIG.PSU__GPIO0_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__GPIO1_MIO__IO {MIO 26 .. 51} \ + CONFIG.PSU__GPIO1_MIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__QSPI__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__QSPI__PERIPHERAL__DATA_MODE {x4} \ + CONFIG.PSU__QSPI__PERIPHERAL__IO {MIO 0 .. 5} \ + CONFIG.PSU__QSPI__PERIPHERAL__MODE {Single} \ + CONFIG.PSU__QSPI__GRP_FBCLK__ENABLE {0} \ + CONFIG.PSU__CRL_APB__QSPI_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__QSPI_REF_CTRL__FREQMHZ {125} \ + CONFIG.PSU__SPI1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SPI1__GRP_SS1__ENABLE {0} \ + CONFIG.PSU__CRL_APB__SPI1_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__SPI1_REF_CTRL__FREQMHZ {200} \ + CONFIG.PSU__DISPLAYPORT__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__IO {MIO 27 .. 30} \ + CONFIG.PSU__DP__LANE_SEL {None} \ + CONFIG.PSU__DP__REF_CLK_SEL {Ref Clk1} \ + CONFIG.PSU__DP__REF_CLK_FREQ {27} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__SRCSEL {VPLL} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__FREQMHZ {300} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__FREQMHZ {25} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__FREQMHZ {27} \ + CONFIG.PSU__USE__IRQ0 {1} \ + CONFIG.PSU__USE__M_AXI_GP0 {1} \ + CONFIG.PSU__USE__M_AXI_GP1 {1} \ + CONFIG.PSU__USE__M_AXI_GP2 {0} \ + CONFIG.PSU__PMU__GPO0__ENABLE {0} \ + CONFIG.PSU__PMU__GPO1__ENABLE {0} \ + CONFIG.PSU__PMU__GPO2__ENABLE {0} \ + CONFIG.PSU__PMU__GPO3__ENABLE {1} \ + CONFIG.PSU__PMU__GPO4__ENABLE {0} \ + CONFIG.PSU__PMU__GPO5__ENABLE {0} \ + CONFIG.PSU__PMU__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__PMU__GPI0__ENABLE {1} \ + CONFIG.PSU__PMU__GPI1__ENABLE {0} \ + CONFIG.PSU__PMU__GPI2__ENABLE {0} \ + CONFIG.PSU__PMU__GPI3__ENABLE {0} \ + CONFIG.PSU__PMU__GPI4__ENABLE {0} \ + CONFIG.PSU__PMU__GPI5__ENABLE {1} \ + CONFIG.PSU_MIO_34_DIRECTION {inout} \ + CONFIG.PSU_MIO_43_DIRECTION {inout} \ + CONFIG.PSU_MIO_44_DIRECTION {inout} \ + CONFIG.PSU__DDRC__VREF {1} \ + CONFIG.PSU__DDRC__ECC {Disabled} \ + CONFIG.PSU__DDRC__BUS_WIDTH {64 Bit} \ + CONFIG.PSU__DDRC__DRAM_WIDTH {16 Bits} \ + CONFIG.PSU__DDRC__MEMORY_TYPE {DDR 4} \ + CONFIG.PSU__DDRC__COMPONENTS {Components} \ + CONFIG.PSU__DDRC__SPEED_BIN {DDR4_2400R} \ + CONFIG.PSU__DDRC__DEVICE_CAPACITY {8192 MBits} \ + CONFIG.PSU__DDRC__RANK_ADDR_COUNT {0} \ + CONFIG.PSU__DDRC__BG_ADDR_COUNT {1} \ + CONFIG.PSU__DDRC__BANK_ADDR_COUNT {2} \ + CONFIG.PSU__DDRC__ROW_ADDR_COUNT {16} \ + CONFIG.PSU__DDRC__COL_ADDR_COUNT {10} \ + CONFIG.PSU__DDRC__CL {16} \ + CONFIG.PSU__DDRC__CWL {14} \ + CONFIG.PSU__DDRC__T_RCD {16} \ + CONFIG.PSU__DDRC__T_RP {16} \ + CONFIG.PSU__DDRC__T_RC {47.06} \ + CONFIG.PSU__DDRC__T_RAS_MIN {33} \ + CONFIG.PSU__DDRC__T_FAW {30.0} \ + CONFIG.PSU__DDRC__DDR4_T_REF_MODE {0} \ + CONFIG.PSU__DDRC__DDR4_T_REF_RANGE {Normal (0-85)} \ + CONFIG.PSU__DDRC__PHY_DBI_MODE {0} \ + CONFIG.PSU__DDRC__PARITY_ENABLE {0} \ + CONFIG.PSU__DDRC__CLOCK_STOP_EN {0} \ + CONFIG.PSU__DDRC__DDR4_CAL_MODE_ENABLE {0} \ + CONFIG.PSU__DDRC__DDR4_CRC_CONTROL {0} \ + CONFIG.PSU__DDRC__TRAIN_DATA_EYE {1} \ + CONFIG.PSU__DDRC__TRAIN_READ_GATE {1} \ + CONFIG.PSU__DDRC__TRAIN_WRITE_LEVEL {1} \ + CONFIG.PSU__DDRC__DDR4_ADDR_MAPPING {0} \ + CONFIG.PSU__DDRC__BRC_MAPPING {ROW_BANK_COL} \ + CONFIG.PSU__DDRC__DM_DBI {DM_NO_DBI} \ + CONFIG.PSU__DDRC__PER_BANK_REFRESH {0} \ + CONFIG.PSU__DDRC__FGRM {1X} \ + CONFIG.PSU__DDRC__LP_ASR {manual normal} \ + CONFIG.PSU__DDRC__DIMM_ADDR_MIRROR {0} \ + CONFIG.PSU__DDRC__STATIC_RD_MODE {0} \ + CONFIG.PSU__DDRC__SELF_REF_ABORT {0} \ + CONFIG.PSU__PSS_REF_CLK__FREQMHZ {33.333} \ + CONFIG.PSU__OVERRIDE__BASIC_CLOCK {0} \ + CONFIG.PSU__CRF_APB__APLL_CTRL__SRCSEL {PSS_REF_CLK} \ + CONFIG.PSU__CRF_APB__DPLL_CTRL__SRCSEL {PSS_REF_CLK} \ + CONFIG.PSU__CRF_APB__VPLL_CTRL__SRCSEL {PSS_REF_CLK} \ + CONFIG.PSU__CRL_APB__IOPLL_CTRL__SRCSEL {PSS_REF_CLK} \ + CONFIG.PSU__CRL_APB__RPLL_CTRL__SRCSEL {PSS_REF_CLK} \ + CONFIG.PSU__CRF_APB__DDR_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__DDR_CTRL__FREQMHZ {1200} \ + CONFIG.PSU__CRL_APB__CPU_R5_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRL_APB__CPU_R5_CTRL__FREQMHZ {533.333} \ + CONFIG.PSU__CRF_APB__ACPU_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__ACPU__FRAC_ENABLED {1} \ + CONFIG.PSU__CRF_APB__ACPU_CTRL__FREQMHZ {1333.333} \ + CONFIG.PSU__CRF_APB__GPU_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRF_APB__GPU_REF_CTRL__FREQMHZ {600} \ + CONFIG.PSU__SWDT0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__SWDT1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__TTC0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__IOU_SLCR__IOU_TTC_APB_CLK__TTC0_SEL {APB} \ + CONFIG.PSU__TTC1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__IOU_SLCR__IOU_TTC_APB_CLK__TTC1_SEL {APB} \ + CONFIG.PSU__TTC2__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__IOU_SLCR__IOU_TTC_APB_CLK__TTC2_SEL {APB} \ + CONFIG.PSU__TTC3__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__IOU_SLCR__IOU_TTC_APB_CLK__TTC3_SEL {APB} \ + CONFIG.PSU__CRL_APB__DBG_LPD_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__DBG_LPD_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRF_APB__DBG_FPD_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRF_APB__DBG_FPD_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRF_APB__DBG_TRACE_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRF_APB__DBG_TRACE_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRF_APB__DBG_TSTMP_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRF_APB__DBG_TSTMP_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRL_APB__IOU_SWITCH_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__IOU_SWITCH_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRL_APB__LPD_SWITCH_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__LPD_SWITCH_CTRL__FREQMHZ {500} \ + CONFIG.PSU__CRL_APB__LPD_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__LPD_LSBUS_CTRL__FREQMHZ {100} \ + CONFIG.PSU__CRL_APB__TIMESTAMP_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__TIMESTAMP_REF_CTRL__FREQMHZ {100} \ + CONFIG.PSU__CRL_APB__PCAP_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__PCAP_CTRL__FREQMHZ {200} \ + CONFIG.PSU__CRL_APB__ADMA_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__ADMA_REF_CTRL__FREQMHZ {500} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__SRCSEL {APLL} \ + CONFIG.PSU__CRF_APB__DPDMA_REF_CTRL__FREQMHZ {600} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__GDMA_REF_CTRL__FREQMHZ {600} \ + CONFIG.PSU__CRF_APB__TOPSW_MAIN_CTRL__SRCSEL {DPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_MAIN_CTRL__FREQMHZ {533.33} \ + CONFIG.PSU__CRF_APB__TOPSW_LSBUS_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRF_APB__TOPSW_LSBUS_CTRL__FREQMHZ {100} \ + CONFIG.PSU__I2C1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__I2C1__PERIPHERAL__IO {MIO 24 .. 25} \ + CONFIG.PSU__CRL_APB__I2C1_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__I2C1_REF_CTRL__FREQMHZ {100} \ + CONFIG.PSU__UART1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__UART1__PERIPHERAL__IO {MIO 36 .. 37} \ + CONFIG.PSU__CRL_APB__UART1_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__UART1_REF_CTRL__FREQMHZ {100} \ + CONFIG.PSU__ENET1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__ENET1__PERIPHERAL__IO {MIO 38 .. 49} \ + CONFIG.PSU__ENET1__GRP_MDIO__ENABLE {1} \ + CONFIG.PSU__ENET1__GRP_MDIO__IO {MIO 50 .. 51} \ + CONFIG.PSU__CRL_APB__GEM1_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__GEM1_REF_CTRL__FREQMHZ {125} \ + CONFIG.PSU__CRL_APB__GEM_TSU_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__GEM_TSU_REF_CTRL__FREQMHZ {250} \ + CONFIG.PSU_MIO_45_PULLUPDOWN {disable} \ + CONFIG.PSU_MIO_47_PULLUPDOWN {disable} \ + CONFIG.PSU_MIO_49_PULLUPDOWN {disable} \ + CONFIG.PSU__ENET0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__ENET0__PERIPHERAL__IO {GT Lane0} \ + CONFIG.PSU__GEM0__REF_CLK_SEL {Ref Clk0} \ + CONFIG.PSU__GEM0__REF_CLK_FREQ {125} \ + CONFIG.PSU__CRL_APB__GEM0_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__GEM0_REF_CTRL__FREQMHZ {125} \ + CONFIG.PSU__DISPLAYPORT__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__DPAUX__PERIPHERAL__IO {MIO 27 .. 30} \ + CONFIG.PSU__DP__LANE_SEL {Single Lower} \ + CONFIG.PSU__DISPLAYPORT__LANE0__ENABLE {1} \ + CONFIG.PSU__DISPLAYPORT__LANE0__IO {GT Lane1} \ + CONFIG.PSU__DP__REF_CLK_SEL {Ref Clk1} \ + CONFIG.PSU__DP__REF_CLK_FREQ {27} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__SRCSEL {VPLL} \ + CONFIG.PSU__CRF_APB__DP_VIDEO_REF_CTRL__FREQMHZ {300} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_AUDIO_REF_CTRL__FREQMHZ {25} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__SRCSEL {RPLL} \ + CONFIG.PSU__CRF_APB__DP_STC_REF_CTRL__FREQMHZ {27} \ + CONFIG.PSU__USB0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB0__PERIPHERAL__IO {MIO 52 .. 63} \ + CONFIG.PSU__CRL_APB__USB0_BUS_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__USB0_BUS_REF_CTRL__FREQMHZ {250} \ + CONFIG.PSU__USB3_0__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB3_0__PERIPHERAL__IO {GT Lane2} \ + CONFIG.PSU__USB0__REF_CLK_SEL {Ref Clk2} \ + CONFIG.PSU__USB0__REF_CLK_FREQ {26} \ + CONFIG.PSU__USB1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB1__PERIPHERAL__IO {MIO 64 .. 75} \ + CONFIG.PSU__CRL_APB__USB1_BUS_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__USB1_BUS_REF_CTRL__FREQMHZ {250} \ + CONFIG.PSU__USB1__RESET__ENABLE {1} \ + CONFIG.PSU__USB1__RESET__IO {MIO 77} \ + CONFIG.PSU__USB3_1__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__USB3_1__PERIPHERAL__IO {GT Lane3} \ + CONFIG.PSU__USB1__REF_CLK_SEL {Ref Clk2} \ + CONFIG.PSU__USB1__REF_CLK_FREQ {26} \ + CONFIG.PSU__USB__RESET__MODE {Separate MIO Pin} \ + CONFIG.PSU__USB0__RESET__ENABLE {1} \ + CONFIG.PSU__USB0__RESET__IO {MIO 76} \ + CONFIG.PSU__CRL_APB__USB3_DUAL_REF_CTRL__SRCSEL {IOPLL} \ + CONFIG.PSU__CRL_APB__USB3_DUAL_REF_CTRL__FREQMHZ {20} \ + CONFIG.PSU__USE__M_AXI_GP0 {1} \ + CONFIG.PSU__MAXIGP0__DATA_WIDTH {32} \ + CONFIG.PSU__USE__M_AXI_GP1 {0} \ + CONFIG.PSU__USE__M_AXI_GP2 {0} \ + CONFIG.PSU__USE__S_AXI_GP0 {1} \ + CONFIG.PSU__USE__IRQ0 {1} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__FREQMHZ {250} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__SRCSEL {IOPLL} +] $zynq_ultra_ps + +# control AXI interconnect +set axi_interconnect_ctrl [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect axi_interconnect_ctrl ] + +# reset +set proc_sys_reset [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset proc_sys_reset ] + +# Create connections + +# Clock +set pl_clk0 [get_bd_pins $zynq_ultra_ps/pl_clk0] +make_bd_pins_external $pl_clk0 +set_property name pl_clk0 [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] +set pl_clk0_port [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_clk0]] + +connect_bd_net $pl_clk0 [get_bd_pins $zynq_ultra_ps/maxihpm0_fpd_aclk] +connect_bd_net $pl_clk0 [get_bd_pins $zynq_ultra_ps/saxihpc0_fpd_aclk] +connect_bd_net $pl_clk0 [get_bd_pins $proc_sys_reset/slowest_sync_clk] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/S00_ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/M00_ACLK] +connect_bd_net $pl_clk0 [get_bd_pins $axi_interconnect_ctrl/M01_ACLK] + +set pl_clk0_busif [list] + +# Reset +set pl_resetn0 [get_bd_pins $zynq_ultra_ps/pl_resetn0] +connect_bd_net $pl_resetn0 [get_bd_pins $proc_sys_reset/ext_reset_in] + +set pl_reset [get_bd_pins $proc_sys_reset/peripheral_reset] +make_bd_pins_external $pl_reset +set_property name pl_reset [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_reset]] + +set interconnect_aresetn [get_bd_pins $proc_sys_reset/interconnect_aresetn] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/S00_ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/M00_ARESETN] +connect_bd_net $interconnect_aresetn [get_bd_pins $axi_interconnect_ctrl/M01_ARESETN] + +# MMIO +connect_bd_intf_net [get_bd_intf_pins $zynq_ultra_ps/M_AXI_HPM0_FPD] [get_bd_intf_pins $axi_interconnect_ctrl/S00_AXI] + +# Control interface +set m_axil_ctrl_pin [get_bd_intf_pins $axi_interconnect_ctrl/M00_AXI] +make_bd_intf_pins_external $m_axil_ctrl_pin +set_property name m_axil_ctrl [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_ctrl_pin]] +set m_axil_ctrl_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_ctrl_pin]] +set_property -dict [list \ + CONFIG.PROTOCOL AXI4LITE \ + CONFIG.DATA_WIDTH 32 \ + CONFIG.ADDR_WIDTH 24 \ +] $m_axil_ctrl_port +lappend pl_clk0_busif $m_axil_ctrl_port + +# Application control interface +set m_axil_app_ctrl_pin [get_bd_intf_pins $axi_interconnect_ctrl/M01_AXI] +make_bd_intf_pins_external $m_axil_app_ctrl_pin +set_property name m_axil_app_ctrl [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_app_ctrl_pin]] +set m_axil_app_ctrl_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $m_axil_app_ctrl_pin]] +set_property -dict [list \ + CONFIG.PROTOCOL AXI4LITE \ + CONFIG.DATA_WIDTH 32 \ + CONFIG.ADDR_WIDTH 24 \ +] $m_axil_app_ctrl_port +lappend pl_clk0_busif $m_axil_app_ctrl_port + +# DMA interface +set s_axi_dma_pin [get_bd_intf_pins $zynq_ultra_ps/S_AXI_HPC0_FPD] +make_bd_intf_pins_external $s_axi_dma_pin +set_property name s_axi_dma [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $s_axi_dma_pin]] +set s_axi_dma_port [get_bd_intf_ports -of_objects [get_bd_intf_nets -of_objects $s_axi_dma_pin]] +lappend pl_clk0_busif $s_axi_dma_port + +# IRQ +set pl_ps_irq0 [get_bd_pins $zynq_ultra_ps/pl_ps_irq0] +make_bd_pins_external $pl_ps_irq0 +set_property name pl_ps_irq0 [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_ps_irq0]] +set pl_ps_irq0_port [get_bd_ports -of_objects [get_bd_nets -of_objects $pl_ps_irq0]] +set_property -dict [list \ + CONFIG.PortWidth 8 \ +] $pl_ps_irq0_port + +# Port clock associations +set lst [list] +foreach port $pl_clk0_busif { + lappend lst [get_property name $port] +} +set_property CONFIG.ASSOCIATED_BUSIF [join $lst ":"] $pl_clk0_port + +# Assign addresses +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_DDR_HIGH] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_QSPI] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_DDR_LOW] -force +assign_bd_address -target_address_space /s_axi_dma [get_bd_addr_segs $zynq_ultra_ps/SAXIGP0/HPC0_LPS_OCM] -force + +assign_bd_address -offset 0xA000_0000 -range 16M -target_address_space $zynq_ultra_ps/Data [get_bd_addr_segs $m_axil_ctrl_port/Reg] -force +assign_bd_address -offset 0xA800_0000 -range 16M -target_address_space $zynq_ultra_ps/Data [get_bd_addr_segs $m_axil_app_ctrl_port/Reg] -force + +validate_bd_design + +# Save block design +save_bd_design [current_bd_design] +close_bd_design [current_bd_design] diff --git a/fpga/mqnic/KR260/fpga/lib b/fpga/mqnic/KR260/fpga/lib new file mode 120000 index 000000000..9512b3d5e --- /dev/null +++ b/fpga/mqnic/KR260/fpga/lib @@ -0,0 +1 @@ +../../../lib/ \ No newline at end of file diff --git a/fpga/mqnic/KR260/fpga/ps/overlay.dtsi b/fpga/mqnic/KR260/fpga/ps/overlay.dtsi new file mode 100644 index 000000000..adc326fd0 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/ps/overlay.dtsi @@ -0,0 +1,58 @@ +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target = <&fpga_full>; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + firmware-name = "fpga.bin"; + }; + }; + fragment@1 { + target = <&amba>; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + afi0: afi0 { + compatible = "xlnx,afi-fpga"; + config-afi = + // PL-to-PS AXI + // 0: 128-bit, 1: 64-bit, 2: 32-bit + <0 0>, // AFIFM0_RDCTRL [1:0] S_AXI_HPC0_FPD + <1 0>, // AFIFM0_WRCTRL [1:0] S_AXI_HPC0_FPD + <2 0>, // AFIFM1_RDCTRL [1:0] S_AXI_HPC1_FPD + <3 0>, // AFIFM1_WRCTRL [1:0] S_AXI_HPC1_FPD + <4 0>, // AFIFM2_RDCTRL [1:0] S_AXI_HP0_FPD + <5 0>, // AFIFM2_WRCTRL [1:0] S_AXI_HP0_FPD + <6 0>, // AFIFM3_RDCTRL [1:0] S_AXI_HP1_FPD + <7 0>, // AFIFM3_WRCTRL [1:0] S_AXI_HP1_FPD + <8 0>, // AFIFM4_RDCTRL [1:0] S_AXI_HP2_FPD + <9 0>, // AFIFM4_WRCTRL [1:0] S_AXI_HP2_FPD + <10 0>, // AFIFM5_RDCTRL [1:0] S_AXI_HP3_FPD + <11 0>, // AFIFM5_WRCTRL [1:0] S_AXI_HP3_FPD + <12 0>, // AFIFM6_RDCTRL [1:0] S_AXI_LPD + <13 0>, // AFIFM6_WRCTRL [1:0] S_AXI_LPD + // PS-to-PL AXI + // 0: 32-bit, 1: 64-bit, 2: 128-bit + <14 0x000>, // FPD_SLCR [9:8] AFIFS0 M_AXI_HPM0_FPD [11:10] AFIFS1 M_AXI_HPM1_FPD + <15 0x000>; // LPD_SLCR [9:8] AFIFS2 M_AXI_HPM0_LPD + }; + + mqnic0: ethernet@a0000000 { + compatible = "corundum,mqnic"; + reg = <0x0 0xa0000000 0x0 0x1000000>, + <0x0 0xa8000000 0x0 0x1000000>; + reg-names = "csr", "app"; + interrupt-parent = <&gic>; + interrupts = <0x0 0x59 0x1>, <0x0 0x5a 0x1>, <0x0 0x5b 0x1>, + <0x0 0x5c 0x1>; + assigned-clocks = <&zynqmp_clk 71>; // PL0_REF + assigned-clock-rates = <250000000>; + resets = <&zynqmp_reset 116>; // ZYNQMP_RESET_PS_PL0 + reset-names = "reset"; + }; + }; + }; +}; diff --git a/fpga/mqnic/KR260/fpga/rtl/common b/fpga/mqnic/KR260/fpga/rtl/common new file mode 120000 index 000000000..449c9409c --- /dev/null +++ b/fpga/mqnic/KR260/fpga/rtl/common @@ -0,0 +1 @@ +../../../../common/rtl/ \ No newline at end of file diff --git a/fpga/mqnic/KR260/fpga/rtl/fpga.v b/fpga/mqnic/KR260/fpga/rtl/fpga.v new file mode 100644 index 000000000..f821a37fb --- /dev/null +++ b/fpga/mqnic/KR260/fpga/rtl/fpga.v @@ -0,0 +1,944 @@ +/* + +Copyright 2023, The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY MISSINGLINKELECTRONICS INC. ''AS +IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL MISSINGLINKELECTRONICS INC. OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of MissingLinkElectronics Inc. + +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA top-level module + */ +module fpga # +( + // FW and board IDs + parameter FPGA_ID = 32'h4A49093, + parameter FW_ID = 32'h00000000, + parameter FW_VER = 32'h00_00_01_00, + parameter BOARD_ID = 32'h10ee_9104, + parameter BOARD_VER = 32'h01_00_00_00, + parameter BUILD_DATE = 32'd602976000, + parameter GIT_HASH = 32'hdce357bf, + parameter RELEASE_INFO = 32'h00000000, + + // Board configuration + parameter TDMA_BER_ENABLE = 0, + + // Structural configuration + parameter IF_COUNT = 1, + parameter PORTS_PER_IF = 1, + parameter SCHED_PER_IF = PORTS_PER_IF, + parameter PORT_MASK = 0, + + // Clock configuration + parameter CLK_PERIOD_NS_NUM = 4, + parameter CLK_PERIOD_NS_DENOM = 1, + + // PTP configuration + parameter PTP_CLOCK_PIPELINE = 0, + parameter PTP_CLOCK_CDC_PIPELINE = 0, + parameter PTP_PORT_CDC_PIPELINE = 0, + parameter PTP_PEROUT_ENABLE = 1, + parameter PTP_PEROUT_COUNT = 1, + + // Queue manager configuration + parameter EVENT_QUEUE_OP_TABLE_SIZE = 32, + parameter TX_QUEUE_OP_TABLE_SIZE = 32, + parameter RX_QUEUE_OP_TABLE_SIZE = 32, + parameter TX_CPL_QUEUE_OP_TABLE_SIZE = TX_QUEUE_OP_TABLE_SIZE, + parameter RX_CPL_QUEUE_OP_TABLE_SIZE = RX_QUEUE_OP_TABLE_SIZE, + parameter EVENT_QUEUE_INDEX_WIDTH = 5, + parameter TX_QUEUE_INDEX_WIDTH = 13, + parameter RX_QUEUE_INDEX_WIDTH = 8, + parameter TX_CPL_QUEUE_INDEX_WIDTH = TX_QUEUE_INDEX_WIDTH, + parameter RX_CPL_QUEUE_INDEX_WIDTH = RX_QUEUE_INDEX_WIDTH, + parameter EVENT_QUEUE_PIPELINE = 3, + parameter TX_QUEUE_PIPELINE = 3+(TX_QUEUE_INDEX_WIDTH > 12 ? TX_QUEUE_INDEX_WIDTH-12 : 0), + parameter RX_QUEUE_PIPELINE = 3+(RX_QUEUE_INDEX_WIDTH > 12 ? RX_QUEUE_INDEX_WIDTH-12 : 0), + parameter TX_CPL_QUEUE_PIPELINE = TX_QUEUE_PIPELINE, + parameter RX_CPL_QUEUE_PIPELINE = RX_QUEUE_PIPELINE, + + // TX and RX engine configuration + parameter TX_DESC_TABLE_SIZE = 32, + parameter RX_DESC_TABLE_SIZE = 32, + parameter RX_INDIR_TBL_ADDR_WIDTH = RX_QUEUE_INDEX_WIDTH > 8 ? 8 : RX_QUEUE_INDEX_WIDTH, + + // Scheduler configuration + parameter TX_SCHEDULER_OP_TABLE_SIZE = TX_DESC_TABLE_SIZE, + parameter TX_SCHEDULER_PIPELINE = TX_QUEUE_PIPELINE, + parameter TDMA_INDEX_WIDTH = 6, + + // Interface configuration + parameter PTP_TS_ENABLE = 1, + parameter TX_CPL_FIFO_DEPTH = 32, + parameter TX_CHECKSUM_ENABLE = 1, + parameter RX_HASH_ENABLE = 1, + parameter RX_CHECKSUM_ENABLE = 1, + parameter TX_FIFO_DEPTH = 32768, + parameter RX_FIFO_DEPTH = 32768, + parameter MAX_TX_SIZE = 9214, + parameter MAX_RX_SIZE = 9214, + parameter TX_RAM_SIZE = 32768, + parameter RX_RAM_SIZE = 32768, + + // Application block configuration + parameter APP_ID = 32'h00000000, + parameter APP_ENABLE = 0, + parameter APP_CTRL_ENABLE = 1, + parameter APP_DMA_ENABLE = 1, + parameter APP_AXIS_DIRECT_ENABLE = 1, + parameter APP_AXIS_SYNC_ENABLE = 1, + parameter APP_AXIS_IF_ENABLE = 1, + parameter APP_STAT_ENABLE = 1, + + // AXI interface configuration (DMA) + parameter AXI_DATA_WIDTH = 128, + parameter AXI_ADDR_WIDTH = 32, + parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8), + parameter AXI_ID_WIDTH = 8, + + // DMA interface configuration + parameter DMA_IMM_ENABLE = 0, + parameter DMA_IMM_WIDTH = 32, + parameter DMA_LEN_WIDTH = 16, + parameter DMA_TAG_WIDTH = 16, + parameter RAM_ADDR_WIDTH = $clog2(TX_RAM_SIZE > RX_RAM_SIZE ? TX_RAM_SIZE : RX_RAM_SIZE), + parameter RAM_PIPELINE = 2, + parameter AXI_DMA_MAX_BURST_LEN = 256, + + // Interrupts + parameter IRQ_COUNT = 32, + parameter IRQ_STRETCH = 10, + + // AXI lite interface configuration (control) + parameter AXIL_CTRL_DATA_WIDTH = 32, + parameter AXIL_CTRL_ADDR_WIDTH = 24, + parameter AXIL_CTRL_STRB_WIDTH = (AXIL_CTRL_DATA_WIDTH/8), + + // AXI lite interface configuration (application control) + parameter AXIL_APP_CTRL_DATA_WIDTH = AXIL_CTRL_DATA_WIDTH, + parameter AXIL_APP_CTRL_ADDR_WIDTH = 24, + parameter AXIL_APP_CTRL_STRB_WIDTH = (AXIL_APP_CTRL_DATA_WIDTH/8), + + // Ethernet interface configuration + parameter AXIS_ETH_TX_PIPELINE = 0, + parameter AXIS_ETH_TX_FIFO_PIPELINE = 2, + parameter AXIS_ETH_TX_TS_PIPELINE = 0, + parameter AXIS_ETH_RX_PIPELINE = 0, + parameter AXIS_ETH_RX_FIFO_PIPELINE = 2, + + // Statistics counter subsystem + parameter STAT_ENABLE = 1, + parameter STAT_DMA_ENABLE = 1, + parameter STAT_AXI_ENABLE = 1, + parameter STAT_INC_WIDTH = 24, + parameter STAT_ID_WIDTH = 12 +) +( + /* + * Clock: 125MHz LVDS + */ + input wire clk_125mhz_p, + input wire clk_125mhz_n, + + /* + * GPIO + */ + output wire [1:0] led, + output wire [1:0] sfp_led, + + /* + * Ethernet: SFP+ + */ + input wire sfp_rx_p, + input wire sfp_rx_n, + output wire sfp_tx_p, + output wire sfp_tx_n, + input wire sfp_mgt_refclk_p, + input wire sfp_mgt_refclk_n, + + output wire sfp_tx_disable, + input wire sfp_tx_fault, + input wire sfp_rx_los, + input wire sfp_mod_abs, + inout wire sfp_i2c_scl, + inout wire sfp_i2c_sda +); + +// PTP configuration +parameter PTP_CLK_PERIOD_NS_NUM = 32; +parameter PTP_CLK_PERIOD_NS_DENOM = 5; +parameter PTP_TS_WIDTH = 96; +parameter PTP_USE_SAMPLE_CLOCK = 1; +parameter IF_PTP_PERIOD_NS = 6'h6; +parameter IF_PTP_PERIOD_FNS = 16'h6666; + +// Interface configuration +parameter TX_TAG_WIDTH = 16; + +// Ethernet interface configuration +parameter XGMII_DATA_WIDTH = 64; +parameter XGMII_CTRL_WIDTH = XGMII_DATA_WIDTH/8; +parameter AXIS_ETH_DATA_WIDTH = XGMII_DATA_WIDTH; +parameter AXIS_ETH_KEEP_WIDTH = AXIS_ETH_DATA_WIDTH/8; +parameter AXIS_ETH_SYNC_DATA_WIDTH = AXIS_ETH_DATA_WIDTH; +parameter AXIS_ETH_TX_USER_WIDTH = TX_TAG_WIDTH + 1; +parameter AXIS_ETH_RX_USER_WIDTH = (PTP_TS_ENABLE ? PTP_TS_WIDTH : 0) + 1; + +// Clock and reset +wire zynq_pl_clk; +wire zynq_pl_reset; + +wire clk_156mhz_int; + +wire clk_125mhz_mmcm_out; + +// Internal 125 MHz clock +wire clk_125mhz_int; +wire rst_125mhz_int; + +wire mmcm_rst = zynq_pl_reset; +wire mmcm_locked; +wire mmcm_clkfb; + +// MMCM instance +// 156.25 MHz in, 125 MHz out +// PFD range: 10 MHz to 500 MHz +// VCO range: 800 MHz to 1600 MHz +// M = 8, D = 1 sets Fvco = 1250 MHz +// Divide by 10 to get output frequency of 125 MHz +MMCME4_BASE #( + .BANDWIDTH("OPTIMIZED"), + .CLKOUT0_DIVIDE_F(10), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0), + .CLKOUT1_DIVIDE(1), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0), + .CLKOUT2_DIVIDE(1), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0), + .CLKOUT3_DIVIDE(1), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0), + .CLKOUT4_DIVIDE(1), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0), + .CLKOUT5_DIVIDE(1), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0), + .CLKOUT6_DIVIDE(1), + .CLKOUT6_DUTY_CYCLE(0.5), + .CLKOUT6_PHASE(0), + .CLKFBOUT_MULT_F(8), + .CLKFBOUT_PHASE(0), + .DIVCLK_DIVIDE(1), + .REF_JITTER1(0.010), + .CLKIN1_PERIOD(6.4), + .STARTUP_WAIT("FALSE"), + .CLKOUT4_CASCADE("FALSE") +) +clk_mmcm_inst ( + .CLKIN1(clk_156mhz_int), + .CLKFBIN(mmcm_clkfb), + .RST(mmcm_rst), + .PWRDWN(1'b0), + .CLKOUT0(clk_125mhz_mmcm_out), + .CLKOUT0B(), + .CLKOUT1(), + .CLKOUT1B(), + .CLKOUT2(), + .CLKOUT2B(), + .CLKOUT3(), + .CLKOUT3B(), + .CLKOUT4(), + .CLKOUT5(), + .CLKOUT6(), + .CLKFBOUT(mmcm_clkfb), + .CLKFBOUTB(), + .LOCKED(mmcm_locked) +); + +BUFG +clk_125mhz_bufg_inst ( + .I(clk_125mhz_mmcm_out), + .O(clk_125mhz_int) +); + +sync_reset #( + .N(4) +) +sync_reset_125mhz_inst ( + .clk(clk_125mhz_int), + .rst(~mmcm_locked), + .out(rst_125mhz_int) +); + +// GPIO +wire sfp_tx_fault_int; +wire sfp_rx_los_int; +wire sfp_mod_abs_int; + +wire sfp_i2c_scl_i; +wire sfp_i2c_scl_o; +wire sfp_i2c_scl_t; +wire sfp_i2c_sda_i; +wire sfp_i2c_sda_o; +wire sfp_i2c_sda_t; + +reg sfp_i2c_scl_o_reg; +reg sfp_i2c_scl_t_reg; +reg sfp_i2c_sda_o_reg; +reg sfp_i2c_sda_t_reg; + +always @(posedge zynq_pl_clk) begin + sfp_i2c_scl_o_reg <= sfp_i2c_scl_o; + sfp_i2c_scl_t_reg <= sfp_i2c_scl_t; + sfp_i2c_sda_o_reg <= sfp_i2c_sda_o; + sfp_i2c_sda_t_reg <= sfp_i2c_sda_t; +end + +sync_signal #( + .WIDTH(5), + .N(2) +) +sync_signal_inst ( + .clk(zynq_pl_clk), + .in({sfp_tx_fault, sfp_rx_los, sfp_mod_abs, sfp_i2c_scl, sfp_i2c_sda}), + .out({sfp_tx_fault_int, sfp_rx_los_int, sfp_mod_abs_int, sfp_i2c_scl_i, sfp_i2c_sda_i}) +); + +assign sfp_i2c_scl = sfp_i2c_scl_t_reg ? 1'bz : sfp_i2c_scl_o_reg; +assign sfp_i2c_sda = sfp_i2c_sda_t_reg ? 1'bz : sfp_i2c_sda_o_reg; + +// Zynq AXI MM +wire [IRQ_COUNT-1:0] irq; + +wire [AXI_ID_WIDTH-1:0] axi_awid; +wire [AXI_ADDR_WIDTH-1:0] axi_awaddr; +wire [7:0] axi_awlen; +wire [2:0] axi_awsize; +wire [1:0] axi_awburst; +wire axi_awlock; +wire [3:0] axi_awcache; +wire [2:0] axi_awprot; +wire axi_awvalid; +wire axi_awready; +wire [AXI_DATA_WIDTH-1:0] axi_wdata; +wire [AXI_STRB_WIDTH-1:0] axi_wstrb; +wire axi_wlast; +wire axi_wvalid; +wire axi_wready; +wire [AXI_ID_WIDTH-1:0] axi_bid; +wire [1:0] axi_bresp; +wire axi_bvalid; +wire axi_bready; +wire [AXI_ID_WIDTH-1:0] axi_arid; +wire [AXI_ADDR_WIDTH-1:0] axi_araddr; +wire [7:0] axi_arlen; +wire [2:0] axi_arsize; +wire [1:0] axi_arburst; +wire axi_arlock; +wire [3:0] axi_arcache; +wire [2:0] axi_arprot; +wire axi_arvalid; +wire axi_arready; +wire [AXI_ID_WIDTH-1:0] axi_rid; +wire [AXI_DATA_WIDTH-1:0] axi_rdata; +wire [1:0] axi_rresp; +wire axi_rlast; +wire axi_rvalid; +wire axi_rready; + +// AXI lite connections +wire [AXIL_CTRL_ADDR_WIDTH-1:0] axil_ctrl_awaddr; +wire [2:0] axil_ctrl_awprot; +wire axil_ctrl_awvalid; +wire axil_ctrl_awready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_ctrl_wdata; +wire [AXIL_CTRL_STRB_WIDTH-1:0] axil_ctrl_wstrb; +wire axil_ctrl_wvalid; +wire axil_ctrl_wready; +wire [1:0] axil_ctrl_bresp; +wire axil_ctrl_bvalid; +wire axil_ctrl_bready; +wire [AXIL_CTRL_ADDR_WIDTH-1:0] axil_ctrl_araddr; +wire [2:0] axil_ctrl_arprot; +wire axil_ctrl_arvalid; +wire axil_ctrl_arready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_ctrl_rdata; +wire [1:0] axil_ctrl_rresp; +wire axil_ctrl_rvalid; +wire axil_ctrl_rready; + +wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] axil_app_ctrl_awaddr; +wire [2:0] axil_app_ctrl_awprot; +wire axil_app_ctrl_awvalid; +wire axil_app_ctrl_awready; +wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] axil_app_ctrl_wdata; +wire [AXIL_APP_CTRL_STRB_WIDTH-1:0] axil_app_ctrl_wstrb; +wire axil_app_ctrl_wvalid; +wire axil_app_ctrl_wready; +wire [1:0] axil_app_ctrl_bresp; +wire axil_app_ctrl_bvalid; +wire axil_app_ctrl_bready; +wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] axil_app_ctrl_araddr; +wire [2:0] axil_app_ctrl_arprot; +wire axil_app_ctrl_arvalid; +wire axil_app_ctrl_arready; +wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] axil_app_ctrl_rdata; +wire [1:0] axil_app_ctrl_rresp; +wire axil_app_ctrl_rvalid; +wire axil_app_ctrl_rready; + +reg [(IRQ_COUNT*IRQ_STRETCH)-1:0] irq_stretch = {(IRQ_COUNT*IRQ_STRETCH){1'b0}}; +always @(posedge zynq_pl_clk) begin + if (zynq_pl_reset) begin + irq_stretch <= {(IRQ_COUNT*IRQ_STRETCH){1'b0}}; + end else begin + /* IRQ shift vector */ + irq_stretch <= {irq_stretch[0 +: (IRQ_COUNT*IRQ_STRETCH)-IRQ_COUNT], irq}; + end +end + +reg [IRQ_COUNT-1:0] zynq_irq; +integer i, k; +always @* begin + for (k = 0; k < IRQ_COUNT; k = k + 1) begin + zynq_irq[k] = 1'b0; + for (i = 0; i < (IRQ_COUNT*IRQ_STRETCH); i = i + IRQ_COUNT) begin + zynq_irq[k] = zynq_irq[k] | irq_stretch[k + i]; + end + end +end + +zynq_ps zynq_ps_inst ( + .pl_clk0(zynq_pl_clk), + .pl_reset(zynq_pl_reset), + .pl_ps_irq0(zynq_irq), + + .m_axil_ctrl_araddr(axil_ctrl_araddr), + .m_axil_ctrl_arprot(axil_ctrl_arprot), + .m_axil_ctrl_arready(axil_ctrl_arready), + .m_axil_ctrl_arvalid(axil_ctrl_arvalid), + .m_axil_ctrl_awaddr(axil_ctrl_awaddr), + .m_axil_ctrl_awprot(axil_ctrl_awprot), + .m_axil_ctrl_awready(axil_ctrl_awready), + .m_axil_ctrl_awvalid(axil_ctrl_awvalid), + .m_axil_ctrl_bready(axil_ctrl_bready), + .m_axil_ctrl_bresp(axil_ctrl_bresp), + .m_axil_ctrl_bvalid(axil_ctrl_bvalid), + .m_axil_ctrl_rdata(axil_ctrl_rdata), + .m_axil_ctrl_rready(axil_ctrl_rready), + .m_axil_ctrl_rresp(axil_ctrl_rresp), + .m_axil_ctrl_rvalid(axil_ctrl_rvalid), + .m_axil_ctrl_wdata(axil_ctrl_wdata), + .m_axil_ctrl_wready(axil_ctrl_wready), + .m_axil_ctrl_wstrb(axil_ctrl_wstrb), + .m_axil_ctrl_wvalid(axil_ctrl_wvalid), + + .m_axil_app_ctrl_araddr(axil_app_ctrl_araddr), + .m_axil_app_ctrl_arprot(axil_app_ctrl_arprot), + .m_axil_app_ctrl_arready(axil_app_ctrl_arready), + .m_axil_app_ctrl_arvalid(axil_app_ctrl_arvalid), + .m_axil_app_ctrl_awaddr(axil_app_ctrl_awaddr), + .m_axil_app_ctrl_awprot(axil_app_ctrl_awprot), + .m_axil_app_ctrl_awready(axil_app_ctrl_awready), + .m_axil_app_ctrl_awvalid(axil_app_ctrl_awvalid), + .m_axil_app_ctrl_bready(axil_app_ctrl_bready), + .m_axil_app_ctrl_bresp(axil_app_ctrl_bresp), + .m_axil_app_ctrl_bvalid(axil_app_ctrl_bvalid), + .m_axil_app_ctrl_rdata(axil_app_ctrl_rdata), + .m_axil_app_ctrl_rready(axil_app_ctrl_rready), + .m_axil_app_ctrl_rresp(axil_app_ctrl_rresp), + .m_axil_app_ctrl_rvalid(axil_app_ctrl_rvalid), + .m_axil_app_ctrl_wdata(axil_app_ctrl_wdata), + .m_axil_app_ctrl_wready(axil_app_ctrl_wready), + .m_axil_app_ctrl_wstrb(axil_app_ctrl_wstrb), + .m_axil_app_ctrl_wvalid(axil_app_ctrl_wvalid), + + .s_axi_dma_araddr(axi_araddr), + .s_axi_dma_arburst(axi_arburst), + .s_axi_dma_arcache(axi_arcache), + .s_axi_dma_arid(axi_arid), + .s_axi_dma_arlen(axi_arlen), + .s_axi_dma_arlock(axi_arlock), + .s_axi_dma_arprot(axi_arprot), + .s_axi_dma_arqos({4{1'b0}}), + .s_axi_dma_arready(axi_arready), + .s_axi_dma_arsize(axi_arsize), + .s_axi_dma_aruser(1'b0), + .s_axi_dma_arvalid(axi_arvalid), + .s_axi_dma_awaddr(axi_awaddr), + .s_axi_dma_awburst(axi_awburst), + .s_axi_dma_awcache(axi_awcache), + .s_axi_dma_awid(axi_awid), + .s_axi_dma_awlen(axi_awlen), + .s_axi_dma_awlock(axi_awlock), + .s_axi_dma_awprot(axi_awprot), + .s_axi_dma_awqos({4{1'b0}}), + .s_axi_dma_awready(axi_awready), + .s_axi_dma_awsize(axi_awsize), + .s_axi_dma_awuser(1'b0), + .s_axi_dma_awvalid(axi_awvalid), + .s_axi_dma_bid(axi_bid), + .s_axi_dma_bready(axi_bready), + .s_axi_dma_bresp(axi_bresp), + .s_axi_dma_bvalid(axi_bvalid), + .s_axi_dma_rdata(axi_rdata), + .s_axi_dma_rid(axi_rid), + .s_axi_dma_rlast(axi_rlast), + .s_axi_dma_rready(axi_rready), + .s_axi_dma_rresp(axi_rresp), + .s_axi_dma_rvalid(axi_rvalid), + .s_axi_dma_wdata(axi_wdata), + .s_axi_dma_wlast(axi_wlast), + .s_axi_dma_wready(axi_wready), + .s_axi_dma_wstrb(axi_wstrb), + .s_axi_dma_wvalid(axi_wvalid) +); + +// XGMII 10G PHY +wire sfp_tx_clk_int; +wire sfp_tx_rst_int; +wire [XGMII_DATA_WIDTH-1:0] sfp_txd_int; +wire [XGMII_CTRL_WIDTH-1:0] sfp_txc_int; +wire sfp_tx_prbs31_enable_int; +wire sfp_rx_clk_int; +wire sfp_rx_rst_int; +wire [XGMII_DATA_WIDTH-1:0] sfp_rxd_int; +wire [XGMII_CTRL_WIDTH-1:0] sfp_rxc_int; +wire sfp_rx_prbs31_enable_int; +wire [6:0] sfp_rx_error_count_int; + +wire sfp_drp_clk = clk_125mhz_int; +wire sfp_drp_rst = rst_125mhz_int; +wire [23:0] sfp_drp_addr; +wire [15:0] sfp_drp_di; +wire sfp_drp_en; +wire sfp_drp_we; +wire [15:0] sfp_drp_do; +wire sfp_drp_rdy; + +wire sfp_rx_block_lock; +wire sfp_rx_status; +wire sfp_gtpowergood; + +wire sfp_mgt_refclk; +wire sfp_mgt_refclk_int; +wire sfp_mgt_refclk_bufg; + +assign clk_156mhz_int = sfp_mgt_refclk_bufg; + +IBUFDS_GTE4 ibufds_gte4_sfp_mgt_refclk_inst ( + .I (sfp_mgt_refclk_p), + .IB (sfp_mgt_refclk_n), + .CEB (1'b0), + .O (sfp_mgt_refclk), + .ODIV2 (sfp_mgt_refclk_int) +); + +BUFG_GT bufg_gt_sfp_mgt_refclk_inst ( + .CE (sfp_gtpowergood), + .CEMASK (1'b1), + .CLR (1'b0), + .CLRMASK (1'b1), + .DIV (3'd0), + .I (sfp_mgt_refclk_int), + .O (sfp_mgt_refclk_bufg) +); + +wire sfp_rst; + +sync_reset #( + .N(4) +) +sfp_sync_reset_inst ( + .clk(sfp_mgt_refclk_bufg), + .rst(rst_125mhz_int), + .out(sfp_rst) +); + +eth_xcvr_phy_10g_gty_quad_wrapper #( + .COUNT(1), + .GT_GTH(1), + .PRBS31_ENABLE(1) +) +sfp_phy_quad_inst ( + .xcvr_ctrl_clk(clk_125mhz_int), + .xcvr_ctrl_rst(sfp_rst), + + /* + * Common + */ + .xcvr_gtpowergood_out(sfp_gtpowergood), + .xcvr_ref_clk(sfp_mgt_refclk), + + /* + * DRP + */ + .drp_clk(sfp_drp_clk), + .drp_rst(sfp_drp_rst), + .drp_addr(sfp_drp_addr), + .drp_di(sfp_drp_di), + .drp_en(sfp_drp_en), + .drp_we(sfp_drp_we), + .drp_do(sfp_drp_do), + .drp_rdy(sfp_drp_rdy), + + /* + * Serial data + */ + .xcvr_txp({sfp_tx_p}), + .xcvr_txn({sfp_tx_n}), + .xcvr_rxp({sfp_rx_p}), + .xcvr_rxn({sfp_rx_n}), + + /* + * PHY connections + */ + .phy_1_tx_clk(sfp_tx_clk_int), + .phy_1_tx_rst(sfp_tx_rst_int), + .phy_1_xgmii_txd(sfp_txd_int), + .phy_1_xgmii_txc(sfp_txc_int), + .phy_1_rx_clk(sfp_rx_clk_int), + .phy_1_rx_rst(sfp_rx_rst_int), + .phy_1_xgmii_rxd(sfp_rxd_int), + .phy_1_xgmii_rxc(sfp_rxc_int), + .phy_1_tx_bad_block(), + .phy_1_rx_error_count(sfp_rx_error_count_int), + .phy_1_rx_bad_block(), + .phy_1_rx_sequence_error(), + .phy_1_rx_block_lock(sfp_rx_block_lock), + .phy_1_rx_high_ber(), + .phy_1_rx_status(sfp_rx_status), + .phy_1_tx_prbs31_enable(sfp_tx_prbs31_enable_int), + .phy_1_rx_prbs31_enable(sfp_rx_prbs31_enable_int) +); + +wire ptp_clk; +wire ptp_rst; +wire ptp_sample_clk; + +assign ptp_clk = sfp_mgt_refclk_bufg; +assign ptp_rst = sfp_rst; +assign ptp_sample_clk = clk_125mhz_int; + +assign sfp_led[0] = sfp_rx_status; +assign sfp_led[1] = 1'b0; + +fpga_core #( + // FW and board IDs + .FPGA_ID(FPGA_ID), + .FW_ID(FW_ID), + .FW_VER(FW_VER), + .BOARD_ID(BOARD_ID), + .BOARD_VER(BOARD_VER), + .BUILD_DATE(BUILD_DATE), + .GIT_HASH(GIT_HASH), + .RELEASE_INFO(RELEASE_INFO), + + // Board configuration + .TDMA_BER_ENABLE(TDMA_BER_ENABLE), + + // Structural configuration + .IF_COUNT(IF_COUNT), + .PORTS_PER_IF(PORTS_PER_IF), + .SCHED_PER_IF(SCHED_PER_IF), + .PORT_MASK(PORT_MASK), + + // Clock configuration + .CLK_PERIOD_NS_NUM(CLK_PERIOD_NS_NUM), + .CLK_PERIOD_NS_DENOM(CLK_PERIOD_NS_DENOM), + + // PTP configuration + .PTP_CLK_PERIOD_NS_NUM(PTP_CLK_PERIOD_NS_NUM), + .PTP_CLK_PERIOD_NS_DENOM(PTP_CLK_PERIOD_NS_DENOM), + .PTP_TS_WIDTH(PTP_TS_WIDTH), + .PTP_CLOCK_PIPELINE(PTP_CLOCK_PIPELINE), + .PTP_CLOCK_CDC_PIPELINE(PTP_CLOCK_CDC_PIPELINE), + .PTP_USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK), + .PTP_PORT_CDC_PIPELINE(PTP_PORT_CDC_PIPELINE), + .PTP_PEROUT_ENABLE(PTP_PEROUT_ENABLE), + .PTP_PEROUT_COUNT(PTP_PEROUT_COUNT), + + // Queue manager configuration + .EVENT_QUEUE_OP_TABLE_SIZE(EVENT_QUEUE_OP_TABLE_SIZE), + .TX_QUEUE_OP_TABLE_SIZE(TX_QUEUE_OP_TABLE_SIZE), + .RX_QUEUE_OP_TABLE_SIZE(RX_QUEUE_OP_TABLE_SIZE), + .TX_CPL_QUEUE_OP_TABLE_SIZE(TX_CPL_QUEUE_OP_TABLE_SIZE), + .RX_CPL_QUEUE_OP_TABLE_SIZE(RX_CPL_QUEUE_OP_TABLE_SIZE), + .EVENT_QUEUE_INDEX_WIDTH(EVENT_QUEUE_INDEX_WIDTH), + .TX_QUEUE_INDEX_WIDTH(TX_QUEUE_INDEX_WIDTH), + .RX_QUEUE_INDEX_WIDTH(RX_QUEUE_INDEX_WIDTH), + .TX_CPL_QUEUE_INDEX_WIDTH(TX_CPL_QUEUE_INDEX_WIDTH), + .RX_CPL_QUEUE_INDEX_WIDTH(RX_CPL_QUEUE_INDEX_WIDTH), + .EVENT_QUEUE_PIPELINE(EVENT_QUEUE_PIPELINE), + .TX_QUEUE_PIPELINE(TX_QUEUE_PIPELINE), + .RX_QUEUE_PIPELINE(RX_QUEUE_PIPELINE), + .TX_CPL_QUEUE_PIPELINE(TX_CPL_QUEUE_PIPELINE), + .RX_CPL_QUEUE_PIPELINE(RX_CPL_QUEUE_PIPELINE), + + // TX and RX engine configuration + .TX_DESC_TABLE_SIZE(TX_DESC_TABLE_SIZE), + .RX_DESC_TABLE_SIZE(RX_DESC_TABLE_SIZE), + .RX_INDIR_TBL_ADDR_WIDTH(RX_INDIR_TBL_ADDR_WIDTH), + + // Scheduler configuration + .TX_SCHEDULER_OP_TABLE_SIZE(TX_SCHEDULER_OP_TABLE_SIZE), + .TX_SCHEDULER_PIPELINE(TX_SCHEDULER_PIPELINE), + .TDMA_INDEX_WIDTH(TDMA_INDEX_WIDTH), + + // Interface configuration + .PTP_TS_ENABLE(PTP_TS_ENABLE), + .TX_CPL_FIFO_DEPTH(TX_CPL_FIFO_DEPTH), + .TX_TAG_WIDTH(TX_TAG_WIDTH), + .TX_CHECKSUM_ENABLE(TX_CHECKSUM_ENABLE), + .RX_HASH_ENABLE(RX_HASH_ENABLE), + .RX_CHECKSUM_ENABLE(RX_CHECKSUM_ENABLE), + .TX_FIFO_DEPTH(TX_FIFO_DEPTH), + .RX_FIFO_DEPTH(RX_FIFO_DEPTH), + .MAX_TX_SIZE(MAX_TX_SIZE), + .MAX_RX_SIZE(MAX_RX_SIZE), + .TX_RAM_SIZE(TX_RAM_SIZE), + .RX_RAM_SIZE(RX_RAM_SIZE), + + // Application block configuration + .APP_ID(APP_ID), + .APP_ENABLE(APP_ENABLE), + .APP_CTRL_ENABLE(APP_CTRL_ENABLE), + .APP_DMA_ENABLE(APP_DMA_ENABLE), + .APP_AXIS_DIRECT_ENABLE(APP_AXIS_DIRECT_ENABLE), + .APP_AXIS_SYNC_ENABLE(APP_AXIS_SYNC_ENABLE), + .APP_AXIS_IF_ENABLE(APP_AXIS_IF_ENABLE), + .APP_STAT_ENABLE(APP_STAT_ENABLE), + + // AXI interface configuration (DMA) + .AXI_DATA_WIDTH(AXI_DATA_WIDTH), + .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH), + .AXI_STRB_WIDTH(AXI_STRB_WIDTH), + .AXI_ID_WIDTH(AXI_ID_WIDTH), + + // DMA interface configuration + .DMA_IMM_ENABLE(DMA_IMM_ENABLE), + .DMA_IMM_WIDTH(DMA_IMM_WIDTH), + .DMA_LEN_WIDTH(DMA_LEN_WIDTH), + .DMA_TAG_WIDTH(DMA_TAG_WIDTH), + .RAM_ADDR_WIDTH(RAM_ADDR_WIDTH), + .RAM_PIPELINE(RAM_PIPELINE), + .AXI_DMA_MAX_BURST_LEN(AXI_DMA_MAX_BURST_LEN), + + // Interrupts + .IRQ_COUNT(IRQ_COUNT), + + // AXI lite interface configuration (control) + .AXIL_CTRL_DATA_WIDTH(AXIL_CTRL_DATA_WIDTH), + .AXIL_CTRL_ADDR_WIDTH(AXIL_CTRL_ADDR_WIDTH), + .AXIL_CTRL_STRB_WIDTH(AXIL_CTRL_STRB_WIDTH), + + // AXI lite interface configuration (application control) + .AXIL_APP_CTRL_DATA_WIDTH(AXIL_APP_CTRL_DATA_WIDTH), + .AXIL_APP_CTRL_ADDR_WIDTH(AXIL_APP_CTRL_ADDR_WIDTH), + .AXIL_APP_CTRL_STRB_WIDTH(AXIL_APP_CTRL_STRB_WIDTH), + + // Ethernet interface configuration + .AXIS_ETH_DATA_WIDTH(AXIS_ETH_DATA_WIDTH), + .AXIS_ETH_KEEP_WIDTH(AXIS_ETH_KEEP_WIDTH), + .AXIS_ETH_SYNC_DATA_WIDTH(AXIS_ETH_SYNC_DATA_WIDTH), + .AXIS_ETH_TX_USER_WIDTH(AXIS_ETH_TX_USER_WIDTH), + .AXIS_ETH_RX_USER_WIDTH(AXIS_ETH_RX_USER_WIDTH), + .AXIS_ETH_TX_PIPELINE(AXIS_ETH_TX_PIPELINE), + .AXIS_ETH_TX_FIFO_PIPELINE(AXIS_ETH_TX_FIFO_PIPELINE), + .AXIS_ETH_TX_TS_PIPELINE(AXIS_ETH_TX_TS_PIPELINE), + .AXIS_ETH_RX_PIPELINE(AXIS_ETH_RX_PIPELINE), + .AXIS_ETH_RX_FIFO_PIPELINE(AXIS_ETH_RX_FIFO_PIPELINE), + + // Statistics counter subsystem + .STAT_ENABLE(STAT_ENABLE), + .STAT_DMA_ENABLE(STAT_DMA_ENABLE), + .STAT_AXI_ENABLE(STAT_AXI_ENABLE), + .STAT_INC_WIDTH(STAT_INC_WIDTH), + .STAT_ID_WIDTH(STAT_ID_WIDTH) +) +core_inst ( + /* + * Clock: 250 MHz + * Synchronous reset + */ + .clk_250mhz(zynq_pl_clk), + .rst_250mhz(zynq_pl_reset), + + /* + * PTP clock + */ + .ptp_clk(ptp_clk), + .ptp_rst(ptp_rst), + .ptp_sample_clk(ptp_sample_clk), + + /* + * GPIO + */ + .led(led), + // .sfp_led(sfp_led), + + /* + * Interrupt outputs + */ + .irq(irq), + + /* + * AXI master interface (DMA) + */ + .m_axi_awid(axi_awid), + .m_axi_awaddr(axi_awaddr), + .m_axi_awlen(axi_awlen), + .m_axi_awsize(axi_awsize), + .m_axi_awburst(axi_awburst), + .m_axi_awlock(axi_awlock), + .m_axi_awcache(axi_awcache), + .m_axi_awprot(axi_awprot), + .m_axi_awvalid(axi_awvalid), + .m_axi_awready(axi_awready), + .m_axi_wdata(axi_wdata), + .m_axi_wstrb(axi_wstrb), + .m_axi_wlast(axi_wlast), + .m_axi_wvalid(axi_wvalid), + .m_axi_wready(axi_wready), + .m_axi_bid(axi_bid), + .m_axi_bresp(axi_bresp), + .m_axi_bvalid(axi_bvalid), + .m_axi_bready(axi_bready), + .m_axi_arid(axi_arid), + .m_axi_araddr(axi_araddr), + .m_axi_arlen(axi_arlen), + .m_axi_arsize(axi_arsize), + .m_axi_arburst(axi_arburst), + .m_axi_arlock(axi_arlock), + .m_axi_arcache(axi_arcache), + .m_axi_arprot(axi_arprot), + .m_axi_arvalid(axi_arvalid), + .m_axi_arready(axi_arready), + .m_axi_rid(axi_rid), + .m_axi_rdata(axi_rdata), + .m_axi_rresp(axi_rresp), + .m_axi_rlast(axi_rlast), + .m_axi_rvalid(axi_rvalid), + .m_axi_rready(axi_rready), + + /* + * AXI lite interface configuration (control) + */ + .s_axil_ctrl_awaddr(axil_ctrl_awaddr), + .s_axil_ctrl_awprot(axil_ctrl_awprot), + .s_axil_ctrl_awvalid(axil_ctrl_awvalid), + .s_axil_ctrl_awready(axil_ctrl_awready), + .s_axil_ctrl_wdata(axil_ctrl_wdata), + .s_axil_ctrl_wstrb(axil_ctrl_wstrb), + .s_axil_ctrl_wvalid(axil_ctrl_wvalid), + .s_axil_ctrl_wready(axil_ctrl_wready), + .s_axil_ctrl_bresp(axil_ctrl_bresp), + .s_axil_ctrl_bvalid(axil_ctrl_bvalid), + .s_axil_ctrl_bready(axil_ctrl_bready), + .s_axil_ctrl_araddr(axil_ctrl_araddr), + .s_axil_ctrl_arprot(axil_ctrl_arprot), + .s_axil_ctrl_arvalid(axil_ctrl_arvalid), + .s_axil_ctrl_arready(axil_ctrl_arready), + .s_axil_ctrl_rdata(axil_ctrl_rdata), + .s_axil_ctrl_rresp(axil_ctrl_rresp), + .s_axil_ctrl_rvalid(axil_ctrl_rvalid), + .s_axil_ctrl_rready(axil_ctrl_rready), + + /* + * AXI lite interface configuration (application control) + */ + .s_axil_app_ctrl_awaddr(axil_app_ctrl_awaddr), + .s_axil_app_ctrl_awprot(axil_app_ctrl_awprot), + .s_axil_app_ctrl_awvalid(axil_app_ctrl_awvalid), + .s_axil_app_ctrl_awready(axil_app_ctrl_awready), + .s_axil_app_ctrl_wdata(axil_app_ctrl_wdata), + .s_axil_app_ctrl_wstrb(axil_app_ctrl_wstrb), + .s_axil_app_ctrl_wvalid(axil_app_ctrl_wvalid), + .s_axil_app_ctrl_wready(axil_app_ctrl_wready), + .s_axil_app_ctrl_bresp(axil_app_ctrl_bresp), + .s_axil_app_ctrl_bvalid(axil_app_ctrl_bvalid), + .s_axil_app_ctrl_bready(axil_app_ctrl_bready), + .s_axil_app_ctrl_araddr(axil_app_ctrl_araddr), + .s_axil_app_ctrl_arprot(axil_app_ctrl_arprot), + .s_axil_app_ctrl_arvalid(axil_app_ctrl_arvalid), + .s_axil_app_ctrl_arready(axil_app_ctrl_arready), + .s_axil_app_ctrl_rdata(axil_app_ctrl_rdata), + .s_axil_app_ctrl_rresp(axil_app_ctrl_rresp), + .s_axil_app_ctrl_rvalid(axil_app_ctrl_rvalid), + .s_axil_app_ctrl_rready(axil_app_ctrl_rready), + + /* + * Ethernet: SFP+ + */ + .sfp_tx_clk(sfp_tx_clk_int), + .sfp_tx_rst(sfp_tx_rst_int), + .sfp_txd(sfp_txd_int), + .sfp_txc(sfp_txc_int), + .sfp_tx_prbs31_enable(sfp_tx_prbs31_enable_int), + .sfp_rx_clk(sfp_rx_clk_int), + .sfp_rx_rst(sfp_rx_rst_int), + .sfp_rxd(sfp_rxd_int), + .sfp_rxc(sfp_rxc_int), + .sfp_rx_prbs31_enable(sfp_rx_prbs31_enable_int), + .sfp_rx_error_count(sfp_rx_error_count_int), + .sfp_rx_status(sfp_rx_status), + + .sfp_tx_disable(sfp_tx_disable), + .sfp_tx_fault(sfp_tx_fault_int), + .sfp_rx_los(sfp_rx_los_int), + .sfp_mod_abs(sfp_mod_abs_int), + .sfp_i2c_scl_i(sfp_i2c_scl_i), + .sfp_i2c_scl_o(sfp_i2c_scl_o), + .sfp_i2c_scl_t(sfp_i2c_scl_t), + .sfp_i2c_sda_i(sfp_i2c_sda_i), + .sfp_i2c_sda_o(sfp_i2c_sda_o), + .sfp_i2c_sda_t(sfp_i2c_sda_t), + + .sfp_drp_clk(sfp_drp_clk), + .sfp_drp_rst(sfp_drp_rst), + .sfp_drp_addr(sfp_drp_addr), + .sfp_drp_di(sfp_drp_di), + .sfp_drp_en(sfp_drp_en), + .sfp_drp_we(sfp_drp_we), + .sfp_drp_do(sfp_drp_do), + .sfp_drp_rdy(sfp_drp_rdy) +); + +endmodule + +`resetall diff --git a/fpga/mqnic/KR260/fpga/rtl/fpga_core.v b/fpga/mqnic/KR260/fpga/rtl/fpga_core.v new file mode 100644 index 000000000..b9bb1662b --- /dev/null +++ b/fpga/mqnic/KR260/fpga/rtl/fpga_core.v @@ -0,0 +1,1219 @@ +/* + +Copyright 2023, The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY MISSINGLINKELECTRONICS INC. ''AS +IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL MISSINGLINKELECTRONICS INC. OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of MissingLinkElectronics Inc. + +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA core logic + */ +module fpga_core # +( + // FW and board IDs + parameter FPGA_ID = 32'h4A49093, + parameter FW_ID = 32'h00000000, + parameter FW_VER = 32'h00_00_01_00, + parameter BOARD_ID = 32'h10ee_9104, + parameter BOARD_VER = 32'h01_00_00_00, + parameter BUILD_DATE = 32'd602976000, + parameter GIT_HASH = 32'hdce357bf, + parameter RELEASE_INFO = 32'h00000000, + + // Board configuration + parameter TDMA_BER_ENABLE = 0, + + // Structural configuration + parameter IF_COUNT = 1, + parameter PORTS_PER_IF = 1, + parameter SCHED_PER_IF = PORTS_PER_IF, + parameter PORT_MASK = 0, + + // Clock configuration + parameter CLK_PERIOD_NS_NUM = 4, + parameter CLK_PERIOD_NS_DENOM = 1, + + // PTP configuration + parameter PTP_CLK_PERIOD_NS_NUM = 32, + parameter PTP_CLK_PERIOD_NS_DENOM = 5, + parameter PTP_TS_WIDTH = 96, + parameter PTP_CLOCK_PIPELINE = 0, + parameter PTP_CLOCK_CDC_PIPELINE = 0, + parameter PTP_USE_SAMPLE_CLOCK = 1, + parameter PTP_PORT_CDC_PIPELINE = 0, + parameter PTP_PEROUT_ENABLE = 1, + parameter PTP_PEROUT_COUNT = 1, + parameter IF_PTP_PERIOD_NS = 6'h6, + parameter IF_PTP_PERIOD_FNS = 16'h6666, + + // Queue manager configuration + parameter EVENT_QUEUE_OP_TABLE_SIZE = 32, + parameter TX_QUEUE_OP_TABLE_SIZE = 32, + parameter RX_QUEUE_OP_TABLE_SIZE = 32, + parameter TX_CPL_QUEUE_OP_TABLE_SIZE = TX_QUEUE_OP_TABLE_SIZE, + parameter RX_CPL_QUEUE_OP_TABLE_SIZE = RX_QUEUE_OP_TABLE_SIZE, + parameter EVENT_QUEUE_INDEX_WIDTH = 5, + parameter TX_QUEUE_INDEX_WIDTH = 13, + parameter RX_QUEUE_INDEX_WIDTH = 8, + parameter TX_CPL_QUEUE_INDEX_WIDTH = TX_QUEUE_INDEX_WIDTH, + parameter RX_CPL_QUEUE_INDEX_WIDTH = RX_QUEUE_INDEX_WIDTH, + parameter EVENT_QUEUE_PIPELINE = 3, + parameter TX_QUEUE_PIPELINE = 3+(TX_QUEUE_INDEX_WIDTH > 12 ? TX_QUEUE_INDEX_WIDTH-12 : 0), + parameter RX_QUEUE_PIPELINE = 3+(RX_QUEUE_INDEX_WIDTH > 12 ? RX_QUEUE_INDEX_WIDTH-12 : 0), + parameter TX_CPL_QUEUE_PIPELINE = TX_QUEUE_PIPELINE, + parameter RX_CPL_QUEUE_PIPELINE = RX_QUEUE_PIPELINE, + + // TX and RX engine configuration + parameter TX_DESC_TABLE_SIZE = 32, + parameter RX_DESC_TABLE_SIZE = 32, + parameter RX_INDIR_TBL_ADDR_WIDTH = RX_QUEUE_INDEX_WIDTH > 8 ? 8 : RX_QUEUE_INDEX_WIDTH, + + // Scheduler configuration + parameter TX_SCHEDULER_OP_TABLE_SIZE = TX_DESC_TABLE_SIZE, + parameter TX_SCHEDULER_PIPELINE = TX_QUEUE_PIPELINE, + parameter TDMA_INDEX_WIDTH = 6, + + // Interface configuration + parameter PTP_TS_ENABLE = 1, + parameter TX_CPL_FIFO_DEPTH = 32, + parameter TX_TAG_WIDTH = 16, + parameter TX_CHECKSUM_ENABLE = 1, + parameter RX_HASH_ENABLE = 1, + parameter RX_CHECKSUM_ENABLE = 1, + parameter ENABLE_PADDING = 1, + parameter ENABLE_DIC = 1, + parameter MIN_FRAME_LENGTH = 64, + parameter TX_FIFO_DEPTH = 32768, + parameter RX_FIFO_DEPTH = 32768, + parameter MAX_TX_SIZE = 9214, + parameter MAX_RX_SIZE = 9214, + parameter TX_RAM_SIZE = 32768, + parameter RX_RAM_SIZE = 32768, + + // Application block configuration + parameter APP_ID = 32'h00000000, + parameter APP_ENABLE = 0, + parameter APP_CTRL_ENABLE = 1, + parameter APP_DMA_ENABLE = 1, + parameter APP_AXIS_DIRECT_ENABLE = 1, + parameter APP_AXIS_SYNC_ENABLE = 1, + parameter APP_AXIS_IF_ENABLE = 1, + parameter APP_STAT_ENABLE = 1, + + // AXI interface configuration (DMA) + parameter AXI_DATA_WIDTH = 128, + parameter AXI_ADDR_WIDTH = 32, + parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8), + parameter AXI_ID_WIDTH = 8, + + // DMA interface configuration + parameter DMA_IMM_ENABLE = 0, + parameter DMA_IMM_WIDTH = 32, + parameter DMA_LEN_WIDTH = 16, + parameter DMA_TAG_WIDTH = 16, + parameter RAM_ADDR_WIDTH = $clog2(TX_RAM_SIZE > RX_RAM_SIZE ? TX_RAM_SIZE : RX_RAM_SIZE), + parameter RAM_PIPELINE = 2, + parameter AXI_DMA_MAX_BURST_LEN = 256, + + // Interrupts + parameter IRQ_COUNT = 32, + + // AXI lite interface configuration (control) + parameter AXIL_CTRL_DATA_WIDTH = 32, + parameter AXIL_CTRL_ADDR_WIDTH = 24, + parameter AXIL_CTRL_STRB_WIDTH = (AXIL_CTRL_DATA_WIDTH/8), + + // AXI lite interface configuration (application control) + parameter AXIL_APP_CTRL_DATA_WIDTH = AXIL_CTRL_DATA_WIDTH, + parameter AXIL_APP_CTRL_ADDR_WIDTH = 24, + parameter AXIL_APP_CTRL_STRB_WIDTH = (AXIL_APP_CTRL_DATA_WIDTH/8), + + // Ethernet interface configuration + parameter XGMII_DATA_WIDTH = 64, + parameter XGMII_CTRL_WIDTH = XGMII_DATA_WIDTH/8, + parameter AXIS_ETH_DATA_WIDTH = XGMII_DATA_WIDTH, + parameter AXIS_ETH_KEEP_WIDTH = AXIS_ETH_DATA_WIDTH/8, + parameter AXIS_ETH_SYNC_DATA_WIDTH = AXIS_ETH_DATA_WIDTH, + parameter AXIS_ETH_TX_USER_WIDTH = TX_TAG_WIDTH + 1, + parameter AXIS_ETH_RX_USER_WIDTH = (PTP_TS_ENABLE ? PTP_TS_WIDTH : 0) + 1, + parameter AXIS_ETH_TX_PIPELINE = 0, + parameter AXIS_ETH_TX_FIFO_PIPELINE = 2, + parameter AXIS_ETH_TX_TS_PIPELINE = 0, + parameter AXIS_ETH_RX_PIPELINE = 0, + parameter AXIS_ETH_RX_FIFO_PIPELINE = 2, + + // Statistics counter subsystem + parameter STAT_ENABLE = 1, + parameter STAT_DMA_ENABLE = 1, + parameter STAT_AXI_ENABLE = 1, + parameter STAT_INC_WIDTH = 24, + parameter STAT_ID_WIDTH = 12 +) +( + /* + * Clock: 300 MHz + * Synchronous reset + */ + input wire clk_250mhz, + input wire rst_250mhz, + + /* + * PTP clock + */ + input wire ptp_clk, + input wire ptp_rst, + input wire ptp_sample_clk, + + /* + * GPIO + */ + output wire [1:0] led, + output wire [1:0] sfp_led, + + /* + * Interrupt outputs + */ + output wire [IRQ_COUNT-1:0] irq, + + /* + * AXI master interface (DMA) + */ + output wire [AXI_ID_WIDTH-1:0] m_axi_awid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [7:0] m_axi_awlen, + output wire [2:0] m_axi_awsize, + output wire [1:0] m_axi_awburst, + output wire m_axi_awlock, + output wire [3:0] m_axi_awcache, + output wire [2:0] m_axi_awprot, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata, + output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb, + output wire m_axi_wlast, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [AXI_ID_WIDTH-1:0] m_axi_bid, + input wire [1:0] m_axi_bresp, + input wire m_axi_bvalid, + output wire m_axi_bready, + output wire [AXI_ID_WIDTH-1:0] m_axi_arid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr, + output wire [7:0] m_axi_arlen, + output wire [2:0] m_axi_arsize, + output wire [1:0] m_axi_arburst, + output wire m_axi_arlock, + output wire [3:0] m_axi_arcache, + output wire [2:0] m_axi_arprot, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [AXI_ID_WIDTH-1:0] m_axi_rid, + input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata, + input wire [1:0] m_axi_rresp, + input wire m_axi_rlast, + input wire m_axi_rvalid, + output wire m_axi_rready, + + /* + * AXI lite interface configuration (control) + */ + input wire [AXIL_CTRL_ADDR_WIDTH-1:0] s_axil_ctrl_awaddr, + input wire [2:0] s_axil_ctrl_awprot, + input wire s_axil_ctrl_awvalid, + output wire s_axil_ctrl_awready, + input wire [AXIL_CTRL_DATA_WIDTH-1:0] s_axil_ctrl_wdata, + input wire [AXIL_CTRL_STRB_WIDTH-1:0] s_axil_ctrl_wstrb, + input wire s_axil_ctrl_wvalid, + output wire s_axil_ctrl_wready, + output wire [1:0] s_axil_ctrl_bresp, + output wire s_axil_ctrl_bvalid, + input wire s_axil_ctrl_bready, + input wire [AXIL_CTRL_ADDR_WIDTH-1:0] s_axil_ctrl_araddr, + input wire [2:0] s_axil_ctrl_arprot, + input wire s_axil_ctrl_arvalid, + output wire s_axil_ctrl_arready, + output wire [AXIL_CTRL_DATA_WIDTH-1:0] s_axil_ctrl_rdata, + output wire [1:0] s_axil_ctrl_rresp, + output wire s_axil_ctrl_rvalid, + input wire s_axil_ctrl_rready, + + /* + * AXI lite interface configuration (application control) + */ + input wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] s_axil_app_ctrl_awaddr, + input wire [2:0] s_axil_app_ctrl_awprot, + input wire s_axil_app_ctrl_awvalid, + output wire s_axil_app_ctrl_awready, + input wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] s_axil_app_ctrl_wdata, + input wire [AXIL_APP_CTRL_STRB_WIDTH-1:0] s_axil_app_ctrl_wstrb, + input wire s_axil_app_ctrl_wvalid, + output wire s_axil_app_ctrl_wready, + output wire [1:0] s_axil_app_ctrl_bresp, + output wire s_axil_app_ctrl_bvalid, + input wire s_axil_app_ctrl_bready, + input wire [AXIL_APP_CTRL_ADDR_WIDTH-1:0] s_axil_app_ctrl_araddr, + input wire [2:0] s_axil_app_ctrl_arprot, + input wire s_axil_app_ctrl_arvalid, + output wire s_axil_app_ctrl_arready, + output wire [AXIL_APP_CTRL_DATA_WIDTH-1:0] s_axil_app_ctrl_rdata, + output wire [1:0] s_axil_app_ctrl_rresp, + output wire s_axil_app_ctrl_rvalid, + input wire s_axil_app_ctrl_rready, + + /* + * Ethernet: SFP+ + */ + input wire sfp_tx_clk, + input wire sfp_tx_rst, + output wire [63:0] sfp_txd, + output wire [7:0] sfp_txc, + output wire sfp_tx_prbs31_enable, + input wire sfp_rx_clk, + input wire sfp_rx_rst, + input wire [63:0] sfp_rxd, + input wire [7:0] sfp_rxc, + output wire sfp_rx_prbs31_enable, + input wire [6:0] sfp_rx_error_count, + input wire sfp_rx_status, + + output wire sfp_tx_disable, + input wire sfp_tx_fault, + input wire sfp_rx_los, + input wire sfp_mod_abs, + input wire sfp_i2c_scl_i, + output wire sfp_i2c_scl_o, + output wire sfp_i2c_scl_t, + input wire sfp_i2c_sda_i, + output wire sfp_i2c_sda_o, + output wire sfp_i2c_sda_t, + + input wire sfp_drp_clk, + input wire sfp_drp_rst, + output wire [23:0] sfp_drp_addr, + output wire [15:0] sfp_drp_di, + output wire sfp_drp_en, + output wire sfp_drp_we, + input wire [15:0] sfp_drp_do, + input wire sfp_drp_rdy +); + +parameter PORT_COUNT = IF_COUNT*PORTS_PER_IF; + +parameter AXIL_IF_CTRL_ADDR_WIDTH = AXIL_CTRL_ADDR_WIDTH-$clog2(IF_COUNT); +parameter AXIL_CSR_ADDR_WIDTH = AXIL_IF_CTRL_ADDR_WIDTH-5-$clog2((PORTS_PER_IF+3)/8); + +localparam RB_BASE_ADDR = 16'h1000; +localparam RBB = RB_BASE_ADDR & {AXIL_CTRL_ADDR_WIDTH{1'b1}}; + +localparam RB_DRP_SFP_BASE = RB_BASE_ADDR + 16'h20; + +initial begin + if (PORT_COUNT > 1) begin + $error("Error: Max port count exceeded (instance %m)"); + $finish; + end +end + +// AXI lite connections +wire [AXIL_CSR_ADDR_WIDTH-1:0] axil_csr_awaddr; +wire [2:0] axil_csr_awprot; +wire axil_csr_awvalid; +wire axil_csr_awready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_csr_wdata; +wire [AXIL_CTRL_STRB_WIDTH-1:0] axil_csr_wstrb; +wire axil_csr_wvalid; +wire axil_csr_wready; +wire [1:0] axil_csr_bresp; +wire axil_csr_bvalid; +wire axil_csr_bready; +wire [AXIL_CSR_ADDR_WIDTH-1:0] axil_csr_araddr; +wire [2:0] axil_csr_arprot; +wire axil_csr_arvalid; +wire axil_csr_arready; +wire [AXIL_CTRL_DATA_WIDTH-1:0] axil_csr_rdata; +wire [1:0] axil_csr_rresp; +wire axil_csr_rvalid; +wire axil_csr_rready; + +// PTP +wire [PTP_TS_WIDTH-1:0] ptp_ts_96; +wire ptp_ts_step; +wire ptp_pps; +wire ptp_pps_str; +wire [PTP_TS_WIDTH-1:0] ptp_sync_ts_96; +wire ptp_sync_ts_step; +wire ptp_sync_pps; + +wire [PTP_PEROUT_COUNT-1:0] ptp_perout_locked; +wire [PTP_PEROUT_COUNT-1:0] ptp_perout_error; +wire [PTP_PEROUT_COUNT-1:0] ptp_perout_pulse; + +// control registers +wire [AXIL_CSR_ADDR_WIDTH-1:0] ctrl_reg_wr_addr; +wire [AXIL_CTRL_DATA_WIDTH-1:0] ctrl_reg_wr_data; +wire [AXIL_CTRL_STRB_WIDTH-1:0] ctrl_reg_wr_strb; +wire ctrl_reg_wr_en; +wire ctrl_reg_wr_wait; +wire ctrl_reg_wr_ack; +wire [AXIL_CSR_ADDR_WIDTH-1:0] ctrl_reg_rd_addr; +wire ctrl_reg_rd_en; +wire [AXIL_CTRL_DATA_WIDTH-1:0] ctrl_reg_rd_data; +wire ctrl_reg_rd_wait; +wire ctrl_reg_rd_ack; + +wire sfp_drp_reg_wr_wait; +wire sfp_drp_reg_wr_ack; +wire [AXIL_CTRL_DATA_WIDTH-1:0] sfp_drp_reg_rd_data; +wire sfp_drp_reg_rd_wait; +wire sfp_drp_reg_rd_ack; + +reg ctrl_reg_wr_ack_reg = 1'b0; +reg [AXIL_CTRL_DATA_WIDTH-1:0] ctrl_reg_rd_data_reg = {AXIL_CTRL_DATA_WIDTH{1'b0}}; +reg ctrl_reg_rd_ack_reg = 1'b0; + +reg sfp_tx_disable_reg = 1'b0; + +reg sfp_i2c_scl_o_reg = 1'b1; +reg sfp_i2c_sda_o_reg = 1'b1; + +assign ctrl_reg_wr_wait = sfp_drp_reg_wr_wait; +assign ctrl_reg_wr_ack = ctrl_reg_wr_ack_reg | sfp_drp_reg_wr_ack; +assign ctrl_reg_rd_data = ctrl_reg_rd_data_reg | sfp_drp_reg_rd_data; +assign ctrl_reg_rd_wait = sfp_drp_reg_rd_wait; +assign ctrl_reg_rd_ack = ctrl_reg_rd_ack_reg | sfp_drp_reg_rd_ack; + +assign sfp_tx_disable = sfp_tx_disable_reg; + +assign sfp_i2c_scl_o = sfp_i2c_scl_o_reg; +assign sfp_i2c_scl_t = sfp_i2c_scl_o_reg; +assign sfp_i2c_sda_o = sfp_i2c_sda_o_reg; +assign sfp_i2c_sda_t = sfp_i2c_sda_o_reg; + +always @(posedge clk_250mhz) begin + ctrl_reg_wr_ack_reg <= 1'b0; + ctrl_reg_rd_data_reg <= {AXIL_CTRL_DATA_WIDTH{1'b0}}; + ctrl_reg_rd_ack_reg <= 1'b0; + + if (ctrl_reg_wr_en && !ctrl_reg_wr_ack_reg) begin + // write operation + ctrl_reg_wr_ack_reg <= 1'b0; + case ({ctrl_reg_wr_addr >> 2, 2'b00}) + // I2C 0 + RBB+8'h0C: begin + // I2C ctrl: control + if (ctrl_reg_wr_strb[0]) begin + sfp_i2c_scl_o_reg <= ctrl_reg_wr_data[1]; + end + if (ctrl_reg_wr_strb[1]) begin + sfp_i2c_sda_o_reg <= ctrl_reg_wr_data[9]; + end + end + // XCVR GPIO + RBB+8'h1C: begin + // XCVR GPIO: control 0123 + if (ctrl_reg_wr_strb[0]) begin + sfp_tx_disable_reg <= ctrl_reg_wr_data[5]; + end + end + default: ctrl_reg_wr_ack_reg <= 1'b0; + endcase + end + + if (ctrl_reg_rd_en && !ctrl_reg_rd_ack_reg) begin + // read operation + ctrl_reg_rd_ack_reg <= 1'b1; + case ({ctrl_reg_rd_addr >> 2, 2'b00}) + // I2C 0 + RBB+8'h00: ctrl_reg_rd_data_reg <= 32'h0000C110; // I2C ctrl: Type + RBB+8'h04: ctrl_reg_rd_data_reg <= 32'h00000100; // I2C ctrl: Version + RBB+8'h08: ctrl_reg_rd_data_reg <= RB_BASE_ADDR+8'h10; // I2C ctrl: Next header + RBB+8'h0C: begin + // I2C ctrl: control + ctrl_reg_rd_data_reg[0] <= sfp_i2c_scl_i; + ctrl_reg_rd_data_reg[1] <= sfp_i2c_scl_o_reg; + ctrl_reg_rd_data_reg[8] <= sfp_i2c_sda_i; + ctrl_reg_rd_data_reg[9] <= sfp_i2c_sda_o_reg; + end + // XCVR GPIO + RBB+8'h10: ctrl_reg_rd_data_reg <= 32'h0000C101; // XCVR GPIO: Type + RBB+8'h14: ctrl_reg_rd_data_reg <= 32'h00000100; // XCVR GPIO: Version + RBB+8'h18: ctrl_reg_rd_data_reg <= RB_DRP_SFP_BASE; // XCVR GPIO: Next header + RBB+8'h1C: begin + // XCVR GPIO: control 0123 + ctrl_reg_rd_data_reg[0] <= !sfp_mod_abs; + ctrl_reg_rd_data_reg[1] <= sfp_tx_fault; + ctrl_reg_rd_data_reg[2] <= sfp_rx_los; + ctrl_reg_rd_data_reg[5] <= sfp_tx_disable_reg; + end + default: ctrl_reg_rd_ack_reg <= 1'b0; + endcase + end + + if (rst_250mhz) begin + ctrl_reg_wr_ack_reg <= 1'b0; + ctrl_reg_rd_ack_reg <= 1'b0; + + sfp_tx_disable_reg <= 1'b0; + + sfp_i2c_scl_o_reg <= 1'b1; + sfp_i2c_sda_o_reg <= 1'b1; + end +end + +rb_drp #( + .DRP_ADDR_WIDTH(24), + .DRP_DATA_WIDTH(16), + .DRP_INFO({8'h09, 8'h02, 8'd0, 8'd1}), + .REG_ADDR_WIDTH(AXIL_CSR_ADDR_WIDTH), + .REG_DATA_WIDTH(AXIL_CTRL_DATA_WIDTH), + .REG_STRB_WIDTH(AXIL_CTRL_STRB_WIDTH), + .RB_BASE_ADDR(RB_DRP_SFP_BASE), + .RB_NEXT_PTR(0) +) +sfp_rb_drp_inst ( + .clk(clk_250mhz), + .rst(rst_250mhz), + + /* + * Register interface + */ + .reg_wr_addr(ctrl_reg_wr_addr), + .reg_wr_data(ctrl_reg_wr_data), + .reg_wr_strb(ctrl_reg_wr_strb), + .reg_wr_en(ctrl_reg_wr_en), + .reg_wr_wait(sfp_drp_reg_wr_wait), + .reg_wr_ack(sfp_drp_reg_wr_ack), + .reg_rd_addr(ctrl_reg_rd_addr), + .reg_rd_en(ctrl_reg_rd_en), + .reg_rd_data(sfp_drp_reg_rd_data), + .reg_rd_wait(sfp_drp_reg_rd_wait), + .reg_rd_ack(sfp_drp_reg_rd_ack), + + /* + * DRP + */ + .drp_clk(sfp_drp_clk), + .drp_rst(sfp_drp_rst), + .drp_addr(sfp_drp_addr), + .drp_di(sfp_drp_di), + .drp_en(sfp_drp_en), + .drp_we(sfp_drp_we), + .drp_do(sfp_drp_do), + .drp_rdy(sfp_drp_rdy) +); + +generate + +if (TDMA_BER_ENABLE) begin + + // BER tester + tdma_ber #( + .COUNT(1), + .INDEX_WIDTH(6), + .SLICE_WIDTH(5), + .AXIL_DATA_WIDTH(AXIL_CTRL_DATA_WIDTH), + .AXIL_ADDR_WIDTH(8+6+$clog2(1)), + .AXIL_STRB_WIDTH(AXIL_CTRL_STRB_WIDTH), + .SCHEDULE_START_S(0), + .SCHEDULE_START_NS(0), + .SCHEDULE_PERIOD_S(0), + .SCHEDULE_PERIOD_NS(1000000), + .TIMESLOT_PERIOD_S(0), + .TIMESLOT_PERIOD_NS(100000), + .ACTIVE_PERIOD_S(0), + .ACTIVE_PERIOD_NS(90000) + ) + tdma_ber_inst ( + .clk(clk_250mhz), + .rst(rst_250mhz), + .phy_tx_clk({sfp_tx_clk}), + .phy_rx_clk({sfp_rx_clk}), + .phy_rx_error_count({sfp_rx_error_count}), + .phy_tx_prbs31_enable({sfp_tx_prbs31_enable}), + .phy_rx_prbs31_enable({sfp_rx_prbs31_enable}), + .s_axil_awaddr(axil_csr_awaddr), + .s_axil_awprot(axil_csr_awprot), + .s_axil_awvalid(axil_csr_awvalid), + .s_axil_awready(axil_csr_awready), + .s_axil_wdata(axil_csr_wdata), + .s_axil_wstrb(axil_csr_wstrb), + .s_axil_wvalid(axil_csr_wvalid), + .s_axil_wready(axil_csr_wready), + .s_axil_bresp(axil_csr_bresp), + .s_axil_bvalid(axil_csr_bvalid), + .s_axil_bready(axil_csr_bready), + .s_axil_araddr(axil_csr_araddr), + .s_axil_arprot(axil_csr_arprot), + .s_axil_arvalid(axil_csr_arvalid), + .s_axil_arready(axil_csr_arready), + .s_axil_rdata(axil_csr_rdata), + .s_axil_rresp(axil_csr_rresp), + .s_axil_rvalid(axil_csr_rvalid), + .s_axil_rready(axil_csr_rready), + .ptp_ts_96(ptp_sync_ts_96), + .ptp_ts_step(ptp_sync_ts_step) + ); + +end else begin + + assign sfp_tx_prbs31_enable = 1'b0; + assign sfp_rx_prbs31_enable = 1'b0; + +end + +endgenerate + +assign led[0] = 0; +assign led[1] = ptp_pps_str; + +assign sfp_led = 0; + +wire [PORT_COUNT-1:0] eth_tx_clk; +wire [PORT_COUNT-1:0] eth_tx_rst; + +wire [PORT_COUNT*PTP_TS_WIDTH-1:0] eth_tx_ptp_ts_96; +wire [PORT_COUNT-1:0] eth_tx_ptp_ts_step; + +wire [PORT_COUNT*AXIS_ETH_DATA_WIDTH-1:0] axis_eth_tx_tdata; +wire [PORT_COUNT*AXIS_ETH_KEEP_WIDTH-1:0] axis_eth_tx_tkeep; +wire [PORT_COUNT-1:0] axis_eth_tx_tvalid; +wire [PORT_COUNT-1:0] axis_eth_tx_tready; +wire [PORT_COUNT-1:0] axis_eth_tx_tlast; +wire [PORT_COUNT*AXIS_ETH_TX_USER_WIDTH-1:0] axis_eth_tx_tuser; + +wire [PORT_COUNT*PTP_TS_WIDTH-1:0] axis_eth_tx_ptp_ts; +wire [PORT_COUNT*TX_TAG_WIDTH-1:0] axis_eth_tx_ptp_ts_tag; +wire [PORT_COUNT-1:0] axis_eth_tx_ptp_ts_valid; +wire [PORT_COUNT-1:0] axis_eth_tx_ptp_ts_ready; + +wire [PORT_COUNT-1:0] eth_tx_status; + +wire [PORT_COUNT-1:0] eth_rx_clk; +wire [PORT_COUNT-1:0] eth_rx_rst; + +wire [PORT_COUNT*PTP_TS_WIDTH-1:0] eth_rx_ptp_ts_96; +wire [PORT_COUNT-1:0] eth_rx_ptp_ts_step; + +wire [PORT_COUNT*AXIS_ETH_DATA_WIDTH-1:0] axis_eth_rx_tdata; +wire [PORT_COUNT*AXIS_ETH_KEEP_WIDTH-1:0] axis_eth_rx_tkeep; +wire [PORT_COUNT-1:0] axis_eth_rx_tvalid; +wire [PORT_COUNT-1:0] axis_eth_rx_tready; +wire [PORT_COUNT-1:0] axis_eth_rx_tlast; +wire [PORT_COUNT*AXIS_ETH_RX_USER_WIDTH-1:0] axis_eth_rx_tuser; + +wire [PORT_COUNT-1:0] eth_rx_status; + +wire [PORT_COUNT-1:0] port_xgmii_tx_clk; +wire [PORT_COUNT-1:0] port_xgmii_tx_rst; +wire [PORT_COUNT*XGMII_DATA_WIDTH-1:0] port_xgmii_txd; +wire [PORT_COUNT*XGMII_CTRL_WIDTH-1:0] port_xgmii_txc; + +wire [PORT_COUNT-1:0] port_xgmii_rx_clk; +wire [PORT_COUNT-1:0] port_xgmii_rx_rst; +wire [PORT_COUNT*XGMII_DATA_WIDTH-1:0] port_xgmii_rxd; +wire [PORT_COUNT*XGMII_CTRL_WIDTH-1:0] port_xgmii_rxc; + +mqnic_port_map_phy_xgmii #( + .PHY_COUNT(1), + .PORT_MASK(PORT_MASK), + .PORT_GROUP_SIZE(1), + + .IF_COUNT(IF_COUNT), + .PORTS_PER_IF(PORTS_PER_IF), + + .PORT_COUNT(PORT_COUNT), + + .XGMII_DATA_WIDTH(XGMII_DATA_WIDTH), + .XGMII_CTRL_WIDTH(XGMII_CTRL_WIDTH) +) +mqnic_port_map_phy_xgmii_inst ( + // towards PHY + .phy_xgmii_tx_clk({sfp_tx_clk}), + .phy_xgmii_tx_rst({sfp_tx_rst}), + .phy_xgmii_txd({sfp_txd}), + .phy_xgmii_txc({sfp_txc}), + .phy_tx_status(1'b1), + + .phy_xgmii_rx_clk({sfp_rx_clk}), + .phy_xgmii_rx_rst({sfp_rx_rst}), + .phy_xgmii_rxd({sfp_rxd}), + .phy_xgmii_rxc({sfp_rxc}), + .phy_rx_status({sfp_rx_status}), + + // towards MAC + .port_xgmii_tx_clk(port_xgmii_tx_clk), + .port_xgmii_tx_rst(port_xgmii_tx_rst), + .port_xgmii_txd(port_xgmii_txd), + .port_xgmii_txc(port_xgmii_txc), + .port_tx_status(eth_tx_status), + + .port_xgmii_rx_clk(port_xgmii_rx_clk), + .port_xgmii_rx_rst(port_xgmii_rx_rst), + .port_xgmii_rxd(port_xgmii_rxd), + .port_xgmii_rxc(port_xgmii_rxc), + .port_rx_status(eth_rx_status) +); + +generate + genvar n; + + for (n = 0; n < PORT_COUNT; n = n + 1) begin : mac + + assign eth_tx_clk[n] = port_xgmii_tx_clk[n]; + assign eth_tx_rst[n] = port_xgmii_tx_rst[n]; + assign eth_rx_clk[n] = port_xgmii_rx_clk[n]; + assign eth_rx_rst[n] = port_xgmii_rx_rst[n]; + + eth_mac_10g #( + .DATA_WIDTH(AXIS_ETH_DATA_WIDTH), + .KEEP_WIDTH(AXIS_ETH_KEEP_WIDTH), + .ENABLE_PADDING(ENABLE_PADDING), + .ENABLE_DIC(ENABLE_DIC), + .MIN_FRAME_LENGTH(MIN_FRAME_LENGTH), + .PTP_PERIOD_NS(IF_PTP_PERIOD_NS), + .PTP_PERIOD_FNS(IF_PTP_PERIOD_FNS), + .TX_PTP_TS_ENABLE(PTP_TS_ENABLE), + .TX_PTP_TS_WIDTH(PTP_TS_WIDTH), + .TX_PTP_TAG_ENABLE(PTP_TS_ENABLE), + .TX_PTP_TAG_WIDTH(TX_TAG_WIDTH), + .RX_PTP_TS_ENABLE(PTP_TS_ENABLE), + .RX_PTP_TS_WIDTH(PTP_TS_WIDTH), + .TX_USER_WIDTH(AXIS_ETH_TX_USER_WIDTH), + .RX_USER_WIDTH(AXIS_ETH_RX_USER_WIDTH) + ) + eth_mac_inst ( + .tx_clk(port_xgmii_tx_clk[n]), + .tx_rst(port_xgmii_tx_rst[n]), + .rx_clk(port_xgmii_rx_clk[n]), + .rx_rst(port_xgmii_rx_rst[n]), + + .tx_axis_tdata(axis_eth_tx_tdata[n*AXIS_ETH_DATA_WIDTH +: AXIS_ETH_DATA_WIDTH]), + .tx_axis_tkeep(axis_eth_tx_tkeep[n*AXIS_ETH_KEEP_WIDTH +: AXIS_ETH_KEEP_WIDTH]), + .tx_axis_tvalid(axis_eth_tx_tvalid[n +: 1]), + .tx_axis_tready(axis_eth_tx_tready[n +: 1]), + .tx_axis_tlast(axis_eth_tx_tlast[n +: 1]), + .tx_axis_tuser(axis_eth_tx_tuser[n*AXIS_ETH_TX_USER_WIDTH +: AXIS_ETH_TX_USER_WIDTH]), + + .rx_axis_tdata(axis_eth_rx_tdata[n*AXIS_ETH_DATA_WIDTH +: AXIS_ETH_DATA_WIDTH]), + .rx_axis_tkeep(axis_eth_rx_tkeep[n*AXIS_ETH_KEEP_WIDTH +: AXIS_ETH_KEEP_WIDTH]), + .rx_axis_tvalid(axis_eth_rx_tvalid[n +: 1]), + .rx_axis_tlast(axis_eth_rx_tlast[n +: 1]), + .rx_axis_tuser(axis_eth_rx_tuser[n*AXIS_ETH_RX_USER_WIDTH +: AXIS_ETH_RX_USER_WIDTH]), + + .xgmii_rxd(port_xgmii_rxd[n*XGMII_DATA_WIDTH +: XGMII_DATA_WIDTH]), + .xgmii_rxc(port_xgmii_rxc[n*XGMII_CTRL_WIDTH +: XGMII_CTRL_WIDTH]), + .xgmii_txd(port_xgmii_txd[n*XGMII_DATA_WIDTH +: XGMII_DATA_WIDTH]), + .xgmii_txc(port_xgmii_txc[n*XGMII_CTRL_WIDTH +: XGMII_CTRL_WIDTH]), + + .tx_ptp_ts(eth_tx_ptp_ts_96[n*PTP_TS_WIDTH +: PTP_TS_WIDTH]), + .rx_ptp_ts(eth_rx_ptp_ts_96[n*PTP_TS_WIDTH +: PTP_TS_WIDTH]), + .tx_axis_ptp_ts(axis_eth_tx_ptp_ts[n*PTP_TS_WIDTH +: PTP_TS_WIDTH]), + .tx_axis_ptp_ts_tag(axis_eth_tx_ptp_ts_tag[n*TX_TAG_WIDTH +: TX_TAG_WIDTH]), + .tx_axis_ptp_ts_valid(axis_eth_tx_ptp_ts_valid[n +: 1]), + + .tx_error_underflow(), + .rx_error_bad_frame(), + .rx_error_bad_fcs(), + + .ifg_delay(8'd12) + ); + + end + +endgenerate + +mqnic_core_axi #( + // FW and board IDs + .FPGA_ID(FPGA_ID), + .FW_ID(FW_ID), + .FW_VER(FW_VER), + .BOARD_ID(BOARD_ID), + .BOARD_VER(BOARD_VER), + .BUILD_DATE(BUILD_DATE), + .GIT_HASH(GIT_HASH), + .RELEASE_INFO(RELEASE_INFO), + + // Structural configuration + .IF_COUNT(IF_COUNT), + .PORTS_PER_IF(PORTS_PER_IF), + .SCHED_PER_IF(SCHED_PER_IF), + + .PORT_COUNT(PORT_COUNT), + + // Clock configuration + .CLK_PERIOD_NS_NUM(CLK_PERIOD_NS_NUM), + .CLK_PERIOD_NS_DENOM(CLK_PERIOD_NS_DENOM), + + // PTP configuration + .PTP_CLK_PERIOD_NS_NUM(PTP_CLK_PERIOD_NS_NUM), + .PTP_CLK_PERIOD_NS_DENOM(PTP_CLK_PERIOD_NS_DENOM), + .PTP_TS_WIDTH(PTP_TS_WIDTH), + .PTP_CLOCK_PIPELINE(PTP_CLOCK_PIPELINE), + .PTP_CLOCK_CDC_PIPELINE(PTP_CLOCK_CDC_PIPELINE), + .PTP_USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK), + .PTP_SEPARATE_TX_CLOCK(0), + .PTP_SEPARATE_RX_CLOCK(0), + .PTP_PORT_CDC_PIPELINE(PTP_PORT_CDC_PIPELINE), + .PTP_PEROUT_ENABLE(PTP_PEROUT_ENABLE), + .PTP_PEROUT_COUNT(PTP_PEROUT_COUNT), + + // Queue manager configuration + .EVENT_QUEUE_OP_TABLE_SIZE(EVENT_QUEUE_OP_TABLE_SIZE), + .TX_QUEUE_OP_TABLE_SIZE(TX_QUEUE_OP_TABLE_SIZE), + .RX_QUEUE_OP_TABLE_SIZE(RX_QUEUE_OP_TABLE_SIZE), + .TX_CPL_QUEUE_OP_TABLE_SIZE(TX_CPL_QUEUE_OP_TABLE_SIZE), + .RX_CPL_QUEUE_OP_TABLE_SIZE(RX_CPL_QUEUE_OP_TABLE_SIZE), + .EVENT_QUEUE_INDEX_WIDTH(EVENT_QUEUE_INDEX_WIDTH), + .TX_QUEUE_INDEX_WIDTH(TX_QUEUE_INDEX_WIDTH), + .RX_QUEUE_INDEX_WIDTH(RX_QUEUE_INDEX_WIDTH), + .TX_CPL_QUEUE_INDEX_WIDTH(TX_CPL_QUEUE_INDEX_WIDTH), + .RX_CPL_QUEUE_INDEX_WIDTH(RX_CPL_QUEUE_INDEX_WIDTH), + .EVENT_QUEUE_PIPELINE(EVENT_QUEUE_PIPELINE), + .TX_QUEUE_PIPELINE(TX_QUEUE_PIPELINE), + .RX_QUEUE_PIPELINE(RX_QUEUE_PIPELINE), + .TX_CPL_QUEUE_PIPELINE(TX_CPL_QUEUE_PIPELINE), + .RX_CPL_QUEUE_PIPELINE(RX_CPL_QUEUE_PIPELINE), + + // TX and RX engine configuration + .TX_DESC_TABLE_SIZE(TX_DESC_TABLE_SIZE), + .RX_DESC_TABLE_SIZE(RX_DESC_TABLE_SIZE), + .RX_INDIR_TBL_ADDR_WIDTH(RX_INDIR_TBL_ADDR_WIDTH), + + // Scheduler configuration + .TX_SCHEDULER_OP_TABLE_SIZE(TX_SCHEDULER_OP_TABLE_SIZE), + .TX_SCHEDULER_PIPELINE(TX_SCHEDULER_PIPELINE), + .TDMA_INDEX_WIDTH(TDMA_INDEX_WIDTH), + + // Interface configuration + .PTP_TS_ENABLE(PTP_TS_ENABLE), + .TX_CPL_ENABLE(PTP_TS_ENABLE), + .TX_CPL_FIFO_DEPTH(TX_CPL_FIFO_DEPTH), + .TX_TAG_WIDTH(TX_TAG_WIDTH), + .TX_CHECKSUM_ENABLE(TX_CHECKSUM_ENABLE), + .RX_HASH_ENABLE(RX_HASH_ENABLE), + .RX_CHECKSUM_ENABLE(RX_CHECKSUM_ENABLE), + .TX_FIFO_DEPTH(TX_FIFO_DEPTH), + .RX_FIFO_DEPTH(RX_FIFO_DEPTH), + .MAX_TX_SIZE(MAX_TX_SIZE), + .MAX_RX_SIZE(MAX_RX_SIZE), + .TX_RAM_SIZE(TX_RAM_SIZE), + .RX_RAM_SIZE(RX_RAM_SIZE), + + // RAM configuration + .DDR_ENABLE(0), + .HBM_ENABLE(0), + + // Application block configuration + .APP_ID(APP_ID), + .APP_ENABLE(APP_ENABLE), + .APP_CTRL_ENABLE(APP_CTRL_ENABLE), + .APP_DMA_ENABLE(APP_DMA_ENABLE), + .APP_AXIS_DIRECT_ENABLE(APP_AXIS_DIRECT_ENABLE), + .APP_AXIS_SYNC_ENABLE(APP_AXIS_SYNC_ENABLE), + .APP_AXIS_IF_ENABLE(APP_AXIS_IF_ENABLE), + .APP_STAT_ENABLE(APP_STAT_ENABLE), + .APP_GPIO_IN_WIDTH(32), + .APP_GPIO_OUT_WIDTH(32), + + // AXI interface configuration (DMA) + .AXI_DATA_WIDTH(AXI_DATA_WIDTH), + .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH), + .AXI_STRB_WIDTH(AXI_STRB_WIDTH), + .AXI_ID_WIDTH(AXI_ID_WIDTH), + + // DMA interface configuration + .DMA_IMM_ENABLE(DMA_IMM_ENABLE), + .DMA_IMM_WIDTH(DMA_IMM_WIDTH), + .DMA_LEN_WIDTH(DMA_LEN_WIDTH), + .DMA_TAG_WIDTH(DMA_TAG_WIDTH), + .RAM_ADDR_WIDTH(RAM_ADDR_WIDTH), + .RAM_PIPELINE(RAM_PIPELINE), + .AXI_DMA_MAX_BURST_LEN(AXI_DMA_MAX_BURST_LEN), + + // Interrupts + .IRQ_COUNT(IRQ_COUNT), + + // AXI lite interface configuration (control) + .AXIL_CTRL_DATA_WIDTH(AXIL_CTRL_DATA_WIDTH), + .AXIL_CTRL_ADDR_WIDTH(AXIL_CTRL_ADDR_WIDTH), + .AXIL_CTRL_STRB_WIDTH(AXIL_CTRL_STRB_WIDTH), + .AXIL_IF_CTRL_ADDR_WIDTH(AXIL_IF_CTRL_ADDR_WIDTH), + .AXIL_CSR_ADDR_WIDTH(AXIL_CSR_ADDR_WIDTH), + .AXIL_CSR_PASSTHROUGH_ENABLE(TDMA_BER_ENABLE), + .RB_NEXT_PTR(RB_BASE_ADDR), + + // AXI lite interface configuration (application control) + .AXIL_APP_CTRL_DATA_WIDTH(AXIL_APP_CTRL_DATA_WIDTH), + .AXIL_APP_CTRL_ADDR_WIDTH(AXIL_APP_CTRL_ADDR_WIDTH), + + // Ethernet interface configuration + .AXIS_DATA_WIDTH(AXIS_ETH_DATA_WIDTH), + .AXIS_KEEP_WIDTH(AXIS_ETH_KEEP_WIDTH), + .AXIS_SYNC_DATA_WIDTH(AXIS_ETH_SYNC_DATA_WIDTH), + .AXIS_TX_USER_WIDTH(AXIS_ETH_TX_USER_WIDTH), + .AXIS_RX_USER_WIDTH(AXIS_ETH_RX_USER_WIDTH), + .AXIS_RX_USE_READY(0), + .AXIS_TX_PIPELINE(AXIS_ETH_TX_PIPELINE), + .AXIS_TX_FIFO_PIPELINE(AXIS_ETH_TX_FIFO_PIPELINE), + .AXIS_TX_TS_PIPELINE(AXIS_ETH_TX_TS_PIPELINE), + .AXIS_RX_PIPELINE(AXIS_ETH_RX_PIPELINE), + .AXIS_RX_FIFO_PIPELINE(AXIS_ETH_RX_FIFO_PIPELINE), + + // Statistics counter subsystem + .STAT_ENABLE(STAT_ENABLE), + .STAT_DMA_ENABLE(STAT_DMA_ENABLE), + .STAT_AXI_ENABLE(STAT_AXI_ENABLE), + .STAT_INC_WIDTH(STAT_INC_WIDTH), + .STAT_ID_WIDTH(STAT_ID_WIDTH) +) +core_inst ( + .clk(clk_250mhz), + .rst(rst_250mhz), + + /* + * Interrupt outputs + */ + .irq(irq), + + /* + * AXI master interface (DMA) + */ + .m_axi_awid(m_axi_awid), + .m_axi_awaddr(m_axi_awaddr), + .m_axi_awlen(m_axi_awlen), + .m_axi_awsize(m_axi_awsize), + .m_axi_awburst(m_axi_awburst), + .m_axi_awlock(m_axi_awlock), + .m_axi_awcache(m_axi_awcache), + .m_axi_awprot(m_axi_awprot), + .m_axi_awvalid(m_axi_awvalid), + .m_axi_awready(m_axi_awready), + .m_axi_wdata(m_axi_wdata), + .m_axi_wstrb(m_axi_wstrb), + .m_axi_wlast(m_axi_wlast), + .m_axi_wvalid(m_axi_wvalid), + .m_axi_wready(m_axi_wready), + .m_axi_bid(m_axi_bid), + .m_axi_bresp(m_axi_bresp), + .m_axi_bvalid(m_axi_bvalid), + .m_axi_bready(m_axi_bready), + .m_axi_arid(m_axi_arid), + .m_axi_araddr(m_axi_araddr), + .m_axi_arlen(m_axi_arlen), + .m_axi_arsize(m_axi_arsize), + .m_axi_arburst(m_axi_arburst), + .m_axi_arlock(m_axi_arlock), + .m_axi_arcache(m_axi_arcache), + .m_axi_arprot(m_axi_arprot), + .m_axi_arvalid(m_axi_arvalid), + .m_axi_arready(m_axi_arready), + .m_axi_rid(m_axi_rid), + .m_axi_rdata(m_axi_rdata), + .m_axi_rresp(m_axi_rresp), + .m_axi_rlast(m_axi_rlast), + .m_axi_rvalid(m_axi_rvalid), + .m_axi_rready(m_axi_rready), + + /* + * AXI-Lite slave interface (control) + */ + .s_axil_ctrl_awaddr(s_axil_ctrl_awaddr), + .s_axil_ctrl_awprot(s_axil_ctrl_awprot), + .s_axil_ctrl_awvalid(s_axil_ctrl_awvalid), + .s_axil_ctrl_awready(s_axil_ctrl_awready), + .s_axil_ctrl_wdata(s_axil_ctrl_wdata), + .s_axil_ctrl_wstrb(s_axil_ctrl_wstrb), + .s_axil_ctrl_wvalid(s_axil_ctrl_wvalid), + .s_axil_ctrl_wready(s_axil_ctrl_wready), + .s_axil_ctrl_bresp(s_axil_ctrl_bresp), + .s_axil_ctrl_bvalid(s_axil_ctrl_bvalid), + .s_axil_ctrl_bready(s_axil_ctrl_bready), + .s_axil_ctrl_araddr(s_axil_ctrl_araddr), + .s_axil_ctrl_arprot(s_axil_ctrl_arprot), + .s_axil_ctrl_arvalid(s_axil_ctrl_arvalid), + .s_axil_ctrl_arready(s_axil_ctrl_arready), + .s_axil_ctrl_rdata(s_axil_ctrl_rdata), + .s_axil_ctrl_rresp(s_axil_ctrl_rresp), + .s_axil_ctrl_rvalid(s_axil_ctrl_rvalid), + .s_axil_ctrl_rready(s_axil_ctrl_rready), + + /* + * AXI-Lite slave interface (application control) + */ + .s_axil_app_ctrl_awaddr(s_axil_app_ctrl_awaddr), + .s_axil_app_ctrl_awprot(s_axil_app_ctrl_awprot), + .s_axil_app_ctrl_awvalid(s_axil_app_ctrl_awvalid), + .s_axil_app_ctrl_awready(s_axil_app_ctrl_awready), + .s_axil_app_ctrl_wdata(s_axil_app_ctrl_wdata), + .s_axil_app_ctrl_wstrb(s_axil_app_ctrl_wstrb), + .s_axil_app_ctrl_wvalid(s_axil_app_ctrl_wvalid), + .s_axil_app_ctrl_wready(s_axil_app_ctrl_wready), + .s_axil_app_ctrl_bresp(s_axil_app_ctrl_bresp), + .s_axil_app_ctrl_bvalid(s_axil_app_ctrl_bvalid), + .s_axil_app_ctrl_bready(s_axil_app_ctrl_bready), + .s_axil_app_ctrl_araddr(s_axil_app_ctrl_araddr), + .s_axil_app_ctrl_arprot(s_axil_app_ctrl_arprot), + .s_axil_app_ctrl_arvalid(s_axil_app_ctrl_arvalid), + .s_axil_app_ctrl_arready(s_axil_app_ctrl_arready), + .s_axil_app_ctrl_rdata(s_axil_app_ctrl_rdata), + .s_axil_app_ctrl_rresp(s_axil_app_ctrl_rresp), + .s_axil_app_ctrl_rvalid(s_axil_app_ctrl_rvalid), + .s_axil_app_ctrl_rready(s_axil_app_ctrl_rready), + + /* + * AXI-Lite master interface (passthrough for NIC control and status) + */ + .m_axil_csr_awaddr(axil_csr_awaddr), + .m_axil_csr_awprot(axil_csr_awprot), + .m_axil_csr_awvalid(axil_csr_awvalid), + .m_axil_csr_awready(axil_csr_awready), + .m_axil_csr_wdata(axil_csr_wdata), + .m_axil_csr_wstrb(axil_csr_wstrb), + .m_axil_csr_wvalid(axil_csr_wvalid), + .m_axil_csr_wready(axil_csr_wready), + .m_axil_csr_bresp(axil_csr_bresp), + .m_axil_csr_bvalid(axil_csr_bvalid), + .m_axil_csr_bready(axil_csr_bready), + .m_axil_csr_araddr(axil_csr_araddr), + .m_axil_csr_arprot(axil_csr_arprot), + .m_axil_csr_arvalid(axil_csr_arvalid), + .m_axil_csr_arready(axil_csr_arready), + .m_axil_csr_rdata(axil_csr_rdata), + .m_axil_csr_rresp(axil_csr_rresp), + .m_axil_csr_rvalid(axil_csr_rvalid), + .m_axil_csr_rready(axil_csr_rready), + + /* + * Control register interface + */ + .ctrl_reg_wr_addr(ctrl_reg_wr_addr), + .ctrl_reg_wr_data(ctrl_reg_wr_data), + .ctrl_reg_wr_strb(ctrl_reg_wr_strb), + .ctrl_reg_wr_en(ctrl_reg_wr_en), + .ctrl_reg_wr_wait(ctrl_reg_wr_wait), + .ctrl_reg_wr_ack(ctrl_reg_wr_ack), + .ctrl_reg_rd_addr(ctrl_reg_rd_addr), + .ctrl_reg_rd_en(ctrl_reg_rd_en), + .ctrl_reg_rd_data(ctrl_reg_rd_data), + .ctrl_reg_rd_wait(ctrl_reg_rd_wait), + .ctrl_reg_rd_ack(ctrl_reg_rd_ack), + + /* + * PTP clock + */ + .ptp_clk(ptp_clk), + .ptp_rst(ptp_rst), + .ptp_sample_clk(ptp_sample_clk), + .ptp_pps(ptp_pps), + .ptp_pps_str(ptp_pps_str), + .ptp_ts_96(ptp_ts_96), + .ptp_ts_step(ptp_ts_step), + .ptp_sync_pps(ptp_sync_pps), + .ptp_sync_ts_96(ptp_sync_ts_96), + .ptp_sync_ts_step(ptp_sync_ts_step), + .ptp_perout_locked(ptp_perout_locked), + .ptp_perout_error(ptp_perout_error), + .ptp_perout_pulse(ptp_perout_pulse), + + /* + * Ethernet + */ + .tx_clk(eth_tx_clk), + .tx_rst(eth_tx_rst), + + .tx_ptp_clk(0), + .tx_ptp_rst(0), + .tx_ptp_ts_96(eth_tx_ptp_ts_96), + .tx_ptp_ts_step(eth_tx_ptp_ts_step), + + .m_axis_tx_tdata(axis_eth_tx_tdata), + .m_axis_tx_tkeep(axis_eth_tx_tkeep), + .m_axis_tx_tvalid(axis_eth_tx_tvalid), + .m_axis_tx_tready(axis_eth_tx_tready), + .m_axis_tx_tlast(axis_eth_tx_tlast), + .m_axis_tx_tuser(axis_eth_tx_tuser), + + .s_axis_tx_cpl_ts(axis_eth_tx_ptp_ts), + .s_axis_tx_cpl_tag(axis_eth_tx_ptp_ts_tag), + .s_axis_tx_cpl_valid(axis_eth_tx_ptp_ts_valid), + .s_axis_tx_cpl_ready(axis_eth_tx_ptp_ts_ready), + + .tx_status(eth_tx_status), + + .rx_clk(eth_rx_clk), + .rx_rst(eth_rx_rst), + + .rx_ptp_clk(0), + .rx_ptp_rst(0), + .rx_ptp_ts_96(eth_rx_ptp_ts_96), + .rx_ptp_ts_step(eth_rx_ptp_ts_step), + + .s_axis_rx_tdata(axis_eth_rx_tdata), + .s_axis_rx_tkeep(axis_eth_rx_tkeep), + .s_axis_rx_tvalid(axis_eth_rx_tvalid), + .s_axis_rx_tready(axis_eth_rx_tready), + .s_axis_rx_tlast(axis_eth_rx_tlast), + .s_axis_rx_tuser(axis_eth_rx_tuser), + + .rx_status(eth_rx_status), + + /* + * DDR + */ + .ddr_clk(0), + .ddr_rst(0), + + .m_axi_ddr_awid(), + .m_axi_ddr_awaddr(), + .m_axi_ddr_awlen(), + .m_axi_ddr_awsize(), + .m_axi_ddr_awburst(), + .m_axi_ddr_awlock(), + .m_axi_ddr_awcache(), + .m_axi_ddr_awprot(), + .m_axi_ddr_awqos(), + .m_axi_ddr_awuser(), + .m_axi_ddr_awvalid(), + .m_axi_ddr_awready(0), + .m_axi_ddr_wdata(), + .m_axi_ddr_wstrb(), + .m_axi_ddr_wlast(), + .m_axi_ddr_wuser(), + .m_axi_ddr_wvalid(), + .m_axi_ddr_wready(0), + .m_axi_ddr_bid(0), + .m_axi_ddr_bresp(0), + .m_axi_ddr_buser(0), + .m_axi_ddr_bvalid(0), + .m_axi_ddr_bready(), + .m_axi_ddr_arid(), + .m_axi_ddr_araddr(), + .m_axi_ddr_arlen(), + .m_axi_ddr_arsize(), + .m_axi_ddr_arburst(), + .m_axi_ddr_arlock(), + .m_axi_ddr_arcache(), + .m_axi_ddr_arprot(), + .m_axi_ddr_arqos(), + .m_axi_ddr_aruser(), + .m_axi_ddr_arvalid(), + .m_axi_ddr_arready(0), + .m_axi_ddr_rid(0), + .m_axi_ddr_rdata(0), + .m_axi_ddr_rresp(0), + .m_axi_ddr_rlast(0), + .m_axi_ddr_ruser(0), + .m_axi_ddr_rvalid(0), + .m_axi_ddr_rready(), + + .ddr_status(0), + + /* + * HBM + */ + .hbm_clk(0), + .hbm_rst(0), + + .m_axi_hbm_awid(), + .m_axi_hbm_awaddr(), + .m_axi_hbm_awlen(), + .m_axi_hbm_awsize(), + .m_axi_hbm_awburst(), + .m_axi_hbm_awlock(), + .m_axi_hbm_awcache(), + .m_axi_hbm_awprot(), + .m_axi_hbm_awqos(), + .m_axi_hbm_awuser(), + .m_axi_hbm_awvalid(), + .m_axi_hbm_awready(0), + .m_axi_hbm_wdata(), + .m_axi_hbm_wstrb(), + .m_axi_hbm_wlast(), + .m_axi_hbm_wuser(), + .m_axi_hbm_wvalid(), + .m_axi_hbm_wready(0), + .m_axi_hbm_bid(0), + .m_axi_hbm_bresp(0), + .m_axi_hbm_buser(0), + .m_axi_hbm_bvalid(0), + .m_axi_hbm_bready(), + .m_axi_hbm_arid(), + .m_axi_hbm_araddr(), + .m_axi_hbm_arlen(), + .m_axi_hbm_arsize(), + .m_axi_hbm_arburst(), + .m_axi_hbm_arlock(), + .m_axi_hbm_arcache(), + .m_axi_hbm_arprot(), + .m_axi_hbm_arqos(), + .m_axi_hbm_aruser(), + .m_axi_hbm_arvalid(), + .m_axi_hbm_arready(0), + .m_axi_hbm_rid(0), + .m_axi_hbm_rdata(0), + .m_axi_hbm_rresp(0), + .m_axi_hbm_rlast(0), + .m_axi_hbm_ruser(0), + .m_axi_hbm_rvalid(0), + .m_axi_hbm_rready(), + + .hbm_status(0), + + /* + * Statistics input + */ + .s_axis_stat_tdata(0), + .s_axis_stat_tid(0), + .s_axis_stat_tvalid(1'b0), + .s_axis_stat_tready(), + + /* + * GPIO + */ + .app_gpio_in(0), + .app_gpio_out(), + + /* + * JTAG + */ + .app_jtag_tdi(1'b0), + .app_jtag_tdo(), + .app_jtag_tms(1'b0), + .app_jtag_tck(1'b0) +); + +endmodule + +`resetall diff --git a/fpga/mqnic/KR260/fpga/rtl/sync_signal.v b/fpga/mqnic/KR260/fpga/rtl/sync_signal.v new file mode 100644 index 000000000..74b855fa1 --- /dev/null +++ b/fpga/mqnic/KR260/fpga/rtl/sync_signal.v @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2014-2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog-2001 + +`resetall +`timescale 1 ns / 1 ps +`default_nettype none + +/* + * Synchronizes an asyncronous signal to a given clock by using a pipeline of + * two registers. + */ +module sync_signal #( + parameter WIDTH=1, // width of the input and output signals + parameter N=2 // depth of synchronizer +)( + input wire clk, + input wire [WIDTH-1:0] in, + output wire [WIDTH-1:0] out +); + +reg [WIDTH-1:0] sync_reg[N-1:0]; + +/* + * The synchronized output is the last register in the pipeline. + */ +assign out = sync_reg[N-1]; + +integer k; + +always @(posedge clk) begin + sync_reg[0] <= in; + for (k = 1; k < N; k = k + 1) begin + sync_reg[k] <= sync_reg[k-1]; + end +end + +endmodule + +`resetall diff --git a/fpga/mqnic/KR260/fpga/tb/fpga_core/Makefile b/fpga/mqnic/KR260/fpga/tb/fpga_core/Makefile new file mode 100644 index 000000000..92943ffaa --- /dev/null +++ b/fpga/mqnic/KR260/fpga/tb/fpga_core/Makefile @@ -0,0 +1,268 @@ +# Copyright 2020-2021, The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of The Regents of the University of California. + +TOPLEVEL_LANG = verilog + +SIM ?= icarus +WAVES ?= 0 + +COCOTB_HDL_TIMEUNIT = 1ns +COCOTB_HDL_TIMEPRECISION = 1ps + +DUT = fpga_core +TOPLEVEL = $(DUT) +MODULE = test_$(DUT) +VERILOG_SOURCES += ../../rtl/$(DUT).v +VERILOG_SOURCES += ../../rtl/common/mqnic_core_axi.v +VERILOG_SOURCES += ../../rtl/common/mqnic_core.v +VERILOG_SOURCES += ../../rtl/common/mqnic_dram_if.v +VERILOG_SOURCES += ../../rtl/common/mqnic_interface.v +VERILOG_SOURCES += ../../rtl/common/mqnic_interface_tx.v +VERILOG_SOURCES += ../../rtl/common/mqnic_interface_rx.v +VERILOG_SOURCES += ../../rtl/common/mqnic_port.v +VERILOG_SOURCES += ../../rtl/common/mqnic_port_tx.v +VERILOG_SOURCES += ../../rtl/common/mqnic_port_rx.v +VERILOG_SOURCES += ../../rtl/common/mqnic_egress.v +VERILOG_SOURCES += ../../rtl/common/mqnic_ingress.v +VERILOG_SOURCES += ../../rtl/common/mqnic_l2_egress.v +VERILOG_SOURCES += ../../rtl/common/mqnic_l2_ingress.v +VERILOG_SOURCES += ../../rtl/common/mqnic_rx_queue_map.v +VERILOG_SOURCES += ../../rtl/common/mqnic_ptp.v +VERILOG_SOURCES += ../../rtl/common/mqnic_ptp_clock.v +VERILOG_SOURCES += ../../rtl/common/mqnic_ptp_perout.v +VERILOG_SOURCES += ../../rtl/common/mqnic_rb_clk_info.v +VERILOG_SOURCES += ../../rtl/common/mqnic_port_map_phy_xgmii.v +VERILOG_SOURCES += ../../rtl/common/cpl_write.v +VERILOG_SOURCES += ../../rtl/common/cpl_op_mux.v +VERILOG_SOURCES += ../../rtl/common/desc_fetch.v +VERILOG_SOURCES += ../../rtl/common/desc_op_mux.v +VERILOG_SOURCES += ../../rtl/common/event_mux.v +VERILOG_SOURCES += ../../rtl/common/queue_manager.v +VERILOG_SOURCES += ../../rtl/common/cpl_queue_manager.v +VERILOG_SOURCES += ../../rtl/common/tx_fifo.v +VERILOG_SOURCES += ../../rtl/common/rx_fifo.v +VERILOG_SOURCES += ../../rtl/common/tx_req_mux.v +VERILOG_SOURCES += ../../rtl/common/tx_engine.v +VERILOG_SOURCES += ../../rtl/common/rx_engine.v +VERILOG_SOURCES += ../../rtl/common/tx_checksum.v +VERILOG_SOURCES += ../../rtl/common/rx_hash.v +VERILOG_SOURCES += ../../rtl/common/rx_checksum.v +VERILOG_SOURCES += ../../rtl/common/rb_drp.v +VERILOG_SOURCES += ../../rtl/common/stats_counter.v +VERILOG_SOURCES += ../../rtl/common/stats_collect.v +VERILOG_SOURCES += ../../rtl/common/stats_dma_if_axi.v +VERILOG_SOURCES += ../../rtl/common/stats_dma_latency.v +VERILOG_SOURCES += ../../rtl/common/mqnic_tx_scheduler_block_rr.v +VERILOG_SOURCES += ../../rtl/common/tx_scheduler_rr.v +VERILOG_SOURCES += ../../rtl/common/tdma_scheduler.v +VERILOG_SOURCES += ../../rtl/common/tdma_ber.v +VERILOG_SOURCES += ../../rtl/common/tdma_ber_ch.v +VERILOG_SOURCES += ../../lib/eth/rtl/eth_mac_10g.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_rx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/axis_xgmii_tx_64.v +VERILOG_SOURCES += ../../lib/eth/rtl/lfsr.v +VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock.v +VERILOG_SOURCES += ../../lib/eth/rtl/ptp_clock_cdc.v +VERILOG_SOURCES += ../../lib/eth/rtl/ptp_perout.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_interconnect.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_crossbar.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_crossbar_addr.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_crossbar_rd.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_crossbar_wr.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_reg_if.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_reg_if_rd.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_reg_if_wr.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_register_rd.v +VERILOG_SOURCES += ../../lib/axi/rtl/axil_register_wr.v +VERILOG_SOURCES += ../../lib/axi/rtl/arbiter.v +VERILOG_SOURCES += ../../lib/axi/rtl/priority_encoder.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_adapter.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_arb_mux.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_async_fifo_adapter.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_demux.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_fifo_adapter.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_pipeline_fifo.v +VERILOG_SOURCES += ../../lib/axis/rtl/axis_register.v +VERILOG_SOURCES += ../../lib/pcie/rtl/irq_rate_limit.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_axi.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_axi_rd.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_axi_wr.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_rd.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_mux_wr.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_if_desc_mux.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_ram_demux_rd.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_ram_demux_wr.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_psdpram.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_sink.v +VERILOG_SOURCES += ../../lib/pcie/rtl/dma_client_axis_source.v +VERILOG_SOURCES += ../../lib/pcie/rtl/pulse_merge.v + +# module parameters + +# Structural configuration +export PARAM_IF_COUNT := 1 +export PARAM_PORTS_PER_IF := 1 +export PARAM_SCHED_PER_IF := $(PARAM_PORTS_PER_IF) +export PARAM_PORT_MASK := 0 + +# Clock configuration +export PARAM_CLK_PERIOD_NS_NUM := 4 +export PARAM_CLK_PERIOD_NS_DENOM := 1 + +# PTP configuration +export PARAM_PTP_CLK_PERIOD_NS_NUM := 32 +export PARAM_PTP_CLK_PERIOD_NS_DENOM := 5 +export PARAM_PTP_CLOCK_PIPELINE := 0 +export PARAM_PTP_CLOCK_CDC_PIPELINE := 0 +export PARAM_PTP_USE_SAMPLE_CLOCK := 1 +export PARAM_PTP_PORT_CDC_PIPELINE := 0 +export PARAM_PTP_PEROUT_ENABLE := 1 +export PARAM_PTP_PEROUT_COUNT := 1 + +# Queue manager configuration +export PARAM_EVENT_QUEUE_OP_TABLE_SIZE := 32 +export PARAM_TX_QUEUE_OP_TABLE_SIZE := 32 +export PARAM_RX_QUEUE_OP_TABLE_SIZE := 32 +export PARAM_TX_CPL_QUEUE_OP_TABLE_SIZE := $(PARAM_TX_QUEUE_OP_TABLE_SIZE) +export PARAM_RX_CPL_QUEUE_OP_TABLE_SIZE := $(PARAM_RX_QUEUE_OP_TABLE_SIZE) +export PARAM_EVENT_QUEUE_INDEX_WIDTH := 2 +export PARAM_TX_QUEUE_INDEX_WIDTH := 5 +export PARAM_RX_QUEUE_INDEX_WIDTH := 5 +export PARAM_TX_CPL_QUEUE_INDEX_WIDTH := $(PARAM_TX_QUEUE_INDEX_WIDTH) +export PARAM_RX_CPL_QUEUE_INDEX_WIDTH := $(PARAM_RX_QUEUE_INDEX_WIDTH) +export PARAM_EVENT_QUEUE_PIPELINE := 3 +export PARAM_TX_QUEUE_PIPELINE := $(shell python -c "print(3 + max($(PARAM_TX_QUEUE_INDEX_WIDTH)-12, 0))") +export PARAM_RX_QUEUE_PIPELINE := $(shell python -c "print(3 + max($(PARAM_RX_QUEUE_INDEX_WIDTH)-12, 0))") +export PARAM_TX_CPL_QUEUE_PIPELINE := $(PARAM_TX_QUEUE_PIPELINE) +export PARAM_RX_CPL_QUEUE_PIPELINE := $(PARAM_RX_QUEUE_PIPELINE) + +# TX and RX engine configuration +export PARAM_TX_DESC_TABLE_SIZE := 32 +export PARAM_RX_DESC_TABLE_SIZE := 32 +export PARAM_RX_INDIR_TBL_ADDR_WIDTH := $(shell python -c "print(min($(PARAM_RX_QUEUE_INDEX_WIDTH), 8))") + +# Scheduler configuration +export PARAM_TX_SCHEDULER_OP_TABLE_SIZE := $(PARAM_TX_DESC_TABLE_SIZE) +export PARAM_TX_SCHEDULER_PIPELINE := $(PARAM_TX_QUEUE_PIPELINE) +export PARAM_TDMA_INDEX_WIDTH := 6 + +# Interface configuration +export PARAM_PTP_TS_ENABLE := 1 +export PARAM_TX_CPL_FIFO_DEPTH := 32 +export PARAM_TX_CHECKSUM_ENABLE := 1 +export PARAM_RX_HASH_ENABLE := 1 +export PARAM_RX_CHECKSUM_ENABLE := 1 +export PARAM_TX_FIFO_DEPTH := 32768 +export PARAM_RX_FIFO_DEPTH := 32768 +export PARAM_MAX_TX_SIZE := 9214 +export PARAM_MAX_RX_SIZE := 9214 +export PARAM_TX_RAM_SIZE := 32768 +export PARAM_RX_RAM_SIZE := 32768 + +# Application block configuration +export PARAM_APP_ID := $(shell echo $$((0x00000000)) ) +export PARAM_APP_ENABLE := 0 +export PARAM_APP_CTRL_ENABLE := 1 +export PARAM_APP_DMA_ENABLE := 1 +export PARAM_APP_AXIS_DIRECT_ENABLE := 1 +export PARAM_APP_AXIS_SYNC_ENABLE := 1 +export PARAM_APP_AXIS_IF_ENABLE := 1 +export PARAM_APP_STAT_ENABLE := 1 + +# AXI DMA interface configuration +export PARAM_AXI_DATA_WIDTH := 128 +export PARAM_AXI_ADDR_WIDTH := 40 +export PARAM_AXI_ID_WIDTH := 4 + +# DMA interface configuration +export PARAM_DMA_IMM_ENABLE := 0 +export PARAM_DMA_IMM_WIDTH := 32 +export PARAM_DMA_LEN_WIDTH := 16 +export PARAM_DMA_TAG_WIDTH := 16 +export PARAM_RAM_ADDR_WIDTH := $(shell python -c "print((max($(PARAM_TX_RAM_SIZE), $(PARAM_RX_RAM_SIZE))-1).bit_length())") +export PARAM_RAM_PIPELINE := 2 +export PARAM_AXI_DMA_MAX_BURST_LEN := 16 + +# AXI lite interface configuration (control) +export PARAM_AXIL_CTRL_DATA_WIDTH := 32 +export PARAM_AXIL_CTRL_ADDR_WIDTH := 24 + +# AXI lite interface configuration (application control) +export PARAM_AXIL_APP_CTRL_DATA_WIDTH := $(PARAM_AXIL_CTRL_DATA_WIDTH) +export PARAM_AXIL_APP_CTRL_ADDR_WIDTH := 24 + +# Ethernet interface configuration +export PARAM_AXIS_ETH_TX_PIPELINE := 0 +export PARAM_AXIS_ETH_TX_FIFO_PIPELINE := 2 +export PARAM_AXIS_ETH_TX_TS_PIPELINE := 0 +export PARAM_AXIS_ETH_RX_PIPELINE := 0 +export PARAM_AXIS_ETH_RX_FIFO_PIPELINE := 2 + +# Statistics counter subsystem +export PARAM_STAT_ENABLE := 1 +export PARAM_STAT_DMA_ENABLE := 1 +export PARAM_STAT_AXI_ENABLE := 1 +export PARAM_STAT_INC_WIDTH := 24 +export PARAM_STAT_ID_WIDTH := 12 + +ifeq ($(SIM), icarus) + PLUSARGS += -fst + + COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(TOPLEVEL).$(subst PARAM_,,$(v))=$($(v))) + + ifeq ($(WAVES), 1) + VERILOG_SOURCES += iverilog_dump.v + COMPILE_ARGS += -s iverilog_dump + endif +else ifeq ($(SIM), verilator) + COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH + + COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v))) + + ifeq ($(WAVES), 1) + COMPILE_ARGS += --trace-fst + endif +endif + +include $(shell cocotb-config --makefiles)/Makefile.sim + +iverilog_dump.v: + echo 'module iverilog_dump();' > $@ + echo 'initial begin' >> $@ + echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ + echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ + echo 'end' >> $@ + echo 'endmodule' >> $@ + +clean:: + @rm -rf iverilog_dump.v + @rm -rf dump.fst $(TOPLEVEL).fst diff --git a/fpga/mqnic/KR260/fpga/tb/fpga_core/mqnic.py b/fpga/mqnic/KR260/fpga/tb/fpga_core/mqnic.py new file mode 100644 index 000000000..8bb7e103e --- /dev/null +++ b/fpga/mqnic/KR260/fpga/tb/fpga_core/mqnic.py @@ -0,0 +1,1721 @@ +""" + +Copyright 2019, The Regents of the University of California. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS +IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of The Regents of the University of California. + +""" + +import datetime +from collections import deque + +import cocotb +from cocotb.log import SimLog +from cocotb.queue import Queue +from cocotb.triggers import Event, Edge, RisingEdge + +from cocotbext.axi import Window + +import struct + +MQNIC_MAX_EQ = 1 +MQNIC_MAX_TXQ = 32 +MQNIC_MAX_TX_CQ = MQNIC_MAX_TXQ +MQNIC_MAX_RXQ = 8 +MQNIC_MAX_RX_CQ = MQNIC_MAX_RXQ + +# Register blocks +MQNIC_RB_REG_TYPE = 0x00 +MQNIC_RB_REG_VER = 0x04 +MQNIC_RB_REG_NEXT_PTR = 0x08 + +MQNIC_RB_FW_ID_TYPE = 0xFFFFFFFF +MQNIC_RB_FW_ID_VER = 0x00000100 +MQNIC_RB_FW_ID_REG_FPGA_ID = 0x0C +MQNIC_RB_FW_ID_REG_FW_ID = 0x10 +MQNIC_RB_FW_ID_REG_FW_VER = 0x14 +MQNIC_RB_FW_ID_REG_BOARD_ID = 0x18 +MQNIC_RB_FW_ID_REG_BOARD_VER = 0x1C +MQNIC_RB_FW_ID_REG_BUILD_DATE = 0x20 +MQNIC_RB_FW_ID_REG_GIT_HASH = 0x24 +MQNIC_RB_FW_ID_REG_REL_INFO = 0x28 + +MQNIC_RB_GPIO_TYPE = 0x0000C100 +MQNIC_RB_GPIO_VER = 0x00000100 +MQNIC_RB_GPIO_REG_GPIO_IN = 0x0C +MQNIC_RB_GPIO_REG_GPIO_OUT = 0x10 + +MQNIC_RB_I2C_TYPE = 0x0000C110 +MQNIC_RB_I2C_VER = 0x00000100 +MQNIC_RB_I2C_REG_CTRL = 0x0C + +MQNIC_RB_SPI_FLASH_TYPE = 0x0000C120 +MQNIC_RB_SPI_FLASH_VER = 0x00000100 +MQNIC_RB_SPI_FLASH_REG_FORMAT = 0x0C +MQNIC_RB_SPI_FLASH_REG_CTRL_0 = 0x10 +MQNIC_RB_SPI_FLASH_REG_CTRL_1 = 0x14 + +MQNIC_RB_BPI_FLASH_TYPE = 0x0000C121 +MQNIC_RB_BPI_FLASH_VER = 0x00000100 +MQNIC_RB_BPI_FLASH_REG_FORMAT = 0x0C +MQNIC_RB_BPI_FLASH_REG_ADDR = 0x10 +MQNIC_RB_BPI_FLASH_REG_DATA = 0x14 +MQNIC_RB_BPI_FLASH_REG_CTRL = 0x18 + +MQNIC_RB_ALVEO_BMC_TYPE = 0x0000C140 +MQNIC_RB_ALVEO_BMC_VER = 0x00000100 +MQNIC_RB_ALVEO_BMC_REG_ADDR = 0x0C +MQNIC_RB_ALVEO_BMC_REG_DATA = 0x10 + +MQNIC_RB_GECKO_BMC_TYPE = 0x0000C141 +MQNIC_RB_GECKO_BMC_VER = 0x00000100 +MQNIC_RB_GECKO_BMC_REG_STATUS = 0x0C +MQNIC_RB_GECKO_BMC_REG_DATA = 0x10 +MQNIC_RB_GECKO_BMC_REG_CMD = 0x14 + +MQNIC_RB_STATS_TYPE = 0x0000C006 +MQNIC_RB_STATS_VER = 0x00000100 +MQNIC_RB_STATS_REG_OFFSET = 0x0C +MQNIC_RB_STATS_REG_COUNT = 0x10 +MQNIC_RB_STATS_REG_STRIDE = 0x14 +MQNIC_RB_STATS_REG_FLAGS = 0x18 + +MQNIC_RB_IRQ_TYPE = 0x0000C007 +MQNIC_RB_IRQ_VER = 0x00000100 + +MQNIC_RB_CLK_INFO_TYPE = 0x0000C008 +MQNIC_RB_CLK_INFO_VER = 0x00000100 +MQNIC_RB_CLK_INFO_COUNT = 0x0C +MQNIC_RB_CLK_INFO_REF_NOM_PER = 0x10 +MQNIC_RB_CLK_INFO_CLK_NOM_PER = 0x18 +MQNIC_RB_CLK_INFO_CLK_FREQ = 0x1C +MQNIC_RB_CLK_INFO_FREQ_BASE = 0x20 + +MQNIC_RB_PHC_TYPE = 0x0000C080 +MQNIC_RB_PHC_VER = 0x00000100 +MQNIC_RB_PHC_REG_CTRL = 0x0C +MQNIC_RB_PHC_REG_CUR_FNS = 0x10 +MQNIC_RB_PHC_REG_CUR_NS = 0x14 +MQNIC_RB_PHC_REG_CUR_SEC_L = 0x18 +MQNIC_RB_PHC_REG_CUR_SEC_H = 0x1C +MQNIC_RB_PHC_REG_GET_FNS = 0x20 +MQNIC_RB_PHC_REG_GET_NS = 0x24 +MQNIC_RB_PHC_REG_GET_SEC_L = 0x28 +MQNIC_RB_PHC_REG_GET_SEC_H = 0x2C +MQNIC_RB_PHC_REG_SET_FNS = 0x30 +MQNIC_RB_PHC_REG_SET_NS = 0x34 +MQNIC_RB_PHC_REG_SET_SEC_L = 0x38 +MQNIC_RB_PHC_REG_SET_SEC_H = 0x3C +MQNIC_RB_PHC_REG_PERIOD_FNS = 0x40 +MQNIC_RB_PHC_REG_PERIOD_NS = 0x44 +MQNIC_RB_PHC_REG_NOM_PERIOD_FNS = 0x48 +MQNIC_RB_PHC_REG_NOM_PERIOD_NS = 0x4C +MQNIC_RB_PHC_REG_ADJ_FNS = 0x50 +MQNIC_RB_PHC_REG_ADJ_NS = 0x54 +MQNIC_RB_PHC_REG_ADJ_COUNT = 0x58 +MQNIC_RB_PHC_REG_ADJ_ACTIVE = 0x5C + +MQNIC_RB_PHC_PEROUT_TYPE = 0x0000C081 +MQNIC_RB_PHC_PEROUT_VER = 0x00000100 +MQNIC_RB_PHC_PEROUT_REG_CTRL = 0x0C +MQNIC_RB_PHC_PEROUT_REG_START_FNS = 0x10 +MQNIC_RB_PHC_PEROUT_REG_START_NS = 0x14 +MQNIC_RB_PHC_PEROUT_REG_START_SEC_L = 0x18 +MQNIC_RB_PHC_PEROUT_REG_START_SEC_H = 0x1C +MQNIC_RB_PHC_PEROUT_REG_PERIOD_FNS = 0x20 +MQNIC_RB_PHC_PEROUT_REG_PERIOD_NS = 0x24 +MQNIC_RB_PHC_PEROUT_REG_PERIOD_SEC_L = 0x28 +MQNIC_RB_PHC_PEROUT_REG_PERIOD_SEC_H = 0x2C +MQNIC_RB_PHC_PEROUT_REG_WIDTH_FNS = 0x30 +MQNIC_RB_PHC_PEROUT_REG_WIDTH_NS = 0x34 +MQNIC_RB_PHC_PEROUT_REG_WIDTH_SEC_L = 0x38 +MQNIC_RB_PHC_PEROUT_REG_WIDTH_SEC_H = 0x3C + +MQNIC_RB_IF_TYPE = 0x0000C000 +MQNIC_RB_IF_VER = 0x00000100 +MQNIC_RB_IF_REG_OFFSET = 0x0C +MQNIC_RB_IF_REG_COUNT = 0x10 +MQNIC_RB_IF_REG_STRIDE = 0x14 +MQNIC_RB_IF_REG_CSR_OFFSET = 0x18 + +MQNIC_RB_IF_CTRL_TYPE = 0x0000C001 +MQNIC_RB_IF_CTRL_VER = 0x00000400 +MQNIC_RB_IF_CTRL_REG_FEATURES = 0x0C +MQNIC_RB_IF_CTRL_REG_PORT_COUNT = 0x10 +MQNIC_RB_IF_CTRL_REG_SCHED_COUNT = 0x14 +MQNIC_RB_IF_CTRL_REG_MAX_TX_MTU = 0x20 +MQNIC_RB_IF_CTRL_REG_MAX_RX_MTU = 0x24 +MQNIC_RB_IF_CTRL_REG_TX_MTU = 0x28 +MQNIC_RB_IF_CTRL_REG_RX_MTU = 0x2C + +MQNIC_IF_FEATURE_RSS = (1 << 0) +MQNIC_IF_FEATURE_PTP_TS = (1 << 4) +MQNIC_IF_FEATURE_TX_CSUM = (1 << 8) +MQNIC_IF_FEATURE_RX_CSUM = (1 << 9) +MQNIC_IF_FEATURE_RX_HASH = (1 << 10) + +MQNIC_RB_RX_QUEUE_MAP_TYPE = 0x0000C090 +MQNIC_RB_RX_QUEUE_MAP_VER = 0x00000200 +MQNIC_RB_RX_QUEUE_MAP_REG_CFG = 0x0C +MQNIC_RB_RX_QUEUE_MAP_CH_OFFSET = 0x10 +MQNIC_RB_RX_QUEUE_MAP_CH_STRIDE = 0x10 +MQNIC_RB_RX_QUEUE_MAP_CH_REG_OFFSET = 0x00 +MQNIC_RB_RX_QUEUE_MAP_CH_REG_RSS_MASK = 0x04 +MQNIC_RB_RX_QUEUE_MAP_CH_REG_APP_MASK = 0x08 + +MQNIC_RB_EQM_TYPE = 0x0000C010 +MQNIC_RB_EQM_VER = 0x00000200 +MQNIC_RB_EQM_REG_OFFSET = 0x0C +MQNIC_RB_EQM_REG_COUNT = 0x10 +MQNIC_RB_EQM_REG_STRIDE = 0x14 + +MQNIC_RB_TX_QM_TYPE = 0x0000C020 +MQNIC_RB_TX_QM_VER = 0x00000200 +MQNIC_RB_TX_QM_REG_OFFSET = 0x0C +MQNIC_RB_TX_QM_REG_COUNT = 0x10 +MQNIC_RB_TX_QM_REG_STRIDE = 0x14 + +MQNIC_RB_TX_CQM_TYPE = 0x0000C030 +MQNIC_RB_TX_CQM_VER = 0x00000200 +MQNIC_RB_TX_CQM_REG_OFFSET = 0x0C +MQNIC_RB_TX_CQM_REG_COUNT = 0x10 +MQNIC_RB_TX_CQM_REG_STRIDE = 0x14 + +MQNIC_RB_RX_QM_TYPE = 0x0000C021 +MQNIC_RB_RX_QM_VER = 0x00000200 +MQNIC_RB_RX_QM_REG_OFFSET = 0x0C +MQNIC_RB_RX_QM_REG_COUNT = 0x10 +MQNIC_RB_RX_QM_REG_STRIDE = 0x14 + +MQNIC_RB_RX_CQM_TYPE = 0x0000C031 +MQNIC_RB_RX_CQM_VER = 0x00000200 +MQNIC_RB_RX_CQM_REG_OFFSET = 0x0C +MQNIC_RB_RX_CQM_REG_COUNT = 0x10 +MQNIC_RB_RX_CQM_REG_STRIDE = 0x14 + +MQNIC_RB_PORT_TYPE = 0x0000C002 +MQNIC_RB_PORT_VER = 0x00000200 +MQNIC_RB_PORT_REG_OFFSET = 0x0C + +MQNIC_RB_PORT_CTRL_TYPE = 0x0000C003 +MQNIC_RB_PORT_CTRL_VER = 0x00000200 +MQNIC_RB_PORT_CTRL_REG_FEATURES = 0x0C +MQNIC_RB_PORT_CTRL_REG_TX_STATUS = 0x10 +MQNIC_RB_PORT_CTRL_REG_RX_STATUS = 0x14 + +MQNIC_RB_SCHED_BLOCK_TYPE = 0x0000C004 +MQNIC_RB_SCHED_BLOCK_VER = 0x00000300 +MQNIC_RB_SCHED_BLOCK_REG_OFFSET = 0x0C + +MQNIC_RB_SCHED_RR_TYPE = 0x0000C040 +MQNIC_RB_SCHED_RR_VER = 0x00000100 +MQNIC_RB_SCHED_RR_REG_OFFSET = 0x0C +MQNIC_RB_SCHED_RR_REG_CH_COUNT = 0x10 +MQNIC_RB_SCHED_RR_REG_CH_STRIDE = 0x14 +MQNIC_RB_SCHED_RR_REG_CTRL = 0x18 +MQNIC_RB_SCHED_RR_REG_DEST = 0x1C + +MQNIC_RB_SCHED_CTRL_TDMA_TYPE = 0x0000C050 +MQNIC_RB_SCHED_CTRL_TDMA_VER = 0x00000100 +MQNIC_RB_SCHED_CTRL_TDMA_REG_OFFSET = 0x0C +MQNIC_RB_SCHED_CTRL_TDMA_REG_CH_COUNT = 0x10 +MQNIC_RB_SCHED_CTRL_TDMA_REG_CH_STRIDE = 0x14 +MQNIC_RB_SCHED_CTRL_TDMA_REG_CTRL = 0x18 +MQNIC_RB_SCHED_CTRL_TDMA_REG_TS_COUNT = 0x1C + +MQNIC_RB_TDMA_SCH_TYPE = 0x0000C060 +MQNIC_RB_TDMA_SCH_VER = 0x00000100 +MQNIC_RB_TDMA_SCH_REG_TS_COUNT = 0x0C +MQNIC_RB_TDMA_SCH_REG_CTRL = 0x10 +MQNIC_RB_TDMA_SCH_REG_STATUS = 0x14 +MQNIC_RB_TDMA_SCH_REG_SCH_START_FNS = 0x20 +MQNIC_RB_TDMA_SCH_REG_SCH_START_NS = 0x24 +MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_L = 0x28 +MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_H = 0x2C +MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_FNS = 0x30 +MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_NS = 0x34 +MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_L = 0x38 +MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_H = 0x3C +MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_FNS = 0x40 +MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_NS = 0x44 +MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_L = 0x48 +MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_H = 0x4C +MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_FNS = 0x50 +MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_NS = 0x54 +MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_L = 0x58 +MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_H = 0x5C + +MQNIC_RB_APP_INFO_TYPE = 0x0000C005 +MQNIC_RB_APP_INFO_VER = 0x00000200 +MQNIC_RB_APP_INFO_REG_ID = 0x0C + +MQNIC_QUEUE_BASE_ADDR_REG = 0x00 +MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG = 0x08 +MQNIC_QUEUE_CPL_QUEUE_INDEX_REG = 0x0C +MQNIC_QUEUE_HEAD_PTR_REG = 0x10 +MQNIC_QUEUE_TAIL_PTR_REG = 0x18 + +MQNIC_QUEUE_ACTIVE_MASK = 0x80000000 + +MQNIC_CQ_BASE_ADDR_REG = 0x00 +MQNIC_CQ_ACTIVE_LOG_SIZE_REG = 0x08 +MQNIC_CQ_INTERRUPT_INDEX_REG = 0x0C +MQNIC_CQ_HEAD_PTR_REG = 0x10 +MQNIC_CQ_TAIL_PTR_REG = 0x18 + +MQNIC_CQ_ACTIVE_MASK = 0x80000000 + +MQNIC_CQ_ARM_MASK = 0x80000000 +MQNIC_CQ_CONT_MASK = 0x40000000 + +MQNIC_EQ_BASE_ADDR_REG = 0x00 +MQNIC_EQ_ACTIVE_LOG_SIZE_REG = 0x08 +MQNIC_EQ_INTERRUPT_INDEX_REG = 0x0C +MQNIC_EQ_HEAD_PTR_REG = 0x10 +MQNIC_EQ_TAIL_PTR_REG = 0x18 + +MQNIC_EQ_ACTIVE_MASK = 0x80000000 + +MQNIC_EQ_ARM_MASK = 0x80000000 +MQNIC_EQ_CONT_MASK = 0x40000000 + +MQNIC_EVENT_TYPE_TX_CPL = 0x0000 +MQNIC_EVENT_TYPE_RX_CPL = 0x0001 + +MQNIC_DESC_SIZE = 16 +MQNIC_CPL_SIZE = 32 +MQNIC_EVENT_SIZE = 32 + + +class RegBlock(Window): + def __init__(self, parent, offset, size, base=0, **kwargs): + super().__init__(parent, offset, size, base, **kwargs) + self._offset = offset + self.type = 0 + self.version = 0 + + +class RegBlockList: + def __init__(self): + self.blocks = [] + + async def enumerate_reg_blocks(self, window, offset=0): + while True: + rb_type = await window.read_dword(offset+MQNIC_RB_REG_TYPE) + rb_version = await window.read_dword(offset+MQNIC_RB_REG_VER) + rb = window.create_window(offset, window_type=RegBlock) + rb.type = rb_type + rb.version = rb_version + print(f"Block ID {rb_type:#010x} version {rb_version:#010x} at offset {offset:#010x}") + self.blocks.append(rb) + offset = await window.read_dword(offset+MQNIC_RB_REG_NEXT_PTR) + if offset == 0: + return + assert offset & 0x3 == 0, "Register block not aligned" + for block in self.blocks: + assert block.offset != offset, "Register blocks form a loop" + + def find(self, rb_type, version=None, index=0): + for block in self.blocks: + if block.type == rb_type and (not version or block.version == version): + if index <= 0: + return block + else: + index -= 1 + return None + + def __getitem__(self, key): + return self.blocks[key] + + def __len__(self): + return len(self.blocks) + + +class Packet: + def __init__(self, data=b''): + self.data = data + self.queue = None + self.timestamp_s = None + self.timestamp_ns = None + self.rx_checksum = None + + def __repr__(self): + return ( + f'{type(self).__name__}(data={self.data}, ' + f'queue={self.queue}, ' + f'timestamp_s={self.timestamp_s}, ' + f'timestamp_ns={self.timestamp_ns}, ' + f'rx_checksum={self.rx_checksum:#06x})' + ) + + def __iter__(self): + return self.data.__iter__() + + def __len__(self): + return len(self.data) + + def __bytes__(self): + return bytes(self.data) + + +class Eq: + def __init__(self, interface, eqn, hw_regs): + self.interface = interface + self.log = interface.log + self.driver = interface.driver + self.log_size = 0 + self.size = 0 + self.size_mask = 0 + self.stride = 0 + self.eqn = eqn + self.active = False + + self.buf_size = 0 + self.buf_region = None + self.buf_dma = 0 + self.buf = None + + self.irq = None + + self.head_ptr = 0 + self.tail_ptr = 0 + + self.hw_ptr_mask = 0xffff + self.hw_regs = hw_regs + + async def init(self): + self.log.info("Init EQ %d (interface %d)", self.eqn, self.interface.index) + + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, 0) # active, log size + + async def alloc(self, size, stride): + if self.active: + raise Exception("Cannot allocate active ring") + if self.buf: + raise Exception("Already allocated") + + self.log_size = size.bit_length() - 1 + self.size = 2**self.log_size + self.size_mask = self.size-1 + self.stride = stride + + self.buf_size = self.size*self.stride + self.buf_region = self.driver.pool.alloc_region(self.buf_size) + self.buf_dma = self.buf_region.get_absolute_address(0) + self.buf = self.buf_region.mem + + self.head_ptr = 0 + self.tail_ptr = 0 + + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_EQ_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_EQ_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_EQ_INTERRUPT_INDEX_REG, 0) # interrupt index + await self.hw_regs.write_dword(MQNIC_EQ_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_EQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size + + async def free(self): + await self.deactivate() + + if self.buf: + # TODO + pass + + async def activate(self, irq): + self.log.info("Activate Eq %d (interface %d)", self.eqn, self.interface.index) + + await self.deactivate() + + self.irq = irq + + self.head_ptr = 0 + self.tail_ptr = 0 + + self.buf[0:self.buf_size] = b'\x00'*self.buf_size + + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_EQ_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_EQ_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_EQ_INTERRUPT_INDEX_REG, irq) # interrupt index + await self.hw_regs.write_dword(MQNIC_EQ_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_EQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_EQ_ACTIVE_MASK) # active, log size + + self.active = True + + async def deactivate(self): + await self.hw_regs.write_dword(MQNIC_EQ_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size + await self.hw_regs.write_dword(MQNIC_EQ_INTERRUPT_INDEX_REG, 0) # interrupt index + + self.irq = None + + self.active = False + + async def read_head_ptr(self): + val = await self.hw_regs.read_dword(MQNIC_EQ_HEAD_PTR_REG) + self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask + + async def write_tail_ptr(self): + await self.hw_regs.write_dword(MQNIC_EQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) + + async def arm(self): + if not self.active: + return + + await self.hw_regs.write_dword(MQNIC_EQ_INTERRUPT_INDEX_REG, self.irq | MQNIC_EQ_ARM_MASK) # interrupt index + + async def process_eq(self): + if not self.interface.port_up: + return + + self.log.info("Process EQ") + + eq_tail_ptr = self.tail_ptr + eq_index = eq_tail_ptr & self.size_mask + + while True: + event_data = struct.unpack_from("> 32) # base address + await self.hw_regs.write_dword(MQNIC_CQ_INTERRUPT_INDEX_REG, 0) # event index + await self.hw_regs.write_dword(MQNIC_CQ_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_CQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_CQ_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size + + async def free(self): + await self.deactivate() + + if self.buf: + # TODO + pass + + async def activate(self, eq): + self.log.info("Activate CQ %d (interface %d)", self.cqn, self.interface.index) + + await self.deactivate() + + self.eq = eq + + self.head_ptr = 0 + self.tail_ptr = 0 + + self.buf[0:self.buf_size] = b'\x00'*self.buf_size + + await self.hw_regs.write_dword(MQNIC_CQ_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_CQ_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_CQ_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_CQ_INTERRUPT_INDEX_REG, eq.eqn) # event index + await self.hw_regs.write_dword(MQNIC_CQ_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_CQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_CQ_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_CQ_ACTIVE_MASK) # active, log size + + self.active = True + + async def deactivate(self): + await self.hw_regs.write_dword(MQNIC_CQ_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size + await self.hw_regs.write_dword(MQNIC_CQ_INTERRUPT_INDEX_REG, 0) # event index + + self.eq = None + + self.active = False + + async def read_head_ptr(self): + val = await self.hw_regs.read_dword(MQNIC_CQ_HEAD_PTR_REG) + self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask + + async def write_tail_ptr(self): + await self.hw_regs.write_dword(MQNIC_CQ_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) + + async def arm(self): + if not self.active: + return + + await self.hw_regs.write_dword(MQNIC_CQ_INTERRUPT_INDEX_REG, self.eq.eqn | MQNIC_CQ_ARM_MASK) # event index + + +class Txq: + def __init__(self, interface, index, hw_regs): + self.interface = interface + self.log = interface.log + self.driver = interface.driver + self.log_queue_size = 0 + self.log_desc_block_size = 0 + self.desc_block_size = 0 + self.size = 0 + self.size_mask = 0 + self.full_size = 0 + self.stride = 0 + self.index = index + self.active = False + + self.buf_size = 0 + self.buf_region = None + self.buf_dma = 0 + self.buf = None + + self.cq = None + + self.head_ptr = 0 + self.tail_ptr = 0 + + self.clean_event = Event() + + self.packets = 0 + self.bytes = 0 + + self.hw_ptr_mask = 0xffff + self.hw_regs = hw_regs + + async def init(self): + self.log.info("Init TXQ %d (interface %d)", self.index, self.interface.index) + + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size + + async def alloc(self, size, stride): + if self.active: + raise Exception("Cannot allocate active ring") + if self.buf: + raise Exception("Already allocated") + + self.log_queue_size = size.bit_length() - 1 + self.log_desc_block_size = int(stride/MQNIC_DESC_SIZE).bit_length() - 1 + self.desc_block_size = 2**self.log_desc_block_size + self.size = 2**self.log_queue_size + self.size_mask = self.size-1 + self.full_size = self.size >> 1 + self.stride = stride + + self.tx_info = [None]*self.size + + self.buf_size = self.size*self.stride + self.buf_region = self.driver.pool.alloc_region(self.buf_size) + self.buf_dma = self.buf_region.get_absolute_address(0) + self.buf = self.buf_region.mem + + self.head_ptr = 0 + self.tail_ptr = 0 + + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size + + async def free(self): + await self.deactivate() + + if self.buf: + # TODO + pass + + async def activate(self, cq): + self.log.info("Activate TXQ %d (interface %d)", self.index, self.interface.index) + + await self.deactivate() + + self.cq = cq + self.cq.src_ring = self + self.cq.handler = Txq.process_tx_cq + + self.head_ptr = 0 + self.tail_ptr = 0 + + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cq.cqn) # completion queue index + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size + + self.active = True + + async def deactivate(self): + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size + + if self.cq: + self.cq.src_ring = None + self.cq.handler = None + + self.cq = None + + self.active = False + + def empty(self): + return self.head_ptr == self.tail_ptr + + def full(self): + return self.head_ptr - self.tail_ptr >= self.full_size + + async def read_tail_ptr(self): + val = await self.hw_regs.read_dword(MQNIC_QUEUE_TAIL_PTR_REG) + self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask + + async def write_head_ptr(self): + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) + + def free_desc(self, index): + pkt = self.tx_info[index] + self.driver.free_pkt(pkt) + self.tx_info[index] = None + + def free_buf(self): + while not self.empty(): + index = self.tail_ptr & self.size_mask + self.free_desc(index) + self.tail_ptr += 1 + + @staticmethod + async def process_tx_cq(cq): + interface = cq.interface + + interface.log.info("Process TX CQ %d for TXQ %d (interface %d)", cq.cqn, cq.src_ring.index, interface.index) + + ring = cq.src_ring + + if not interface.port_up: + return + + # process completion queue + cq_tail_ptr = cq.tail_ptr + cq_index = cq_tail_ptr & cq.size_mask + + while True: + cpl_data = struct.unpack_from("> 1 + self.stride = stride + + self.rx_info = [None]*self.size + + self.buf_size = self.size*self.stride + self.buf_region = self.driver.pool.alloc_region(self.buf_size) + self.buf_dma = self.buf_region.get_absolute_address(0) + self.buf = self.buf_region.mem + + self.head_ptr = 0 + self.tail_ptr = 0 + + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size + + async def free(self): + await self.deactivate() + + if self.buf: + # TODO + pass + + async def activate(self, cq): + self.log.info("Activate RXQ %d (interface %d)", self.index, self.interface.index) + + await self.deactivate() + + self.cq = cq + self.cq.src_ring = self + self.cq.handler = Rxq.process_rx_cq + + self.head_ptr = 0 + self.tail_ptr = 0 + + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address + await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cq.cqn) # completion queue index + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size + + self.active = True + + await self.refill_buffers() + + async def deactivate(self): + await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size + + if self.cq: + self.cq.src_ring = None + self.cq.handler = None + + self.cq = None + + self.active = False + + def empty(self): + return self.head_ptr == self.tail_ptr + + def full(self): + return self.head_ptr - self.tail_ptr >= self.full_size + + async def read_tail_ptr(self): + val = await self.hw_regs.read_dword(MQNIC_QUEUE_TAIL_PTR_REG) + self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask + + async def write_head_ptr(self): + await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) + + def free_desc(self, index): + pkt = self.rx_info[index] + self.driver.free_pkt(pkt) + self.rx_info[index] = None + + def free_buf(self): + while not self.empty(): + index = self.tail_ptr & self.size_mask + self.free_desc(index) + self.tail_ptr += 1 + + def prepare_desc(self, index): + pkt = self.driver.alloc_pkt() + self.rx_info[index] = pkt + + length = pkt.size + ptr = pkt.get_absolute_address(0) + offset = 0 + + # write descriptors + for k in range(0, self.desc_block_size): + seg = min(length-offset, 4096) if k < self.desc_block_size-1 else length-offset + struct.pack_into("> 8) & 0xff) + self.rx_queue_map_indir_table = [] + for k in range(self.port_count): + offset = await self.rx_queue_map_rb.read_dword(MQNIC_RB_RX_QUEUE_MAP_CH_OFFSET + + MQNIC_RB_RX_QUEUE_MAP_CH_STRIDE*k + MQNIC_RB_RX_QUEUE_MAP_CH_REG_OFFSET) + self.rx_queue_map_indir_table.append(self.rx_queue_map_rb.parent.create_window(offset)) + + await self.set_rx_queue_map_rss_mask(k, 0) + await self.set_rx_queue_map_app_mask(k, 0) + await self.set_rx_queue_map_indir_table(k, 0, 0) + + self.event_queues = [] + + self.txq = [] + self.tx_cq = [] + self.rxq = [] + self.rx_cq = [] + self.ports = [] + self.sched_blocks = [] + + for k in range(self.eq_count): + eq = Eq(self, k, self.hw_regs.create_window(self.eq_offset + k*self.eq_stride, self.eq_stride)) + await eq.init() + self.event_queues.append(eq) + + for k in range(self.txq_count): + txq = Txq(self, k, self.hw_regs.create_window(self.txq_offset + k*self.txq_stride, self.txq_stride)) + await txq.init() + self.txq.append(txq) + + for k in range(self.tx_cq_count): + cq = Cq(self, k, self.hw_regs.create_window(self.tx_cq_offset + k*self.tx_cq_stride, self.tx_cq_stride)) + await cq.init() + self.tx_cq.append(cq) + + for k in range(self.rxq_count): + rxq = Rxq(self, k, self.hw_regs.create_window(self.rxq_offset + k*self.rxq_stride, self.rxq_stride)) + await rxq.init() + self.rxq.append(rxq) + + for k in range(self.rx_cq_count): + cq = Cq(self, k, self.hw_regs.create_window(self.rx_cq_offset + k*self.rx_cq_stride, self.rx_cq_stride)) + await cq.init() + self.rx_cq.append(cq) + + for k in range(self.port_count): + rb = self.reg_blocks.find(MQNIC_RB_PORT_TYPE, MQNIC_RB_PORT_VER, index=k) + + p = Port(self, k, rb) + await p.init() + self.ports.append(p) + + for k in range(self.sched_block_count): + rb = self.reg_blocks.find(MQNIC_RB_SCHED_BLOCK_TYPE, MQNIC_RB_SCHED_BLOCK_VER, index=k) + + s = SchedulerBlock(self, k, rb) + await s.init() + self.sched_blocks.append(s) + + assert self.sched_block_count == len(self.sched_blocks) + + for eq in self.event_queues: + await eq.alloc(1024, MQNIC_EVENT_SIZE) + await eq.activate(self.index) # TODO? + await eq.arm() + + # wait for all writes to complete + await self.hw_regs.read_dword(0) + + async def open(self): + for rxq in self.rxq: + cq = self.rx_cq[rxq.index] + await cq.alloc(1024, MQNIC_CPL_SIZE) + await cq.activate(self.event_queues[cq.cqn % self.eq_count]) + await cq.arm() + await rxq.alloc(1024, MQNIC_DESC_SIZE*4) + await rxq.activate(cq) + + for txq in self.txq: + cq = self.tx_cq[txq.index] + await cq.alloc(1024, MQNIC_CPL_SIZE) + await cq.activate(self.event_queues[cq.cqn % self.eq_count]) + await cq.arm() + await txq.alloc(1024, MQNIC_DESC_SIZE*4) + await txq.activate(cq) + + # wait for all writes to complete + await self.hw_regs.read_dword(0) + + self.port_up = True + + async def close(self): + self.port_up = False + + for txq in self.txq: + await txq.deactivate() + await txq.cq.deactivate() + + for rxq in self.rxq: + await rxq.deactivate() + await rxq.cq.deactivate() + + # wait for all writes to complete + await self.hw_regs.read_dword(0) + + for q in self.txq: + await q.free_buf() + + for q in self.rxq: + await q.free_buf() + + async def start_xmit(self, skb, tx_ring=None, csum_start=None, csum_offset=None): + if not self.port_up: + return + + data = bytes(skb) + + assert len(data) < self.max_tx_mtu + + if tx_ring is not None: + ring_index = tx_ring + else: + ring_index = 0 + + ring = self.txq[ring_index] + + while True: + # check for space in ring + if ring.head_ptr - ring.tail_ptr < ring.full_size: + break + + # wait for space + ring.clean_event.clear() + await ring.clean_event.wait() + + index = ring.head_ptr & ring.size_mask + + ring.packets += 1 + ring.bytes += len(data) + + pkt = self.driver.alloc_pkt() + + assert not ring.tx_info[index] + ring.tx_info[index] = pkt + + # put data in packet buffer + pkt[10:len(data)+10] = data + + csum_cmd = 0 + + if csum_start is not None and csum_offset is not None: + csum_cmd = 0x8000 | (csum_offset << 8) | csum_start + + length = len(data) + ptr = pkt.get_absolute_address(0)+10 + offset = 0 + + # write descriptors + seg = min(length-offset, 42) if ring.desc_block_size > 1 else length-offset + struct.pack_into("