From 20280bdc3a52fb0fad41ecaa62f0486fb20e6e20 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Wed, 27 Sep 2023 09:31:09 -0700 Subject: [PATCH 01/28] First push for gw-move-to-2023 --- hw/lib/common/constraints/au250_general.xdc | 19 +++++++++++---- hw/lib/common/hdl/top.v | 9 +++---- .../hw/tcl/reference_switch.tcl | 24 ++++++++++++++++++- tools/settings.sh | 10 +++++--- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/hw/lib/common/constraints/au250_general.xdc b/hw/lib/common/constraints/au250_general.xdc index d1a71d6..d65b6ad 100644 --- a/hw/lib/common/constraints/au250_general.xdc +++ b/hw/lib/common/constraints/au250_general.xdc @@ -138,13 +138,24 @@ set_property -dict { LOC U3 } [get_ports QSFP1_RX_N[0]] ########################################################################## # Timing ########################################################################## -# CMAC user clock -create_clock -period 3.103 -name cmac_clk_0 [get_pins -hier -filter name=~*cmac_port[0]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] -create_clock -period 3.103 -name cmac_clk_1 [get_pins -hier -filter name=~*cmac_port[1]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] +# CMAC user clock. 3.103ns = 322.27 MHz (handles 65B pkts on a 512b bus with some extra slack) +# Greg: The following hierarchy does not match actual hierarchy: +# The instance cmac_port[0]*cmac_gtwiz_userclk_tx_inst is there but it has no pin txoutclk_out[0] +# create_clock -period 3.103 -name cmac_clk_0 [get_pins -hier -filter name=~*cmac_port[0]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] +# create_clock -period 3.103 -name cmac_clk_1 [get_pins -hier -filter name=~*cmac_port[1]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] +create_clock -period 3.103 -name cmac_clk_0 [get_pins -hier -filter name=~*cmac_port[0]*cmac_gtwiz_userclk_tx_inst/gtwiz_userclk_tx_usrclk2_out] +create_clock -period 3.103 -name cmac_clk_1 [get_pins -hier -filter name=~*cmac_port[1]*cmac_gtwiz_userclk_tx_inst/gtwiz_userclk_tx_usrclk2_out] -# Datapath Clock - 340MHz +# Greg: axis_aclk needs to be specified +create_clock -period 4.00 -name axis_aclk [get_pins -hier -filter name=~*u_top_wrapper/xilinx_nic_shell/axis_aclk] + +# Datapath Clock - 340MHz (called core_clk internally apparently) create_clock -period 2.941 -name dp_clk [get_pins -hier -filter name=~*u_clk_wiz_1/clk_out1] +# Greg: PCIe clock 100MHz +create_clock -period 10.0 -name pcie_refclk [get_ports pci_clk_p] + + set_false_path -from [get_clocks axis_aclk] -to [get_clocks dp_clk] set_false_path -from [get_clocks dp_clk] -to [get_clocks axis_aclk] set_false_path -from [get_clocks cmac_clk_1] -to [get_clocks dp_clk] diff --git a/hw/lib/common/hdl/top.v b/hw/lib/common/hdl/top.v index eb0d946..10743bb 100644 --- a/hw/lib/common/hdl/top.v +++ b/hw/lib/common/hdl/top.v @@ -28,7 +28,7 @@ module top #( parameter SIMULATIOM = "FALSE", - parameter BOARD = "AU280", + parameter BOARD = "AU250", // Greg: was "AU280" parameter C_NF_DATA_WIDTH = 512 , parameter C_NF_TUSER_WIDTH = 128, parameter C_IF_DATA_WIDTH = 512, @@ -153,6 +153,10 @@ module top #( end end + // Moved instantiation here to remove synth warning + wire core_clk; + wire locked; + reg [9:0] core_rst_cnt = 10'd0; reg core_rst_reg; always @ (posedge core_clk) begin @@ -169,9 +173,6 @@ module top #( wire axis_aclk, axil_aclk_250m; wire axis_rst, axil_rst_250m; - wire core_clk; - wire locked; - clk_wiz_1 u_clk_wiz_1 ( .clk_out1(core_clk), .reset (axis_rst), diff --git a/hw/projects/reference_switch/hw/tcl/reference_switch.tcl b/hw/projects/reference_switch/hw/tcl/reference_switch.tcl index dc5191c..ad9db3c 100644 --- a/hw/projects/reference_switch/hw/tcl/reference_switch.tcl +++ b/hw/projects/reference_switch/hw/tcl/reference_switch.tcl @@ -46,6 +46,26 @@ set datapath_freq_mhz 340 set opl_bcam_size 16 set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Limit messages reported +# These are typically not helpful. +# But if you really want to see all messages +# then set suppress_unwanted_warnings to 0. +##################################### +set suppress_unwanted_warnings 1 +if {$suppress_unwanted_warnings == 1} { + set_msg_config -id "Synth 8-11241" -limit 1 + set_msg_config -id "Synth 8-6014" -limit 1 + set_msg_config -id "Synth 8-3848" -limit 1 + set_msg_config -id "Synth 8-7129" -limit 1 + set_msg_config -id "Synth 8-10592" -limit 1 + set_msg_config -id "Synth 8-7154" -limit 1 + set_msg_config -id "Synth 8-223" -limit 1 + set_msg_config -id "Synth 8-3332" -limit 1 + set_msg_config -id "Synth 8-3886" -limit 1 + set_msg_config -id "Synth 8-5396" -limit 1 +} + ##################################### # Project Settings ##################################### @@ -87,9 +107,11 @@ if {[string match $board_name "au280"]} { } elseif {[string match $board_name "vcu1525"]} { add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl -} else { +} elseif {[string match $board_name "au250"]} { add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au250_timing.tcl add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} else { + puts "ERROR: Unknown Board type $board_name" } set_property is_enabled true [get_files ${project_constraints}] set_property constrset constraints [get_runs synth_1] diff --git a/tools/settings.sh b/tools/settings.sh index 42daf15..368218b 100644 --- a/tools/settings.sh +++ b/tools/settings.sh @@ -23,13 +23,16 @@ # @NETFPGA_LICENSE_HEADER_END@ # ### User defined -export NFPLUS_FOLDER=${HOME}/NetFPGA-PLUS +export NFPLUS_FOLDER=${HOME}/NetFPGA-PLUS-GW export BOARD_NAME=au250 export NF_PROJECT_NAME=reference_switch export PYTHON_BNRY=/usr/bin/python3 ### Don't change -export VERSION=2020.2 +# export VERSION=2020.2 - GREG - had to change this to latest Vivado version +export VERSION=2023.1 + + export PROJECTS=${NFPLUS_FOLDER}/projects export CONTRIB_PROJECTS=${NFPLUS_FOLDER}/contrib-projects export NF_DESIGN_DIR=${NFPLUS_FOLDER}/hw/projects/${NF_PROJECT_NAME} @@ -55,6 +58,7 @@ if [ ${BOARD_NAME} != "au280" -a \ return -1 else board_name=`echo "puts [get_board_parts -quiet -latest_file_version \"*:${BOARD_NAME}:*\"]" | vivado -nolog -nojournal -mode tcl | grep xilinx` + echo "**** GREG: BOARD_NAME is $BOARD_NAME and board_name is $board_name" if [ ${BOARD_NAME} = "au280" ] ; then device="xcu280-fsvh2892-2L-e" elif [ ${BOARD_NAME} = "au250" ] ; then @@ -73,7 +77,7 @@ if [ ! -d ${NF_DESIGN_DIR} ] ; then return -1 fi -echo "[ok] All parameters has been checked." +echo "[ok] All parameters have been checked." vivado_version=`echo $XILINX_VIVADO | awk -F "/" 'NF>1{print $NF}'` if [ -z ${vivado_version} ]; then From aa59614fde01d3c15702440f9719495982368667 Mon Sep 17 00:00:00 2001 From: Greg Watson <6108877+GregWatson@users.noreply.github.com> Date: Sat, 2 Dec 2023 21:16:15 -0800 Subject: [PATCH 02/28] Updated constraints. Now have clean build of reference-switch. Timing clean. --- hw/lib/common/constraints/au250_general.xdc | 22 ++++++++------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/lib/common/constraints/au250_general.xdc b/hw/lib/common/constraints/au250_general.xdc index d65b6ad..b233c51 100644 --- a/hw/lib/common/constraints/au250_general.xdc +++ b/hw/lib/common/constraints/au250_general.xdc @@ -138,29 +138,23 @@ set_property -dict { LOC U3 } [get_ports QSFP1_RX_N[0]] ########################################################################## # Timing ########################################################################## -# CMAC user clock. 3.103ns = 322.27 MHz (handles 65B pkts on a 512b bus with some extra slack) -# Greg: The following hierarchy does not match actual hierarchy: -# The instance cmac_port[0]*cmac_gtwiz_userclk_tx_inst is there but it has no pin txoutclk_out[0] -# create_clock -period 3.103 -name cmac_clk_0 [get_pins -hier -filter name=~*cmac_port[0]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] -# create_clock -period 3.103 -name cmac_clk_1 [get_pins -hier -filter name=~*cmac_port[1]*cmac_gtwiz_userclk_tx_inst/txoutclk_out[0]] -create_clock -period 3.103 -name cmac_clk_0 [get_pins -hier -filter name=~*cmac_port[0]*cmac_gtwiz_userclk_tx_inst/gtwiz_userclk_tx_usrclk2_out] -create_clock -period 3.103 -name cmac_clk_1 [get_pins -hier -filter name=~*cmac_port[1]*cmac_gtwiz_userclk_tx_inst/gtwiz_userclk_tx_usrclk2_out] - -# Greg: axis_aclk needs to be specified + +# axis_aclk needs to be specified create_clock -period 4.00 -name axis_aclk [get_pins -hier -filter name=~*u_top_wrapper/xilinx_nic_shell/axis_aclk] # Datapath Clock - 340MHz (called core_clk internally apparently) create_clock -period 2.941 -name dp_clk [get_pins -hier -filter name=~*u_clk_wiz_1/clk_out1] -# Greg: PCIe clock 100MHz +# PCIe clock 100MHz create_clock -period 10.0 -name pcie_refclk [get_ports pci_clk_p] +# Note: txoutclk_out[0] and txoutclk_out[0]_1 are created by the cmac librray constraints set_false_path -from [get_clocks axis_aclk] -to [get_clocks dp_clk] set_false_path -from [get_clocks dp_clk] -to [get_clocks axis_aclk] -set_false_path -from [get_clocks cmac_clk_1] -to [get_clocks dp_clk] -set_false_path -from [get_clocks dp_clk] -to [get_clocks cmac_clk_1] -set_false_path -from [get_clocks cmac_clk_0] -to [get_clocks dp_clk] -set_false_path -from [get_clocks dp_clk] -to [get_clocks cmac_clk_0] +set_false_path -from [get_clocks dp_clk] -to [get_clocks txoutclk_out[0]] +set_false_path -from [get_clocks txoutclk_out[0] ] -to [get_clocks dp_clk] +set_false_path -from [get_clocks dp_clk] -to [get_clocks txoutclk_out[0]_1] +set_false_path -from [get_clocks txoutclk_out[0]_1] -to [get_clocks dp_clk] set_false_path -from [get_clocks clk_out1_qdma_subsystem_clk_div] -to [get_clocks axis_aclk] set_false_path -from [get_clocks dp_clk] -to [get_clocks clk_out1_qdma_subsystem_clk_div] From 64906a44342200a78f9ecd13263e06ffdc6a7409 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Fri, 8 Dec 2023 12:02:49 -0800 Subject: [PATCH 03/28] Added Zhukun's patch to fix driver for recent kernels --- sw/app/main.c | 15 +++- sw/driver/Makefile | 6 ++ sw/driver/opennic-driver.patch | 139 +++++++++++++++++++++------------ 3 files changed, 107 insertions(+), 53 deletions(-) diff --git a/sw/app/main.c b/sw/app/main.c index 0b0409c..01d7593 100644 --- a/sw/app/main.c +++ b/sw/app/main.c @@ -62,12 +62,13 @@ struct xlni_ioctl_ifreq { #define HAVE_ADDR 0x01 #define HAVE_VALUE 0x02 #define HAVE_IFACE 0x04 +#define HAVE_DEBUG 0x08 static void usage(const char *progname) { - printf("Usage: %s -a [-w ] [-i ]\n", + printf("Usage: %s -a [-d] [-w ] [-i ]\n", progname); _exit(1); } @@ -88,7 +89,7 @@ main(int argc, char *argv[]) ifnam = "nf0";//NFPLUS_IFNAM_DEFAULT; req = NFDP_IOCTL_CMD_READ_REG; value = 0; - while ((rc = getopt(argc, argv, "+a:hi:w:")) != -1) { + while ((rc = getopt(argc, argv, "+a:dhi:w:")) != -1) { switch (rc) { case 'a': l = strtoul(optarg, NULL, 0); @@ -97,6 +98,9 @@ main(int argc, char *argv[]) addr = (uint32_t)l; flags |= HAVE_ADDR; break; + case 'd': + flags |= HAVE_DEBUG; + break; case 'i': ifnam = optarg; flags |= HAVE_IFACE; @@ -145,7 +149,12 @@ main(int argc, char *argv[]) memcpy(ifr.ifr_name, ifnam, ifnamlen); ifr.ifr_name[ifnamlen] = '\0'; ifr.ifr_data = (char *)&sifr; - + + if ((flags & HAVE_DEBUG) != 0) { + printf("IF: %s Addr: 0x%08x RD_IOCTL:%0d WR_IOCTL:%0d\n", + ifnam, addr, NFDP_IOCTL_CMD_READ_REG,NFDP_IOCTL_CMD_WRITE_REG ); + } + rc = ioctl(fd, req, &ifr); if (rc == -1) err(1, "ioctl"); diff --git a/sw/driver/Makefile b/sw/driver/Makefile index c2844a9..554acb2 100644 --- a/sw/driver/Makefile +++ b/sw/driver/Makefile @@ -45,3 +45,9 @@ driver: clean: $(MAKE) -C $(DRIVER_DIR) clean + +install: + $(MAKE) -C $(DRIVER_DIR) install + +uninstall: + $(MAKE) -C $(DRIVER_DIR) uninstall \ No newline at end of file diff --git a/sw/driver/opennic-driver.patch b/sw/driver/opennic-driver.patch index d86d81a..a33a7bd 100644 --- a/sw/driver/opennic-driver.patch +++ b/sw/driver/opennic-driver.patch @@ -34,23 +34,28 @@ diff -uprN ./onic_hardware.h ./onic_hardware.h struct onic_qdma_h2c_param { diff -uprN ./onic_main.c ./onic_main.c ---- ./onic_main.c 2020-10-10 22:22:57.000000000 +0900 -+++ ./onic_main.c 2021-02-02 14:52:46.000000000 +0900 -@@ -187,7 +187,9 @@ - strlcpy(netdev->name, dev_name, sizeof(netdev->name)); - - memset(&saddr, 0, sizeof(struct sockaddr)); - memcpy(saddr.sa_data, onic_default_dev_addr, 6); +--- ./onic_main.c 2023-12-07 12:27:36.237535443 +0000 ++++ ./onic_main.c 2023-12-07 12:33:38.980629056 +0000 +@@ -129,6 +129,7 @@ static const struct net_device_ops onic_ + .ndo_start_xmit = onic_xmit_frame, + .ndo_set_mac_address = onic_set_mac_address, + .ndo_do_ioctl = onic_do_ioctl, ++ .ndo_siocdevprivate = onic_siocdevprivate, + .ndo_change_mtu = onic_change_mtu, + .ndo_get_stats64 = onic_get_stats64, + }; +@@ -203,7 +204,9 @@ static int onic_probe(struct pci_dev *pd + + memset(&saddr, 0, sizeof(struct sockaddr)); + memcpy(saddr.sa_data, onic_default_dev_addr, 6); - get_random_bytes(saddr.sa_data + 3, 3); + saddr.sa_data[3] = pdev->bus->number; + saddr.sa_data[4] = PCI_SLOT(pdev->devfn); + saddr.sa_data[5] = PCI_FUNC(pdev->devfn); - onic_set_mac_address(netdev, (void *)&saddr); - -diff -uprN ./onic_main.c ./onic_main.c ---- ./onic_main.c 2020-10-10 22:22:57.000000000 +0900 -+++ ./onic_main.c 2021-02-02 14:52:46.000000000 +0900 -@@ -223,6 +223,15 @@ static int onic_probe(struct pci_dev *pd + onic_set_mac_address(netdev, (void *)&saddr); + + priv = netdev_priv(netdev); +@@ -241,6 +244,15 @@ static int onic_probe(struct pci_dev *pd netif_set_real_num_tx_queues(netdev, priv->num_tx_queues); netif_set_real_num_rx_queues(netdev, priv->num_rx_queues); @@ -66,10 +71,11 @@ diff -uprN ./onic_main.c ./onic_main.c rv = register_netdev(netdev); if (rv < 0) { dev_err(&pdev->dev, "register_netdev, err = %d", rv); + diff -uprN ./onic_netdev.c ./onic_netdev.c ---- ./onic_netdev.c 2020-10-10 22:22:57.000000000 +0900 -+++ ./onic_netdev.c 2021-02-02 14:52:46.000000000 +0900 -@@ -24,6 +24,97 @@ +--- ./onic_netdev.c 2023-12-07 12:27:48.485237886 +0000 ++++ ./onic_netdev.c 2023-12-07 12:33:03.369510418 +0000 +@@ -25,6 +25,97 @@ #define ONIC_RX_DESC_STEP 256 @@ -167,7 +173,7 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c inline static u16 onic_ring_get_real_count(struct onic_ring *ring) { /* Valid writeback entry means one less count of descriptor entries */ -@@ -609,6 +700,34 @@ netdev_tx_t onic_xmit_frame(struct sk_bu +@@ -742,6 +833,34 @@ netdev_tx_t onic_xmit_frame(struct sk_bu return NETDEV_TX_OK; } @@ -199,13 +205,58 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c +} +#endif /*NF_IOCTl*/ + - int onic_set_mac_address(struct net_device *dev, void *addr) - { - u8 *dev_addr = (u8 *)addr; -@@ -622,6 +741,50 @@ int onic_set_mac_address(struct net_devi - - int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) - { + int onic_set_mac_address(struct net_device *dev, void *addr) + { + struct sockaddr *saddr = addr; +@@ -758,6 +877,90 @@ int onic_set_mac_address(struct net_devi + + int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { ++#ifdef NF_IOCTL ++ struct onic_private *priv = netdev_priv(dev); ++ struct nfdp_dev *nfdev = onic_get_nfdp_dev(priv->hw.nfdp_handle); ++ struct onic_ioctl_ifreq sifr; ++ int err; ++ ++ switch(cmd) { ++ case NFDP_IOCTL_CMD_WRITE_REG: ++ err = copy_from_user(&sifr, ifr->ifr_data, ++ sizeof(struct onic_ioctl_ifreq)); ++ if (err != 0) { ++ err = -EFAULT; ++ break; ++ } ++ err = ioctl_write_reg(nfdev, &sifr); ++ break; ++ case NFDP_IOCTL_CMD_READ_REG: ++ err = copy_from_user(&sifr, ifr->ifr_data, ++ sizeof(struct onic_ioctl_ifreq)); ++ if (err != 0) { ++ err = -EFAULT; ++ break; ++ } ++ err = ioctl_read_reg(nfdev, &sifr); ++ if (err != 0) { ++ err = -EFAULT; ++ break; ++ } ++ err = copy_to_user(ifr->ifr_data, &sifr, ++ sizeof(struct onic_ioctl_ifreq)); ++ if (err != 0) ++ err = -EFAULT; ++ break; ++ default: ++ pr_info("unspported ioctl 0x%8x", cmd); ++ err = -EOPNOTSUPP; ++ break; ++ } ++#endif /*NF_IOCTL*/ ++ return 0; ++} ++ ++int onic_siocdevprivate(struct net_device *dev, struct ifreq *ifr, ++ void *data, int cmd) ++{ +#ifdef NF_IOCTL + struct onic_private *priv = netdev_priv(dev); + struct nfdp_dev *nfdev = onic_get_nfdp_dev(priv->hw.nfdp_handle); @@ -229,11 +280,6 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c + err = -EFAULT; + break; + } -+ //err = ioctl_write_reg(nfdev, &sifr); -+ //if (err != 0) { -+ // err = -EFAULT; -+ // break; -+ //} + err = ioctl_read_reg(nfdev, &sifr); + if (err != 0) { + err = -EFAULT; @@ -250,21 +296,27 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c + break; + } +#endif /*NF_IOCTL*/ - return 0; - } + return 0; + } diff -uprN ./onic_netdev.h ./onic_netdev.h ---- ./onic_netdev.h 2020-10-10 22:22:57.000000000 +0900 -+++ ./onic_netdev.h 2021-02-02 14:52:46.000000000 +0900 -@@ -49,4 +49,27 @@ void onic_get_stats64(struct net_device +--- ./onic_netdev.h 2023-12-07 12:27:36.237535443 +0000 ++++ ./onic_netdev.h 2023-12-07 12:35:34.613759583 +0000 +@@ -43,10 +43,32 @@ int onic_set_mac_address(struct net_devi - int onic_poll(struct napi_struct *napi, int budget); + int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + ++int onic_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void *data, int cmd); ++ + int onic_change_mtu(struct net_device *dev, int mtu); + + void onic_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats); + + int onic_poll(struct napi_struct *napi, int budget); + +#define NF_IOCTL +#ifdef NF_IOCTL -+//#ifndef __NF_IOCTL__ -+//#define __NF_IOCTL__ + +struct nfdp_dev { + struct pci_dev *pdev; @@ -280,19 +332,6 @@ diff -uprN ./onic_netdev.h ./onic_netdev.h +int onic_create_nfdp_dev(unsigned long *handle, struct pci_dev *pdev); + +void onic_destroy_nfdp_dev(unsigned long handle); -+//#endif /*__NF_IOCTL__ */ +#endif /* NF_IOCTL */ + #endif -diff -uprN ./onic_register.h ./onic_register.h ---- ./onic_register.h 2020-10-10 22:22:57.000000000 +0900 -+++ ./onic_register.h 2021-02-02 14:52:46.000000000 +0900 -@@ -30,7 +30,7 @@ static inline void onic_write_reg(struct - } - - #define SHELL_START 0x0 --#define SHELL_END 0x10000 -+#define SHELL_END 0x40000 - #define SHELL_MAXLEN (SHELL_END - SHELL_START) - - /***** system config registers *****/ From a0186c0aabe3497ab76619a010596a1172664a7f Mon Sep 17 00:00:00 2001 From: Greg Watson <6108877+GregWatson@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:16:18 -0800 Subject: [PATCH 04/28] Started to create project reference_dma and module nf_data_sink_v1_0_0 --- hw/lib/std/nf_data_sink_v1_0_0/Makefile | 33 + .../data/module_generation_nf_data_sink.xlsm | Bin 0 -> 17251 bytes .../data/nf_data_sink_defines.tcl | 56 ++ .../data/nf_data_sink_defines.txt | 56 ++ .../data/nf_data_sink_regs_defines.h | 59 ++ .../nf_data_sink_v1_0_0/data\\regs_gen.py" | 0 .../nf_data_sink_v1_0_0/hdl/nf_data_sink.v | 290 ++++++++ .../std/nf_data_sink_v1_0_0/nf_data_sink.tcl | 133 ++++ hw/projects/reference_dma/bitfiles/README | 42 ++ hw/projects/reference_dma/hw/Makefile | 91 +++ .../au250_au200_vcu1525_user_timing.tcl | 29 + .../reference_dma/hw/hdl/nf_datapath.v | 239 +++++++ hw/projects/reference_dma/hw/hdl/top_sim.v | 677 ++++++++++++++++++ hw/projects/reference_dma/hw/hdl/top_tb.v | 180 +++++ .../reference_dma/hw/tcl/export_registers.tcl | 160 +++++ .../reference_dma/hw/tcl/reference_dma.tcl | 455 ++++++++++++ .../hw/tcl/reference_dma_defines.tcl | 81 +++ .../hw/tcl/reference_dma_sim.tcl | 253 +++++++ .../test/both_learning_sw/run.py | 116 +++ .../test/both_simple_broadcast/run.py | 96 +++ .../reference_dma/test/connections/conn | 30 + hw/projects/reference_dma/test/global/setup | 35 + tools/settings.sh | 2 +- 23 files changed, 3112 insertions(+), 1 deletion(-) create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/Makefile create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h create mode 100644 "hw/lib/std/nf_data_sink_v1_0_0/data\\regs_gen.py" create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl create mode 100644 hw/projects/reference_dma/bitfiles/README create mode 100644 hw/projects/reference_dma/hw/Makefile create mode 100644 hw/projects/reference_dma/hw/constraints/au250_au200_vcu1525_user_timing.tcl create mode 100644 hw/projects/reference_dma/hw/hdl/nf_datapath.v create mode 100644 hw/projects/reference_dma/hw/hdl/top_sim.v create mode 100644 hw/projects/reference_dma/hw/hdl/top_tb.v create mode 100644 hw/projects/reference_dma/hw/tcl/export_registers.tcl create mode 100644 hw/projects/reference_dma/hw/tcl/reference_dma.tcl create mode 100644 hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl create mode 100644 hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl create mode 100755 hw/projects/reference_dma/test/both_learning_sw/run.py create mode 100755 hw/projects/reference_dma/test/both_simple_broadcast/run.py create mode 100644 hw/projects/reference_dma/test/connections/conn create mode 100644 hw/projects/reference_dma/test/global/setup diff --git a/hw/lib/std/nf_data_sink_v1_0_0/Makefile b/hw/lib/std/nf_data_sink_v1_0_0/Makefile new file mode 100644 index 0000000..b4044c4 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (c) 2015 University of Cambridge +# Modified by Salvator Galea +# All rights reserved. +# +# This software was developed by +# Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ + +all: clean + vivado -mode batch -source nf_data_sink.tcl + +clean: + rm -rf ip_* vivado*.* *.xml xgui/ .Xil* *.*~ *.zip diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm new file mode 100644 index 0000000000000000000000000000000000000000..aa4f658e2ee284ad562f8b32041975843782f861 GIT binary patch literal 17251 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 I@9(4k17#m)*8l(j literal 0 HcmV?d00001 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl new file mode 100644 index 0000000..a8b9a2b --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl @@ -0,0 +1,56 @@ +# +# Copyright (c) 2015 University of Cambridge +# All rights reserved. +# +# +# File: +# input_arbiter_regs_defines.tcl +# +# Description: +# This file is automatically generated with tcl defines for the software +# +# This software was developed by +# Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +set INPUT_ARBITER_REGS_ID_0_OFFSET 0x0 +set INPUT_ARBITER_REGS_ID_0_DEFAULT 0x0000DA01 +set INPUT_ARBITER_REGS_ID_0_WIDTH 32 +set INPUT_ARBITER_REGS_VERSION_0_OFFSET 0x4 +set INPUT_ARBITER_REGS_VERSION_0_DEFAULT 0x1 +set INPUT_ARBITER_REGS_VERSION_0_WIDTH 32 +set INPUT_ARBITER_REGS_RESET_0_OFFSET 0x8 +set INPUT_ARBITER_REGS_RESET_0_DEFAULT 0x0 +set INPUT_ARBITER_REGS_RESET_0_WIDTH 16 +set INPUT_ARBITER_REGS_FLIP_0_OFFSET 0xC +set INPUT_ARBITER_REGS_FLIP_0_DEFAULT 0x0 +set INPUT_ARBITER_REGS_FLIP_0_WIDTH 32 +set INPUT_ARBITER_REGS_DEBUG_0_OFFSET 0x10 +set INPUT_ARBITER_REGS_DEBUG_0_DEFAULT 0x0 +set INPUT_ARBITER_REGS_DEBUG_0_WIDTH 32 +set INPUT_ARBITER_REGS_PKTIN_0_OFFSET 0x14 +set INPUT_ARBITER_REGS_PKTIN_0_DEFAULT 0x0 +set INPUT_ARBITER_REGS_PKTIN_0_WIDTH 32 +set INPUT_ARBITER_REGS_PKTOUT_0_OFFSET 0x18 +set INPUT_ARBITER_REGS_PKTOUT_0_DEFAULT 0x0 +set INPUT_ARBITER_REGS_PKTOUT_0_WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt new file mode 100644 index 0000000..224df27 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt @@ -0,0 +1,56 @@ +// +// Copyright (c) 2015 University of Cambridge +// All rights reserved. +// +// +// File: +// input_arbiter_regs_defines.txt +// +// Description: +// This file is automatically generated with header defines for the software +// +// This software was developed by +// Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +#define NFPLUS INPUT_ARBITER ID OFFSET 0x0 +#define NFPLUS INPUT_ARBITER ID DEFAULT 0x0000DA01 +#define NFPLUS INPUT_ARBITER ID WIDTH 32 +#define NFPLUS INPUT_ARBITER VERSION OFFSET 0x4 +#define NFPLUS INPUT_ARBITER VERSION DEFAULT 0x1 +#define NFPLUS INPUT_ARBITER VERSION WIDTH 32 +#define NFPLUS INPUT_ARBITER RESET OFFSET 0x8 +#define NFPLUS INPUT_ARBITER RESET DEFAULT 0x0 +#define NFPLUS INPUT_ARBITER RESET WIDTH 16 +#define NFPLUS INPUT_ARBITER FLIP OFFSET 0xC +#define NFPLUS INPUT_ARBITER FLIP DEFAULT 0x0 +#define NFPLUS INPUT_ARBITER FLIP WIDTH 32 +#define NFPLUS INPUT_ARBITER DEBUG OFFSET 0x10 +#define NFPLUS INPUT_ARBITER DEBUG DEFAULT 0x0 +#define NFPLUS INPUT_ARBITER DEBUG WIDTH 32 +#define NFPLUS INPUT_ARBITER PKTIN OFFSET 0x14 +#define NFPLUS INPUT_ARBITER PKTIN DEFAULT 0x0 +#define NFPLUS INPUT_ARBITER PKTIN WIDTH 32 +#define NFPLUS INPUT_ARBITER PKTOUT OFFSET 0x18 +#define NFPLUS INPUT_ARBITER PKTOUT DEFAULT 0x0 +#define NFPLUS INPUT_ARBITER PKTOUT WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h new file mode 100644 index 0000000..751ee8d --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2015 University of Cambridge +// All rights reserved. +// +// +// File: +// input_arbiter_regs_defines.h +// +// Description: +// This file is automatically generated with header defines for the software +// +// This software was developed by +// Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +##########This text should be copied to the head file ############# + #Registers offset definitions + +#define NFPLUS_INPUT_ARBITER_ID_0_OFFSET 0x0 +#define NFPLUS_INPUT_ARBITER_ID_0_DEFAULT 0x0000DA01 +#define NFPLUS_INPUT_ARBITER_ID_0_WIDTH 32 +#define NFPLUS_INPUT_ARBITER_VERSION_0_OFFSET 0x4 +#define NFPLUS_INPUT_ARBITER_VERSION_0_DEFAULT 0x1 +#define NFPLUS_INPUT_ARBITER_VERSION_0_WIDTH 32 +#define NFPLUS_INPUT_ARBITER_RESET_0_OFFSET 0x8 +#define NFPLUS_INPUT_ARBITER_RESET_0_DEFAULT 0x0 +#define NFPLUS_INPUT_ARBITER_RESET_0_WIDTH 16 +#define NFPLUS_INPUT_ARBITER_FLIP_0_OFFSET 0xC +#define NFPLUS_INPUT_ARBITER_FLIP_0_DEFAULT 0x0 +#define NFPLUS_INPUT_ARBITER_FLIP_0_WIDTH 32 +#define NFPLUS_INPUT_ARBITER_DEBUG_0_OFFSET 0x10 +#define NFPLUS_INPUT_ARBITER_DEBUG_0_DEFAULT 0x0 +#define NFPLUS_INPUT_ARBITER_DEBUG_0_WIDTH 32 +#define NFPLUS_INPUT_ARBITER_PKTIN_0_OFFSET 0x14 +#define NFPLUS_INPUT_ARBITER_PKTIN_0_DEFAULT 0x0 +#define NFPLUS_INPUT_ARBITER_PKTIN_0_WIDTH 32 +#define NFPLUS_INPUT_ARBITER_PKTOUT_0_OFFSET 0x18 +#define NFPLUS_INPUT_ARBITER_PKTOUT_0_DEFAULT 0x0 +#define NFPLUS_INPUT_ARBITER_PKTOUT_0_WIDTH 32 diff --git "a/hw/lib/std/nf_data_sink_v1_0_0/data\\regs_gen.py" "b/hw/lib/std/nf_data_sink_v1_0_0/data\\regs_gen.py" new file mode 100644 index 0000000..e69de29 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v new file mode 100644 index 0000000..f1ec0a7 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v @@ -0,0 +1,290 @@ +//- +// Copyright (C) 2010, 2011 The Board of Trustees of The Leland Stanford +// Junior University +// Copyright (C) 2010, 2011 Adam Covington +// Copyright (C) 2015 Noa Zilberman +// Copyright (C) 2021 Yuta Tokusashi +// Copyright (C) 2024 Gregory Watson +// +// All rights reserved. +// +// This software was developed by +// Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme, +// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +// EP/P025374/1 alongside support from Xilinx Inc. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// +/******************************************************************************* + * File: + * nf_data_sink.v + * + * Library: + * hw/std/cores/nf_data_sink + * + * Module: + * nf_data_sink + * + * Author: + * Greg Watson + * + * Description: + * Accepts incoming data and discards it. + * Provides statistics on input data rate. + * + */ + +`timescale 1ns/1ns +`include "nf_data_sink_cpu_regs_defines.v" + +module nf_data_sink +#( + // Master AXI Stream Data Width + parameter C_M_AXIS_DATA_WIDTH=512, + parameter C_S_AXIS_DATA_WIDTH=512, + parameter C_M_AXIS_TUSER_WIDTH=128, + parameter C_S_AXIS_TUSER_WIDTH=128, + parameter NUM_QUEUES=1, + + // AXI Registers Data Width + parameter C_S_AXI_DATA_WIDTH = 32, + parameter C_S_AXI_ADDR_WIDTH = 12, + parameter C_BASEADDR = 32'h00000000 + +) +( + // Part 1: System side signals + // Global Ports + input axis_aclk, + input axis_resetn, + + // --- Master Stream Ports (interface to data path) + // --- n.c. until we code DMA tx logic + // output [C_M_AXIS_DATA_WIDTH - 1:0] m_axis_tdata, + // output [((C_M_AXIS_DATA_WIDTH / 8)) - 1:0] m_axis_tkeep, + // output [C_M_AXIS_TUSER_WIDTH-1:0] m_axis_tuser, + // output m_axis_tvalid, + // input m_axis_tready, + // output m_axis_tlast, + + + // DMA data from Host + input [C_S_AXIS_DATA_WIDTH - 1:0] s_axis_2_tdata, + input [((C_S_AXIS_DATA_WIDTH / 8)) - 1:0] s_axis_2_tkeep, + input [C_S_AXIS_TUSER_WIDTH-1:0] s_axis_2_tuser, + input s_axis_2_tvalid, + output s_axis_2_tready, + input s_axis_2_tlast, + + // Slave AXI Ports + input S_AXI_ACLK, + input S_AXI_ARESETN, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + input S_AXI_AWVALID, + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB, + input S_AXI_WVALID, + input S_AXI_BREADY, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + input S_AXI_ARVALID, + input S_AXI_RREADY, + output S_AXI_ARREADY, + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + output [1 : 0] S_AXI_RRESP, + output S_AXI_RVALID, + output S_AXI_WREADY, + output [1 :0] S_AXI_BRESP, + output S_AXI_BVALID, + output S_AXI_AWREADY + +); + + function integer log2; + input integer number; + begin + log2=0; + while(2**log2 NUM_QUEUES-1) ? extended_next_queue - NUM_QUEUES : extended_next_queue; + + assign m_axis_tuser = fifo_out_tuser[cur_queue]; + assign m_axis_tdata = fifo_out_tdata[cur_queue]; + assign m_axis_tlast = fifo_out_tlast[cur_queue]; + assign m_axis_tkeep = fifo_out_tkeep[cur_queue]; + assign m_axis_tvalid = ~empty[cur_queue]; + + + //Registers section + nf_data_sink_cpu_regs + #( + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH), + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH), + .C_BASE_ADDRESS (C_BASEADDR) + ) arbiter_cpu_regs_inst + ( + // General ports + .clk (axis_aclk), + .resetn (axis_resetn), + // AXI Lite ports + .S_AXI_ACLK (S_AXI_ACLK), + .S_AXI_ARESETN (S_AXI_ARESETN), + .S_AXI_AWADDR (S_AXI_AWADDR), + .S_AXI_AWVALID (S_AXI_AWVALID), + .S_AXI_WDATA (S_AXI_WDATA), + .S_AXI_WSTRB (S_AXI_WSTRB), + .S_AXI_WVALID (S_AXI_WVALID), + .S_AXI_BREADY (S_AXI_BREADY), + .S_AXI_ARADDR (S_AXI_ARADDR), + .S_AXI_ARVALID (S_AXI_ARVALID), + .S_AXI_RREADY (S_AXI_RREADY), + .S_AXI_ARREADY (S_AXI_ARREADY), + .S_AXI_RDATA (S_AXI_RDATA), + .S_AXI_RRESP (S_AXI_RRESP), + .S_AXI_RVALID (S_AXI_RVALID), + .S_AXI_WREADY (S_AXI_WREADY), + .S_AXI_BRESP (S_AXI_BRESP), + .S_AXI_BVALID (S_AXI_BVALID), + .S_AXI_AWREADY (S_AXI_AWREADY), + + // Register ports + .id_reg (id_reg), + .version_reg (version_reg), + .reset_reg (reset_reg), + .ip2cpu_flip_reg (ip2cpu_flip_reg), + .cpu2ip_flip_reg (cpu2ip_flip_reg), + .pktin_reg (pktin_reg), + .pktin_reg_clear (pktin_reg_clear), + .pktsum_reg (pktsum_reg), + .pktsum_reg_clear (pktsum_reg_clear), + .ip2cpu_debug_reg (ip2cpu_debug_reg), + .cpu2ip_debug_reg (cpu2ip_debug_reg), + + // Global Registers - user can select if to use + .cpu_resetn_soft(),//software reset, after cpu module + .resetn_soft (),//software reset to cpu module (from central reset management) + .resetn_sync (resetn_sync)//synchronized reset, use for better timing + ); + + assign clear_counters = reset_reg[0]; + assign reset_registers = reset_reg[4]; + + always @(posedge axis_aclk) + if (~resetn_sync | reset_registers) begin + id_reg <= #1 `REG_ID_DEFAULT; + version_reg <= #1 `REG_VERSION_DEFAULT; + ip2cpu_flip_reg <= #1 `REG_FLIP_DEFAULT; + pktin_reg <= #1 `REG_PKTIN_DEFAULT; + pktsum_reg <= #1 `REG_PKTOUT_DEFAULT; + ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT; + end + else begin + id_reg <= #1 `REG_ID_DEFAULT; + version_reg <= #1 `REG_VERSION_DEFAULT; + ip2cpu_flip_reg <= #1 ~cpu2ip_flip_reg; + pktin_reg <= #1 clear_counters | pktin_reg_clear ? 'h0 : pktin_reg + (in_tvalid & in_tlast & s_axis_2_tready); + + // Pktsum is just here to make sure data logic is not deleted in synthesis + pktsum_reg <= #1 clear_counters | pktsum_reg_clear ? 'h0 : pktsum_reg + (m_axis_tvalid && m_axis_tlast && m_axis_tready ) ? in_tdata[`REG_PKTSUM_BITS] : '0 ; + + ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT+cpu2ip_debug_reg; + end + + + +endmodule diff --git a/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl b/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl new file mode 100644 index 0000000..4f3d92f --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl @@ -0,0 +1,133 @@ +# +# Copyright (c) 2015 Noa Zilberman +# Modified by Salvator Galea +# All rights reserved. +# +# This software was developed by +# Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +# Vivado Launch Script +#### Change design settings here ####### +set design nf_data_sink +set top nf_data_sink +set device $::env(DEVICE) +set proj_dir ./ip_proj +set ip_version 1.0 +set lib_name NetFPGA +##################################### +# Project Settings +##################################### +create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} -ip +set_property source_mgmt_mode All [current_project] +set_property top ${top} [current_fileset] +set_property ip_repo_paths $::env(NFPLUS_FOLDER)/hw/lib/ [current_fileset] +puts "Creating Input Arbiter IP" +##################################### +# Project Structure & IP Build +##################################### +read_verilog "./hdl/nf_data_sink_cpu_regs_defines.v" +read_verilog "./hdl/nf_data_sink_cpu_regs.v" +read_verilog "./hdl/nf_data_sink.v" +update_compile_order -fileset sources_1 +update_compile_order -fileset sim_1 +ipx::package_project + +set_property name ${design} [ipx::current_core] +set_property library ${lib_name} [ipx::current_core] +set_property vendor_display_name {NetFPGA} [ipx::current_core] +set_property company_url {http://www.netfpga.org} [ipx::current_core] +set_property vendor {NetFPGA} [ipx::current_core] +set_property supported_families {{virtexuplus} {Production} {virtexuplushbm} {Production}} [ipx::current_core] +set_property taxonomy {{/NetFPGA/Generic}} [ipx::current_core] +set_property version ${ip_version} [ipx::current_core] +set_property display_name ${design} [ipx::current_core] +set_property description ${design} [ipx::current_core] + +update_ip_catalog -rebuild +ipx::add_subcore NetFPGA:NetFPGA:fallthrough_small_fifo:1.0 [ipx::get_file_groups xilinx_anylanguagesynthesis -of_objects [ipx::current_core]] +ipx::add_subcore NetFPGA:NetFPGA:fallthrough_small_fifo:1.0 [ipx::get_file_groups xilinx_anylanguagebehavioralsimulation -of_objects [ipx::current_core]] +ipx::infer_user_parameters [ipx::current_core] + +ipx::add_user_parameter {C_M_AXIS_DATA_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_M_AXIS_DATA_WIDTH] +set_property display_name {C_M_AXIS_DATA_WIDTH} [ipx::get_user_parameters C_M_AXIS_DATA_WIDTH] +set_property value {512} [ipx::get_user_parameters C_M_AXIS_DATA_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_M_AXIS_DATA_WIDTH] + +ipx::add_user_parameter {C_S_AXIS_DATA_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_S_AXIS_DATA_WIDTH] +set_property display_name {C_S_AXIS_DATA_WIDTH} [ipx::get_user_parameters C_S_AXIS_DATA_WIDTH] +set_property value {512} [ipx::get_user_parameters C_S_AXIS_DATA_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_S_AXIS_DATA_WIDTH] + +ipx::add_user_parameter {C_M_AXIS_TUSER_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_M_AXIS_TUSER_WIDTH] +set_property display_name {C_M_AXIS_TUSER_WIDTH} [ipx::get_user_parameters C_M_AXIS_TUSER_WIDTH] +set_property value {128} [ipx::get_user_parameters C_M_AXIS_TUSER_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_M_AXIS_TUSER_WIDTH] + +ipx::add_user_parameter {C_S_AXIS_TUSER_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_S_AXIS_TUSER_WIDTH] +set_property display_name {C_S_AXIS_TUSER_WIDTH} [ipx::get_user_parameters C_S_AXIS_TUSER_WIDTH] +set_property value {128} [ipx::get_user_parameters C_S_AXIS_TUSER_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_S_AXIS_TUSER_WIDTH] + +ipx::add_user_parameter {NUM_QUEUES} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters NUM_QUEUES] +set_property display_name {NUM_QUEUES} [ipx::get_user_parameters NUM_QUEUES] +set_property value {3} [ipx::get_user_parameters NUM_QUEUES] +set_property value_format {long} [ipx::get_user_parameters NUM_QUEUES] + +ipx::add_user_parameter {C_S_AXI_DATA_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_S_AXI_DATA_WIDTH] +set_property display_name {C_S_AXI_DATA_WIDTH} [ipx::get_user_parameters C_S_AXI_DATA_WIDTH] +set_property value {32} [ipx::get_user_parameters C_S_AXI_DATA_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_S_AXI_DATA_WIDTH] + +ipx::add_user_parameter {C_S_AXI_ADDR_WIDTH} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_S_AXI_ADDR_WIDTH] +set_property display_name {C_S_AXI_ADDR_WIDTH} [ipx::get_user_parameters C_S_AXI_ADDR_WIDTH] +set_property value {32} [ipx::get_user_parameters C_S_AXI_ADDR_WIDTH] +set_property value_format {long} [ipx::get_user_parameters C_S_AXI_ADDR_WIDTH] + +ipx::add_user_parameter {C_BASEADDR} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters C_BASEADDR] +set_property display_name {C_BASEADDR} [ipx::get_user_parameters C_BASEADDR] +set_property value {0x00000000} [ipx::get_user_parameters C_BASEADDR] +set_property value_format {bitstring} [ipx::get_user_parameters C_BASEADDR] + +ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces m_axis -of_objects [ipx::current_core]] +ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_0 -of_objects [ipx::current_core]] +ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_1 -of_objects [ipx::current_core]] +ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_2 -of_objects [ipx::current_core]] + +ipx::infer_user_parameters [ipx::current_core] + +ipx::check_integrity [ipx::current_core] +ipx::save_core [ipx::current_core] +update_ip_catalog +close_project + diff --git a/hw/projects/reference_dma/bitfiles/README b/hw/projects/reference_dma/bitfiles/README new file mode 100644 index 0000000..0ba0931 --- /dev/null +++ b/hw/projects/reference_dma/bitfiles/README @@ -0,0 +1,42 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +Reference Switch bitfile is available for a direct download from the University of Cambridge servers: + +1. Reference Switch (VCU1525) +url: http://www.cl.cam.ac.uk/research/srg/netos/projects/netfpga/bitfiles/NetFPGA-PLUS/1.0.0/reference_switch/reference_switch_vcu1525.bit +md5 checksum: b22506015c327aee7ebc3afb15a34f83 + +2. Reference Switch (U200) +url: http://www.cl.cam.ac.uk/research/srg/netos/projects/netfpga/bitfiles/NetFPGA-PLUS/1.0.0/reference_switch/reference_switch_au200.bit +md5 checksum: eac1597bef620d510613686976ee81de + +3. Reference Switch (U250) +url: http://www.cl.cam.ac.uk/research/srg/netos/projects/netfpga/bitfiles/NetFPGA-PLUS/1.0.0/reference_switch/reference_switch_au250.bit +md5 checksum: 867c207c1e037a98287b27e374da79a9 + +4. Reference Switch (U280) +url: http://www.cl.cam.ac.uk/research/srg/netos/projects/netfpga/bitfiles/NetFPGA-PLUS/1.0.0/reference_switch/reference_switch_au280.bit +md5 checksum: ae1a019c61f4c7554c91ef4934269d99 diff --git a/hw/projects/reference_dma/hw/Makefile b/hw/projects/reference_dma/hw/Makefile new file mode 100644 index 0000000..c29c376 --- /dev/null +++ b/hw/projects/reference_dma/hw/Makefile @@ -0,0 +1,91 @@ +################################################################################ +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +################################################################################ +PROJ = ${NF_PROJECT_NAME} + +all: project + +project: + echo "Create reference project under folder /project"; + @if test -d project/; then \ + echo "Project already exists"; \ + else \ + vivado -mode batch -source tcl/${PROJ}.tcl; \ + fi + +projectgui: + echo "Create reference project under folder /project"; + @if test -d project/; then \ + echo "Project already exists"; \ + else \ + vivado -mode gui -source tcl/${PROJ}.tcl; \ + fi + +sim: simclean + cp -f $(NF_DESIGN_DIR)/test/reg_defines_${NF_PROJECT_NAME}.py $(NF_DESIGN_DIR)/test/${TESTNAME}/reg_defines_${NF_PROJECT_NAME}.py + vivado -mode batch -source ../../../projects/${PROJ}/hw/tcl/${NF_PROJECT_NAME}_sim.tcl -tclargs ${TESTNAME} + $(NFPLUS_FOLDER)/tools/scripts/nf_sim_reconcile_axi_logs.py + $(NFPLUS_FOLDER)/tools/scripts/nf_sim_registers_axi_logs.py + +reg: + vivado -mode batch -source $(NF_DESIGN_DIR)/hw/tcl/export_registers.tcl + cd ../test && cp ../../../../tools/scripts/xparam2regdefines.py . && python xparam2regdefines.py + cd ../test && rm -f xparam2regdefines.py + cd ../test && cp ../../../../tools/scripts/python_parser.py . && python python_parser.py + cd ../test && rm -f python_parser.py && mv reg_defines.py reg_defines_${NF_PROJECT_NAME}.py + +simgui: simclean + cp -f $(NF_DESIGN_DIR)/test/reg_defines_reference_dma.py $(NF_DESIGN_DIR)/test/${TESTNAME}/reg_defines_reference_dma.py + vivado -mode gui -source ../../../projects/${PROJ}/hw/tcl/${NF_PROJECT_NAME}_sim.tcl -tclargs ${TESTNAME} + $(NFPLUS_FOLDER)/tools/scripts/nf_sim_reconcile_axi_logs.py + $(NFPLUS_FOLDER)/tools/scripts/nf_sim_registers_axi_logs.py + +simclean: + rm -rf proj_* vivado*.* *.*~ .Xil* $(NF_DESIGN_DIR)/hw/ip_repo/ $(NF_DESIGN_DIR)/hw/project/ + rm -rf *[0-9]_{stim,expected,log}.axi + rm -f *.axi + rm -f portconfig.sim + rm -f seed + rm -f *.log + rm -f ../test/Makefile + rm -rf ../test/*.log + rm -rf ../test/*.axi + rm -rf ../test/seed + rm -rf ../test/*.sim + rm -rf ../test/proj_* + rm -rf ../test/ip_repo + rm -f ../test/vivado*.* + rm -f ../test/*_*_*/reg_defines_${NF_PROJECT_NAME}.py + rm -f ../test/*_*_*/reg_defines_${NF_PROJECT_NAME}.pyc + + +clean: + rm -rf project + rm -f vivado* + rm -rf ip_repo diff --git a/hw/projects/reference_dma/hw/constraints/au250_au200_vcu1525_user_timing.tcl b/hw/projects/reference_dma/hw/constraints/au250_au200_vcu1525_user_timing.tcl new file mode 100644 index 0000000..6dd258f --- /dev/null +++ b/hw/projects/reference_dma/hw/constraints/au250_au200_vcu1525_user_timing.tcl @@ -0,0 +1,29 @@ +# +# Copyright (c) 2021 Yuta Tokusashi +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +create_pblock pblock_nf_datapath +add_cells_to_pblock [get_pblocks pblock_nf_datapath] [get_cells -quiet [list nf_datapath_0]] +add_cells_to_pblock [get_pblocks pblock_nf_datapath] [get_cells -quiet [list u_top_wrapper/u_nf_attachment]] +resize_pblock [get_pblocks pblock_nf_datapath] -add {SLR2} diff --git a/hw/projects/reference_dma/hw/hdl/nf_datapath.v b/hw/projects/reference_dma/hw/hdl/nf_datapath.v new file mode 100644 index 0000000..dc0361e --- /dev/null +++ b/hw/projects/reference_dma/hw/hdl/nf_datapath.v @@ -0,0 +1,239 @@ +`timescale 1ns / 1ps +//- +// Copyright (c) 2015 Noa Zilberman +// Copyright (c) 2021 Yuta Tokusashi +// All rights reserved. +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme, +// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +// EP/P025374/1 alongside support from Xilinx Inc. +// +// File: +// nf_datapath.v +// +// Module: +// nf_datapath +// +// Author: Noa Zilberman +// Modified by: Greg Watson +// +// Description: +// NetFPGA user data path wrapper. Used to explore host DMA performance. +// Has Tx and Rx interfaces to DMS. +// No connectivity to the CMACs. +// +// s_axis_0, s_axis_1, m_axis0, and m_axis1 are no connect (CMACs) +// s_axis2, and m_axis_2 connect to the DMA (PCIe) +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + + +module nf_datapath #( + //Slave AXI parameters + parameter C_S_AXI_DATA_WIDTH = 32, + parameter C_S_AXI_ADDR_WIDTH = 32, + parameter C_BASEADDR = 32'h00000000, + + // Master AXI Stream Data Width + parameter C_M_AXIS_DATA_WIDTH=512, + parameter C_S_AXIS_DATA_WIDTH=512, + parameter C_M_AXIS_TUSER_WIDTH=128, + parameter C_S_AXIS_TUSER_WIDTH=128, + parameter NUM_QUEUES=5 +) ( + //Datapath clock + input axis_aclk, + input axis_resetn, + //Registers clock + input axi_aclk, + input axi_resetn, + + // Slave AXI Ports + input [C_S_AXI_ADDR_WIDTH-1 : 0] S0_AXI_AWADDR, + input S0_AXI_AWVALID, + input [C_S_AXI_DATA_WIDTH-1 : 0] S0_AXI_WDATA, + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S0_AXI_WSTRB, + input S0_AXI_WVALID, + input S0_AXI_BREADY, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S0_AXI_ARADDR, + input S0_AXI_ARVALID, + input S0_AXI_RREADY, + output S0_AXI_ARREADY, + output [C_S_AXI_DATA_WIDTH-1 : 0] S0_AXI_RDATA, + output [1 : 0] S0_AXI_RRESP, + output S0_AXI_RVALID, + output S0_AXI_WREADY, + output [1 :0] S0_AXI_BRESP, + output S0_AXI_BVALID, + output S0_AXI_AWREADY, + + input [C_S_AXI_ADDR_WIDTH-1 : 0] S1_AXI_AWADDR, + input S1_AXI_AWVALID, + input [C_S_AXI_DATA_WIDTH-1 : 0] S1_AXI_WDATA, + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S1_AXI_WSTRB, + input S1_AXI_WVALID, + input S1_AXI_BREADY, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S1_AXI_ARADDR, + input S1_AXI_ARVALID, + input S1_AXI_RREADY, + output S1_AXI_ARREADY, + output [C_S_AXI_DATA_WIDTH-1 : 0] S1_AXI_RDATA, + output [1 : 0] S1_AXI_RRESP, + output S1_AXI_RVALID, + output S1_AXI_WREADY, + output [1 :0] S1_AXI_BRESP, + output S1_AXI_BVALID, + output S1_AXI_AWREADY, + + input [C_S_AXI_ADDR_WIDTH-1 : 0] S2_AXI_AWADDR, + input S2_AXI_AWVALID, + input [C_S_AXI_DATA_WIDTH-1 : 0] S2_AXI_WDATA, + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S2_AXI_WSTRB, + input S2_AXI_WVALID, + input S2_AXI_BREADY, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S2_AXI_ARADDR, + input S2_AXI_ARVALID, + input S2_AXI_RREADY, + output S2_AXI_ARREADY, + output [C_S_AXI_DATA_WIDTH-1 : 0] S2_AXI_RDATA, + output [1 : 0] S2_AXI_RRESP, + output S2_AXI_RVALID, + output S2_AXI_WREADY, + output [1 :0] S2_AXI_BRESP, + output S2_AXI_BVALID, + output S2_AXI_AWREADY, + + + // Slave Stream Ports (interface from Rx queues) + input [C_S_AXIS_DATA_WIDTH - 1:0] s_axis_0_tdata, + input [((C_S_AXIS_DATA_WIDTH / 8)) - 1:0] s_axis_0_tkeep, + input [C_S_AXIS_TUSER_WIDTH-1:0] s_axis_0_tuser, + input s_axis_0_tvalid, + output s_axis_0_tready, + input s_axis_0_tlast, + input [C_S_AXIS_DATA_WIDTH - 1:0] s_axis_1_tdata, + input [((C_S_AXIS_DATA_WIDTH / 8)) - 1:0] s_axis_1_tkeep, + input [C_S_AXIS_TUSER_WIDTH-1:0] s_axis_1_tuser, + input s_axis_1_tvalid, + output s_axis_1_tready, + input s_axis_1_tlast, + input [C_S_AXIS_DATA_WIDTH - 1:0] s_axis_2_tdata, + input [((C_S_AXIS_DATA_WIDTH / 8)) - 1:0] s_axis_2_tkeep, + input [C_S_AXIS_TUSER_WIDTH-1:0] s_axis_2_tuser, + input s_axis_2_tvalid, + output s_axis_2_tready, + input s_axis_2_tlast, + + + // Master Stream Ports (interface to TX queues) + output [C_M_AXIS_DATA_WIDTH - 1:0] m_axis_0_tdata, + output [((C_M_AXIS_DATA_WIDTH / 8)) - 1:0] m_axis_0_tkeep, + output [C_M_AXIS_TUSER_WIDTH-1:0] m_axis_0_tuser, + output m_axis_0_tvalid, + input m_axis_0_tready, + output m_axis_0_tlast, + output [C_M_AXIS_DATA_WIDTH - 1:0] m_axis_1_tdata, + output [((C_M_AXIS_DATA_WIDTH / 8)) - 1:0] m_axis_1_tkeep, + output [C_M_AXIS_TUSER_WIDTH-1:0] m_axis_1_tuser, + output m_axis_1_tvalid, + input m_axis_1_tready, + output m_axis_1_tlast, + output [C_M_AXIS_DATA_WIDTH - 1:0] m_axis_2_tdata, + output [((C_M_AXIS_DATA_WIDTH / 8)) - 1:0] m_axis_2_tkeep, + output [C_M_AXIS_TUSER_WIDTH-1:0] m_axis_2_tuser, + output m_axis_2_tvalid, + input m_axis_2_tready, + output m_axis_2_tlast + + ); + + // tie off unused output connections to CMAC + assign s_axis_0_tready = '0; + assign s_axis_1_tready = '0; + + assign m_axis_0_tdata = '0; + assign m_axis_0_tkeep = '0; + assign m_axis_0_tuser = '0; + assign m_axis_0_tlast = '0; + assign m_axis_1_tdata = '0; + assign m_axis_1_tkeep = '0; + assign m_axis_1_tuser = '0; + assign m_axis_1_tlast = '0; + + // not using S1_AXI or S2_AXI register interfaces at the moment. + assign S1_AXI_ARREADY = '0; + assign S1_AXI_RDATA = '0; + assign S1_AXI_RRESP = '0; + assign S1_AXI_RVALID = '0; + assign S1_AXI_WREADY = '0; + assign S1_AXI_BRESP = '0; + assign S1_AXI_BVALID = '0; + assign S1_AXI_AWREADY = '0; + assign S2_AXI_ARREADY = '0; + assign S2_AXI_RDATA = '0; + assign S2_AXI_RRESP = '0; + assign S2_AXI_RVALID = '0; + assign S2_AXI_WREADY = '0; + assign S2_AXI_BRESP = '0; + assign S2_AXI_BVALID = '0; + assign S2_AXI_AWREADY = '0; + + // temporarirly tie of m_axis until we code up the outbound DMA side. + assign m_axis_2_tdata = '0; + assign m_axis_2_tkeep = '0; + assign m_axis_2_tuser = '0; + assign m_axis_2_tlast = '0; + + // Data sink (data from DMA) + nf_data_sink nf_data_sink_v1_0 ( + .axis_aclk(axis_aclk), + .axis_resetn(axis_resetn), + .s_axis_2_tdata (s_axis_2_tdata), + .s_axis_2_tkeep (s_axis_2_tkeep), + .s_axis_2_tuser (s_axis_2_tuser), + .s_axis_2_tvalid(s_axis_2_tvalid), + .s_axis_2_tready(s_axis_2_tready), + .s_axis_2_tlast (s_axis_2_tlast), + .S_AXI_AWADDR(S0_AXI_AWADDR), + .S_AXI_AWVALID(S0_AXI_AWVALID), + .S_AXI_WDATA(S0_AXI_WDATA), + .S_AXI_WSTRB(S0_AXI_WSTRB), + .S_AXI_WVALID(S0_AXI_WVALID), + .S_AXI_BREADY(S0_AXI_BREADY), + .S_AXI_ARADDR(S0_AXI_ARADDR), + .S_AXI_ARVALID(S0_AXI_ARVALID), + .S_AXI_RREADY(S0_AXI_RREADY), + .S_AXI_ARREADY(S0_AXI_ARREADY), + .S_AXI_RDATA(S0_AXI_RDATA), + .S_AXI_RRESP(S0_AXI_RRESP), + .S_AXI_RVALID(S0_AXI_RVALID), + .S_AXI_WREADY(S0_AXI_WREADY), + .S_AXI_BRESP(S0_AXI_BRESP), + .S_AXI_BVALID(S0_AXI_BVALID), + .S_AXI_AWREADY(S0_AXI_AWREADY), + .S_AXI_ACLK (axi_aclk), + .S_AXI_ARESETN(axi_resetn) + ); + + + +endmodule diff --git a/hw/projects/reference_dma/hw/hdl/top_sim.v b/hw/projects/reference_dma/hw/hdl/top_sim.v new file mode 100644 index 0000000..14e47a3 --- /dev/null +++ b/hw/projects/reference_dma/hw/hdl/top_sim.v @@ -0,0 +1,677 @@ +//- +// Copyright (c) 2015 Noa Zilberman, Georgina Kalogeridou +// Copyright (c) 2021 Yuta Tokusashi +// All rights reserved. +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme, +// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +// EP/P025374/1 alongside support from Xilinx Inc. +// +// File: +// top_sim.v +// +// Module: +// top +// +// Author: Noa Zilberman, Georgina Kalogeridou +// +// Description: +// reference nic top module +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +`timescale 1ps / 100 fs + + module top_sim # ( + parameter C_DATA_WIDTH = 512, // RX/TX interface data width + parameter C_TUSER_WIDTH = 128, // RX/TX interface data width + parameter C_NF_DATA_WIDTH = 1024, // RX/TX interface data width + parameter KEEP_WIDTH = C_DATA_WIDTH / 32 + ) ( + +//PCI Express + input [15:0] pcie_rxn, + input [15:0] pcie_rxp, + output [15:0] pcie_txn, + output [15:0] pcie_txp, + //Network Interface + input [3:0] qsfp0_rxp, + input [3:0] qsfp0_rxn, + output [3:0] qsfp0_txp, + output [3:0] qsfp0_txn, + + input [3:0] qsfp1_rxp, + input [3:0] qsfp1_rxn, + output [3:0] qsfp1_txp, + output [3:0] qsfp1_txn, + + // PCIe Clock + input pci_clk_p, + input pci_clk_n, + + //200MHz Clock + input fpga_sysclk_p, + input fpga_sysclk_n, + + // 156.25 MHz clock in + input qsfp_refclk_p, + input qsfp_refclk_n, + + input sys_reset_n +); + + //----------------------------------------------------------------------------------------------------------------// + // System(SYS) Interface // + //----------------------------------------------------------------------------------------------------------------// + + wire sys_clk; + wire clk_200_i; + wire clk_200; + wire sys_rst_n_c; + + //----------------------------------------------------------------------------------------------------------------------- + + //----------------------------------------------------------------------------------------------------------------// + // axis interface // + //----------------------------------------------------------------------------------------------------------------// + + wire[C_NF_DATA_WIDTH-1:0] axis_i_0_tdata , axis_o_0_tdata; + wire axis_i_0_tvalid, axis_o_0_tvalid; + wire axis_i_0_tlast , axis_o_0_tlast; + wire[C_TUSER_WIDTH-1:0] axis_i_0_tuser , axis_o_0_tuser; + wire[C_NF_DATA_WIDTH/8-1:0] axis_i_0_tkeep , axis_o_0_tkeep; + wire axis_i_0_tready, axis_o_0_tready; + + wire[C_NF_DATA_WIDTH-1:0] axis_i_1_tdata , axis_o_1_tdata; + wire axis_i_1_tvalid, axis_o_1_tvalid; + wire axis_i_1_tlast , axis_o_1_tlast; + wire[C_TUSER_WIDTH-1:0] axis_i_1_tuser , axis_o_1_tuser; + wire[C_NF_DATA_WIDTH/8-1:0] axis_i_1_tkeep , axis_o_1_tkeep; + wire axis_i_1_tready, axis_o_1_tready; + + wire[C_NF_DATA_WIDTH-1:0] axis_dma_i_tdata , axis_dma_o_tdata; + wire axis_dma_i_tvalid, axis_dma_o_tvalid; + wire axis_dma_i_tlast , axis_dma_o_tlast; + wire[C_TUSER_WIDTH-1:0] axis_dma_i_tuser , axis_dma_o_tuser; + wire[C_NF_DATA_WIDTH/8-1:0] axis_dma_i_tkeep , axis_dma_o_tkeep; + wire axis_dma_i_tready, axis_dma_o_tready; + + wire[C_DATA_WIDTH-1:0] p_axis_i_0_tdata , p_axis_o_0_tdata; + wire p_axis_i_0_tvalid, p_axis_o_0_tvalid; + wire p_axis_i_0_tlast , p_axis_o_0_tlast; + wire[C_TUSER_WIDTH-1:0] p_axis_i_0_tuser , p_axis_o_0_tuser; + wire[C_DATA_WIDTH/8-1:0] p_axis_i_0_tkeep , p_axis_o_0_tkeep; + wire p_axis_i_0_tready, p_axis_o_0_tready; + + wire[C_DATA_WIDTH-1:0] p_axis_i_1_tdata , p_axis_o_1_tdata; + wire p_axis_i_1_tvalid, p_axis_o_1_tvalid; + wire p_axis_i_1_tlast , p_axis_o_1_tlast; + wire[C_TUSER_WIDTH-1:0] p_axis_i_1_tuser , p_axis_o_1_tuser; + wire[C_DATA_WIDTH/8-1:0] p_axis_i_1_tkeep , p_axis_o_1_tkeep; + wire p_axis_i_1_tready, p_axis_o_1_tready; + + wire[C_DATA_WIDTH-1:0] p_axis_dma_i_tdata , p_axis_dma_o_tdata; + wire p_axis_dma_i_tvalid, p_axis_dma_o_tvalid; + wire p_axis_dma_i_tlast , p_axis_dma_o_tlast; + wire[C_TUSER_WIDTH-1:0] p_axis_dma_i_tuser , p_axis_dma_o_tuser; + wire[C_DATA_WIDTH/8-1:0] p_axis_dma_i_tkeep , p_axis_dma_o_tkeep; + wire p_axis_dma_i_tready, p_axis_dma_o_tready; + //----------------------------------------------------------------------------------------------------------------// + // AXI Lite interface // + //----------------------------------------------------------------------------------------------------------------// + wire [31:0] M0_AXI_araddr , M1_AXI_araddr , M2_AXI_araddr; + wire [2:0] M0_AXI_arprot , M1_AXI_arprot , M2_AXI_arprot; + wire M0_AXI_arready, M1_AXI_arready, M2_AXI_arready; + wire M0_AXI_arvalid, M1_AXI_arvalid, M2_AXI_arvalid; + wire [31:0] M0_AXI_awaddr , M1_AXI_awaddr , M2_AXI_awaddr; + wire [2:0] M0_AXI_awprot , M1_AXI_awprot , M2_AXI_awprot; + wire M0_AXI_awready, M1_AXI_awready, M2_AXI_awready; + wire M0_AXI_awvalid, M1_AXI_awvalid, M2_AXI_awvalid; + wire M0_AXI_bready , M1_AXI_bready , M2_AXI_bready; + wire [1:0] M0_AXI_bresp , M1_AXI_bresp , M2_AXI_bresp; + wire M0_AXI_bvalid , M1_AXI_bvalid , M2_AXI_bvalid; + wire [31:0] M0_AXI_rdata , M1_AXI_rdata , M2_AXI_rdata; + wire M0_AXI_rready , M1_AXI_rready , M2_AXI_rready; + wire [1:0] M0_AXI_rresp , M1_AXI_rresp , M2_AXI_rresp; + wire M0_AXI_rvalid , M1_AXI_rvalid , M2_AXI_rvalid; + wire [31:0] M0_AXI_wdata , M1_AXI_wdata , M2_AXI_wdata; + wire M0_AXI_wready , M1_AXI_wready , M2_AXI_wready; + wire [3:0] M0_AXI_wstrb , M1_AXI_wstrb , M2_AXI_wstrb; + wire M0_AXI_wvalid , M1_AXI_wvalid , M2_AXI_wvalid; + + wire [31:0] M3_AXI_araddr , M4_AXI_araddr , M5_AXI_araddr; + wire [2:0] M3_AXI_arprot , M4_AXI_arprot , M5_AXI_arprot; + wire M3_AXI_arready, M4_AXI_arready, M5_AXI_arready; + wire M3_AXI_arvalid, M4_AXI_arvalid, M5_AXI_arvalid; + wire [31:0] M3_AXI_awaddr , M4_AXI_awaddr , M5_AXI_awaddr; + wire [2:0] M3_AXI_awprot , M4_AXI_awprot , M5_AXI_awprot; + wire M3_AXI_awready, M4_AXI_awready, M5_AXI_awready; + wire M3_AXI_awvalid, M4_AXI_awvalid, M5_AXI_awvalid; + wire M3_AXI_bready , M4_AXI_bready , M5_AXI_bready; + wire [1:0] M3_AXI_bresp , M4_AXI_bresp , M5_AXI_bresp; + wire M3_AXI_bvalid , M4_AXI_bvalid , M5_AXI_bvalid; + wire [31:0] M3_AXI_rdata , M4_AXI_rdata , M5_AXI_rdata; + wire M3_AXI_rready , M4_AXI_rready , M5_AXI_rready; + wire [1:0] M3_AXI_rresp , M4_AXI_rresp , M5_AXI_rresp; + wire M3_AXI_rvalid , M4_AXI_rvalid , M5_AXI_rvalid; + wire [31:0] M3_AXI_wdata , M4_AXI_wdata , M5_AXI_wdata; + wire M3_AXI_wready , M4_AXI_wready , M5_AXI_wready; + wire [3:0] M3_AXI_wstrb , M4_AXI_wstrb , M5_AXI_wstrb; + wire M3_AXI_wvalid , M4_AXI_wvalid , M5_AXI_wvalid; + + wire [31:0] S00_AXI_araddr; + wire [2:0] S00_AXI_arprot /*= 3'b010*/; + wire S00_AXI_arready; + wire S00_AXI_arvalid; + wire [31:0] S00_AXI_awaddr; + wire [2:0] S00_AXI_awprot /*= 3'b010*/; + wire S00_AXI_awready; + wire S00_AXI_awvalid; + wire S00_AXI_bready; + wire [1:0] S00_AXI_bresp; + wire S00_AXI_bvalid; + wire [31:0] S00_AXI_rdata; + wire S00_AXI_rready; + wire [1:0] S00_AXI_rresp; + wire S00_AXI_rvalid; + wire [31:0] S00_AXI_wdata; + wire S00_AXI_wready; + wire [3:0] S00_AXI_wstrb; + wire S00_AXI_wvalid; + + // Network Interfaces + wire axi_aresetn; + wire axi_clk; + wire [10:0] counter0,counter1,counter2,counter3,counter4; + wire activity_stim4, activity_stim3, activity_stim2, activity_stim1, activity_stim0; + wire activity_rec4, activity_rec3, activity_rec2, activity_rec1, activity_rec0; + wire barrier_req0, barrier_req1, barrier_req2, barrier_req3, barrier_req4; + wire barrier_proceed; + wire activity_trans_sim; + wire activity_trans_log; + wire barrier_req_trans; + + //--------------------------------------------------------------------- + // Misc + //--------------------------------------------------------------------- + IBUF sys_reset_n_ibuf ( .O(sys_rst_n_c), .I(sys_reset_n)); + + reg [15:0] sys_clk_count; + always @(posedge ~sys_clk) + sys_clk_count <= sys_clk_count + 1'b1; + + IBUFDS_GTE2 #( + .CLKCM_CFG("TRUE"), // Refer to Transceiver User Guide + .CLKRCV_TRST("TRUE"), // Refer to Transceiver User Guide + .CLKSWING_CFG(2'b11) // Refer to Transceiver User Guide + ) IBUFDS_GTE2_inst ( + .O (sys_clk), // 1-bit output: Refer to Transceiver User Guide + .ODIV2 (), // 1-bit output: Refer to Transceiver User Guide + .CEB (1'b0), // 1-bit input: Refer to Transceiver User Guide + .I (pci_clk_p), // 1-bit input: Refer to Transceiver User Guide + .IB (pci_clk_n) // 1-bit input: Refer to Transceiver User Guide + ); + + + IBUFDS_GTE2 #( + .CLKCM_CFG("TRUE"), // Refer to Transceiver User Guide + .CLKRCV_TRST("TRUE"), // Refer to Transceiver User Guide + .CLKSWING_CFG(2'b11) // Refer to Transceiver User Guide + ) IBUFDS_GTE2_core_inst ( + .O (clk_200), // 1-bit output: Refer to Transceiver User Guide + .ODIV2 (), // 1-bit output: Refer to Transceiver User Guide + .CEB (1'b0), // 1-bit input: Refer to Transceiver User Guide + .I (fpga_sysclk_p), // 1-bit input: Refer to Transceiver User Guide + .IB (fpga_sysclk_n) // 1-bit input: Refer to Transceiver User Guide + ); + + // drive AXI-lite from sys_clk & sys_rst + assign axi_clk = sys_clk; + assign axi_aresetn = sys_rst_n_c; + +//-----------------------------------------------------------------------------------------------// +// Network modules // +//-----------------------------------------------------------------------------------------------// + + nf_datapath + #( + // Master AXI Stream Data Width + .C_M_AXIS_DATA_WIDTH (C_NF_DATA_WIDTH), + .C_S_AXIS_DATA_WIDTH (C_NF_DATA_WIDTH), + .C_M_AXIS_TUSER_WIDTH (128), + .C_S_AXIS_TUSER_WIDTH (128), + .NUM_QUEUES (5) + ) + nf_datapath_0 + ( + .axis_aclk (clk_200), + .axis_resetn (sys_rst_n_c), + .axi_aclk (axi_clk), + .axi_resetn (axi_aresetn), + + // Slave Stream Ports (interface from Rx queues) + .s_axis_0_tdata (axis_i_0_tdata), + .s_axis_0_tkeep (axis_i_0_tkeep), + .s_axis_0_tuser (axis_i_0_tuser), + .s_axis_0_tvalid (axis_i_0_tvalid), + .s_axis_0_tready (axis_i_0_tready), + .s_axis_0_tlast (axis_i_0_tlast), + .s_axis_1_tdata (axis_i_1_tdata), + .s_axis_1_tkeep (axis_i_1_tkeep), + .s_axis_1_tuser (axis_i_1_tuser), + .s_axis_1_tvalid (axis_i_1_tvalid), + .s_axis_1_tready (axis_i_1_tready), + .s_axis_1_tlast (axis_i_1_tlast), + .s_axis_2_tdata (axis_dma_i_tdata), + .s_axis_2_tkeep (axis_dma_i_tkeep), + .s_axis_2_tuser (axis_dma_i_tuser), + .s_axis_2_tvalid (axis_dma_i_tvalid), + .s_axis_2_tready (axis_dma_i_tready), + .s_axis_2_tlast (axis_dma_i_tlast), + + + // Master Stream Ports (interface to TX queues) + .m_axis_0_tdata (axis_o_0_tdata), + .m_axis_0_tkeep (axis_o_0_tkeep), + .m_axis_0_tuser (axis_o_0_tuser), + .m_axis_0_tvalid (axis_o_0_tvalid), + .m_axis_0_tready (axis_o_0_tready), + .m_axis_0_tlast (axis_o_0_tlast), + .m_axis_1_tdata (axis_o_1_tdata), + .m_axis_1_tkeep (axis_o_1_tkeep), + .m_axis_1_tuser (axis_o_1_tuser), + .m_axis_1_tvalid (axis_o_1_tvalid), + .m_axis_1_tready (axis_o_1_tready), + .m_axis_1_tlast (axis_o_1_tlast), + .m_axis_2_tdata (axis_dma_o_tdata), + .m_axis_2_tkeep (axis_dma_o_tkeep), + .m_axis_2_tuser (axis_dma_o_tuser), + .m_axis_2_tvalid (axis_dma_o_tvalid), + .m_axis_2_tready (axis_dma_o_tready), + .m_axis_2_tlast (axis_dma_o_tlast), + + //AXI-Lite interface + .S0_AXI_AWADDR (M0_AXI_awaddr), + .S0_AXI_AWVALID (M0_AXI_awvalid), + .S0_AXI_WDATA (M0_AXI_wdata), + .S0_AXI_WSTRB (M0_AXI_wstrb), + .S0_AXI_WVALID (M0_AXI_wvalid), + .S0_AXI_BREADY (M0_AXI_bready), + .S0_AXI_ARADDR (M0_AXI_araddr), + .S0_AXI_ARVALID (M0_AXI_arvalid), + .S0_AXI_RREADY (M0_AXI_rready), + .S0_AXI_ARREADY (M0_AXI_arready), + .S0_AXI_RDATA (M0_AXI_rdata), + .S0_AXI_RRESP (M0_AXI_rresp), + .S0_AXI_RVALID (M0_AXI_rvalid), + .S0_AXI_WREADY (M0_AXI_wready), + .S0_AXI_BRESP (M0_AXI_bresp), + .S0_AXI_BVALID (M0_AXI_bvalid), + .S0_AXI_AWREADY (M0_AXI_awready), + + .S1_AXI_AWADDR (M1_AXI_awaddr), + .S1_AXI_AWVALID (M1_AXI_awvalid), + .S1_AXI_WDATA (M1_AXI_wdata), + .S1_AXI_WSTRB (M1_AXI_wstrb), + .S1_AXI_WVALID (M1_AXI_wvalid), + .S1_AXI_BREADY (M1_AXI_bready), + .S1_AXI_ARADDR (M1_AXI_araddr), + .S1_AXI_ARVALID (M1_AXI_arvalid), + .S1_AXI_RREADY (M1_AXI_rready), + .S1_AXI_ARREADY (M1_AXI_arready), + .S1_AXI_RDATA (M1_AXI_rdata), + .S1_AXI_RRESP (M1_AXI_rresp), + .S1_AXI_RVALID (M1_AXI_rvalid), + .S1_AXI_WREADY (M1_AXI_wready), + .S1_AXI_BRESP (M1_AXI_bresp), + .S1_AXI_BVALID (M1_AXI_bvalid), + .S1_AXI_AWREADY (M1_AXI_awready), + + .S2_AXI_AWADDR (M2_AXI_awaddr), + .S2_AXI_AWVALID (M2_AXI_awvalid), + .S2_AXI_WDATA (M2_AXI_wdata), + .S2_AXI_WSTRB (M2_AXI_wstrb), + .S2_AXI_WVALID (M2_AXI_wvalid), + .S2_AXI_BREADY (M2_AXI_bready), + .S2_AXI_ARADDR (M2_AXI_araddr), + .S2_AXI_ARVALID (M2_AXI_arvalid), + .S2_AXI_RREADY (M2_AXI_rready), + .S2_AXI_ARREADY (M2_AXI_arready), + .S2_AXI_RDATA (M2_AXI_rdata), + .S2_AXI_RRESP (M2_AXI_rresp), + .S2_AXI_RVALID (M2_AXI_rvalid), + .S2_AXI_WREADY (M2_AXI_wready), + .S2_AXI_BRESP (M2_AXI_bresp), + .S2_AXI_BVALID (M2_AXI_bvalid), + .S2_AXI_AWREADY (M2_AXI_awready) + ); + + axis_sim_stim_ip0 axis_sim_stim_0 ( + .ACLK (clk_200), + .ARESETN (sys_rst_n_c), + + //axi streaming data interface + .M_AXIS_TDATA (p_axis_i_0_tdata), + .M_AXIS_TKEEP (p_axis_i_0_tkeep), + .M_AXIS_TUSER (p_axis_i_0_tuser), + .M_AXIS_TVALID (p_axis_i_0_tvalid), + .M_AXIS_TREADY (1'b1), + .M_AXIS_TLAST (p_axis_i_0_tlast), + + .counter (counter0), + .activity_stim (activity_stim0), + .barrier_req (barrier_req0), + .barrier_proceed (barrier_proceed) + ); + + axis_sim_stim_ip1 axis_sim_stim_1 ( + .ACLK (clk_200), + .ARESETN (sys_rst_n_c), + + //axi streaming data interface + .M_AXIS_TDATA (p_axis_i_1_tdata), + .M_AXIS_TKEEP (p_axis_i_1_tkeep), + .M_AXIS_TUSER (p_axis_i_1_tuser), + .M_AXIS_TVALID (p_axis_i_1_tvalid), + .M_AXIS_TREADY (1'b1), + .M_AXIS_TLAST (p_axis_i_1_tlast), + + .counter (counter1), + .activity_stim (activity_stim1), + .barrier_req (barrier_req1), + .barrier_proceed (barrier_proceed) + ); + + axis_sim_stim_ip2 axis_sim_stim_2 ( + .ACLK (clk_200), + .ARESETN (sys_rst_n_c), + + //axi streaming data interface + .M_AXIS_TDATA (p_axis_dma_i_tdata), + .M_AXIS_TKEEP (p_axis_dma_i_tkeep), + .M_AXIS_TUSER (p_axis_dma_i_tuser), + .M_AXIS_TVALID (p_axis_dma_i_tvalid), + .M_AXIS_TREADY (1'b1), + .M_AXIS_TLAST (p_axis_dma_i_tlast), + + .counter (counter4), + .activity_stim (activity_stim4), + .barrier_req (barrier_req4), + .barrier_proceed (barrier_proceed) + ); + + axis_sim_record_ip0 axis_sim_record_0 ( + .axi_aclk (clk_200), + // Slave Stream Ports (interface to data path) + .s_axis_tdata (p_axis_o_0_tdata), + .s_axis_tkeep (p_axis_o_0_tkeep), + .s_axis_tuser (p_axis_o_0_tuser), + .s_axis_tvalid(p_axis_o_0_tvalid), + .s_axis_tready(p_axis_o_0_tready), + .s_axis_tlast (p_axis_o_0_tlast), + + .counter (counter0), + .activity_rec(activity_rec0) + ); + + axis_sim_record_ip1 axis_sim_record_1 ( + .axi_aclk (clk_200), + // Slave Stream Ports (interface to data path) + .s_axis_tdata (p_axis_o_1_tdata), + .s_axis_tkeep (p_axis_o_1_tkeep), + .s_axis_tuser (p_axis_o_1_tuser), + .s_axis_tvalid(p_axis_o_1_tvalid), + .s_axis_tready(p_axis_o_1_tready), + .s_axis_tlast (p_axis_o_1_tlast), + + .counter (counter1), + .activity_rec(activity_rec1) + ); + + axis_sim_record_ip2 axis_sim_record_2 ( + .axi_aclk (clk_200), + // Slave Stream Ports (interface to data path) + .s_axis_tdata (p_axis_dma_o_tdata), + .s_axis_tkeep (p_axis_dma_o_tkeep), + .s_axis_tuser (p_axis_dma_o_tuser), + .s_axis_tvalid(p_axis_dma_o_tvalid), + .s_axis_tready(p_axis_dma_o_tready), + .s_axis_tlast (p_axis_dma_o_tlast), + + .counter (counter4), + .activity_rec(activity_rec4) + ); + + nf_mac_attachment_dma_ip u_nf_attachment_dma ( + // 10GE block clk & rst + .clk156 (clk_200), + .areset_clk156 (!sys_rst_n_c), + // RX MAC 64b@clk156 (no backpressure) -> rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_dma_i_tdata), + .m_axis_mac_tkeep (p_axis_dma_i_tkeep), + .m_axis_mac_tvalid (p_axis_dma_i_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_dma_i_tuser), + .m_axis_mac_tlast (p_axis_dma_i_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_dma_o_tdata), + .s_axis_mac_tkeep (p_axis_dma_o_tkeep), + .s_axis_mac_tvalid (p_axis_dma_o_tvalid), + .s_axis_mac_tuser_err (), //underrun + .s_axis_mac_tuser (p_axis_dma_o_tuser), + .s_axis_mac_tlast (p_axis_dma_o_tlast), + .s_axis_mac_tready (p_axis_dma_o_tready), + + // TX/RX DATA channels + .interface_number (8'd0), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_dma_o_tdata), + .s_axis_pipe_tkeep (axis_dma_o_tkeep), + .s_axis_pipe_tlast (axis_dma_o_tlast), + .s_axis_pipe_tuser (axis_dma_o_tuser), + .s_axis_pipe_tvalid (axis_dma_o_tvalid), + .s_axis_pipe_tready (axis_dma_o_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_dma_i_tdata), + .m_axis_pipe_tkeep (axis_dma_i_tkeep), + .m_axis_pipe_tlast (axis_dma_i_tlast), + .m_axis_pipe_tuser (axis_dma_i_tuser), + .m_axis_pipe_tvalid (axis_dma_i_tvalid), + .m_axis_pipe_tready (axis_dma_i_tready) + ); + + nf_mac_attachment_ip u_nf_attachment_0 ( + // 10GE block clk & rst + .clk156 (clk_200), + .areset_clk156 (!sys_rst_n_c), + // RX MAC 64b@clk156 (no backpressure) -> rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_i_0_tdata), + .m_axis_mac_tkeep (p_axis_i_0_tkeep), + .m_axis_mac_tvalid (p_axis_i_0_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_i_0_tuser), + .m_axis_mac_tlast (p_axis_i_0_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_o_0_tdata), + .s_axis_mac_tkeep (p_axis_o_0_tkeep), + .s_axis_mac_tvalid (p_axis_o_0_tvalid), + .s_axis_mac_tuser_err (), //underrun + .s_axis_mac_tuser (p_axis_o_0_tuser), + .s_axis_mac_tlast (p_axis_o_0_tlast), + .s_axis_mac_tready (p_axis_o_0_tready), + + // TX/RX DATA channels + .interface_number (8'b0000_0001), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_o_0_tdata), + .s_axis_pipe_tkeep (axis_o_0_tkeep), + .s_axis_pipe_tlast (axis_o_0_tlast), + .s_axis_pipe_tuser (axis_o_0_tuser), + .s_axis_pipe_tvalid (axis_o_0_tvalid), + .s_axis_pipe_tready (axis_o_0_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_i_0_tdata), + .m_axis_pipe_tkeep (axis_i_0_tkeep), + .m_axis_pipe_tlast (axis_i_0_tlast), + .m_axis_pipe_tuser (axis_i_0_tuser), + .m_axis_pipe_tvalid (axis_i_0_tvalid), + .m_axis_pipe_tready (axis_i_0_tready) + ); + + nf_mac_attachment_ip u_nf_attachment_1 ( + // 10GE block clk & rst + .clk156 (clk_200), + .areset_clk156 (!sys_rst_n_c), + // RX MAC 64b@clk156 (no backpressure) -> rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_i_1_tdata), + .m_axis_mac_tkeep (p_axis_i_1_tkeep), + .m_axis_mac_tvalid (p_axis_i_1_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_i_1_tuser), + .m_axis_mac_tlast (p_axis_i_1_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_o_1_tdata), + .s_axis_mac_tkeep (p_axis_o_1_tkeep), + .s_axis_mac_tvalid (p_axis_o_1_tvalid), + .s_axis_mac_tuser_err (p_axis_o_1_tuser), //underrun + .s_axis_mac_tuser (p_axis_o_1_tuser), + .s_axis_mac_tlast (p_axis_o_1_tlast), + .s_axis_mac_tready (p_axis_o_1_tready), + + // TX/RX DATA channels + .interface_number (8'b0000_0100), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_o_1_tdata), + .s_axis_pipe_tkeep (axis_o_1_tkeep), + .s_axis_pipe_tlast (axis_o_1_tlast), + .s_axis_pipe_tuser (axis_o_1_tuser), + .s_axis_pipe_tvalid (axis_o_1_tvalid), + .s_axis_pipe_tready (axis_o_1_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_i_1_tdata), + .m_axis_pipe_tkeep (axis_i_1_tkeep), + .m_axis_pipe_tlast (axis_i_1_tlast), + .m_axis_pipe_tuser (axis_i_1_tuser), + .m_axis_pipe_tvalid (axis_i_1_tvalid), + .m_axis_pipe_tready (axis_i_1_tready) + ); + + axi_crossbar_0 u_interconnect( + .aclk (axi_clk), + .aresetn (axi_aresetn), + .s_axi_awaddr (S00_AXI_awaddr), + .s_axi_awprot (3'b010), + .s_axi_awvalid (S00_AXI_awvalid), + .s_axi_awready (S00_AXI_awready), + .s_axi_wdata (S00_AXI_wdata ), + .s_axi_wstrb (4'hf), + .s_axi_wvalid (S00_AXI_wvalid ), + .s_axi_wready (S00_AXI_wready ), + .s_axi_bresp (S00_AXI_bresp ), + .s_axi_bvalid (S00_AXI_bvalid ), + .s_axi_bready (S00_AXI_bready ), + .s_axi_araddr (S00_AXI_araddr[31:0]), + .s_axi_arprot (3'b010), + .s_axi_arvalid (S00_AXI_arvalid ), + .s_axi_arready (S00_AXI_arready ), + .s_axi_rdata (S00_AXI_rdata ), + .s_axi_rresp (S00_AXI_rresp ), + .s_axi_rvalid (S00_AXI_rvalid ), + .s_axi_rready (S00_AXI_rready ), + .m_axi_awaddr ({M2_AXI_awaddr[31:0] ,M1_AXI_awaddr[31:0] ,M0_AXI_awaddr[31:0] }), + .m_axi_awprot (), + .m_axi_awvalid ({M2_AXI_awvalid,M1_AXI_awvalid,M0_AXI_awvalid}), + .m_axi_awready ({M2_AXI_awready,M1_AXI_awready,M0_AXI_awready}), + .m_axi_wdata ({M2_AXI_wdata ,M1_AXI_wdata ,M0_AXI_wdata }), + .m_axi_wstrb ({M2_AXI_wstrb ,M1_AXI_wstrb ,M0_AXI_wstrb }), + .m_axi_wvalid ({M2_AXI_wvalid ,M1_AXI_wvalid ,M0_AXI_wvalid }), + .m_axi_wready ({M2_AXI_wready ,M1_AXI_wready ,M0_AXI_wready }), + .m_axi_bresp ({M2_AXI_bresp ,M1_AXI_bresp ,M0_AXI_bresp }), + .m_axi_bvalid ({M2_AXI_bvalid ,M1_AXI_bvalid ,M0_AXI_bvalid }), + .m_axi_bready ({M2_AXI_bready ,M1_AXI_bready ,M0_AXI_bready }), + .m_axi_araddr ({M2_AXI_araddr ,M1_AXI_araddr ,M0_AXI_araddr }), + .m_axi_arprot (), + .m_axi_arvalid ({M2_AXI_arvalid,M1_AXI_arvalid,M0_AXI_arvalid}), + .m_axi_arready ({M2_AXI_arready,M1_AXI_arready,M0_AXI_arready}), + .m_axi_rdata ({M2_AXI_rdata ,M1_AXI_rdata ,M0_AXI_rdata }), + .m_axi_rresp ({M2_AXI_rresp ,M1_AXI_rresp ,M0_AXI_rresp }), + .m_axi_rvalid ({M2_AXI_rvalid ,M1_AXI_rvalid ,M0_AXI_rvalid }), + .m_axi_rready ({M2_AXI_rready ,M1_AXI_rready ,M0_AXI_rready }) + ); + + + axi_sim_transactor_ip axi_sim_transactor_i ( + .axi_aclk (axi_clk), + .axi_resetn (axi_aresetn), + //AXI Write address channel + .M_AXI_AWADDR (S00_AXI_awaddr), + .M_AXI_AWVALID (S00_AXI_awvalid), + .M_AXI_AWREADY (S00_AXI_awready), + // AXI Write data channel + .M_AXI_WDATA (S00_AXI_wdata), + .M_AXI_WSTRB (S00_AXI_wstrb), + .M_AXI_WVALID (S00_AXI_wvalid), + .M_AXI_WREADY (S00_AXI_wready), + //AXI Write response channel + .M_AXI_BRESP (S00_AXI_bresp), + .M_AXI_BVALID (S00_AXI_bvalid), + .M_AXI_BREADY (S00_AXI_bready), + //AXI Read address channel + .M_AXI_ARADDR (S00_AXI_araddr), + .M_AXI_ARVALID (S00_AXI_arvalid), + .M_AXI_ARREADY (S00_AXI_arready), + //AXI Read data & response channel + .M_AXI_RDATA (S00_AXI_rdata), + .M_AXI_RRESP (S00_AXI_rresp), + .M_AXI_RVALID (S00_AXI_rvalid), + .M_AXI_RREADY (S00_AXI_rready), + + .activity_trans_sim (activity_trans_sim), + .activity_trans_log (activity_trans_log), + .barrier_req_trans (barrier_req_trans), + .barrier_proceed (barrier_proceed) + ); + + barrier_ip barrier_i ( + .activity_stim ({activity_stim4, activity_stim3, activity_stim2, activity_stim1, activity_stim0}), + .activity_rec ({activity_rec4, activity_rec3, activity_rec2, activity_rec1, activity_rec0}), + .activity_trans_sim (activity_trans_sim), + .activity_trans_log (activity_trans_log), + .barrier_req ({barrier_req4, barrier_req3, barrier_req2, barrier_req1, barrier_req0}), + .barrier_req_trans (barrier_req_trans), + .barrier_proceed (barrier_proceed) + ); + +endmodule + diff --git a/hw/projects/reference_dma/hw/hdl/top_tb.v b/hw/projects/reference_dma/hw/hdl/top_tb.v new file mode 100644 index 0000000..a57d63a --- /dev/null +++ b/hw/projects/reference_dma/hw/hdl/top_tb.v @@ -0,0 +1,180 @@ +//- +// Copyright (c) 2015 Noa Zilberman +// All rights reserved. +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// File: +// top_tb.v +// +// Module: +// top +// +// Author: Noa Zilberman +// +// Description: +// reference nic top module +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +`timescale 1ns / 100ps + + module top_tb # ( + parameter PL_SIM_FAST_LINK_TRAINING = "TRUE", // Simulation Speedup + parameter C_DATA_WIDTH = 512, // RX/TX interface data width + parameter KEEP_WIDTH = C_DATA_WIDTH / 32, + parameter integer USER_CLK2_FREQ = 4, + parameter REF_CLK_FREQ = 0, // 0 - 100 MHz, 1 - 125 MHz, 2 - 250 MHz + parameter AXISTEN_IF_RQ_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_CC_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_CQ_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_RC_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_ENABLE_CLIENT_TAG = 0, + parameter AXISTEN_IF_RQ_PARITY_CHECK = 0, + parameter AXISTEN_IF_CC_PARITY_CHECK = 0, + parameter AXISTEN_IF_MC_RX_STRADDLE = 0, + parameter AXISTEN_IF_ENABLE_RX_MSG_INTFC = 0, + parameter [17:0] AXISTEN_IF_ENABLE_MSG_ROUTE = 18'h2FFFF +) ( + +); + + parameter PCIE_PERIOD = 4.0; + parameter XPHY_PERIOD = 6.4; + parameter real CORE_PERIOD = 2.941; + + localparam TCQ = 1; + localparam BAR0AXI = 32'h40000000; + localparam BAR1AXI = 32'h10000000; + localparam BAR2AXI = 32'h20000000; + localparam BAR3AXI = 32'h30000000; + localparam BAR4AXI = 32'h40000000; + localparam BAR5AXI = 32'h50000000; + localparam BAR0SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR1SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR2SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR3SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR4SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR5SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam throttle_percent = 50; + + reg sys_reset_n; + + reg sys_clk; + wire sys_clkp,sys_clkn; + reg xphy_clk; + wire xphy_refclk_p,xphy_refclk_n; + reg clk_ref; + wire clk_ref_p,clk_ref_n; + //----------------------------------------------------------------------------------------------------------------// + // axis interface // + //----------------------------------------------------------------------------------------------------------------// + + + + top_sim # ( + .PL_SIM_FAST_LINK_TRAINING (PL_SIM_FAST_LINK_TRAINING ), + .C_DATA_WIDTH (C_DATA_WIDTH ), + .KEEP_WIDTH (KEEP_WIDTH ), + .USER_CLK2_FREQ (USER_CLK2_FREQ ), + .REF_CLK_FREQ (REF_CLK_FREQ ), + .AXISTEN_IF_RQ_ALIGNMENT_MODE (AXISTEN_IF_RQ_ALIGNMENT_MODE ), + .AXISTEN_IF_CC_ALIGNMENT_MODE (AXISTEN_IF_CC_ALIGNMENT_MODE ), + .AXISTEN_IF_CQ_ALIGNMENT_MODE (AXISTEN_IF_CQ_ALIGNMENT_MODE ), + .AXISTEN_IF_RC_ALIGNMENT_MODE (AXISTEN_IF_RC_ALIGNMENT_MODE ), + .AXISTEN_IF_ENABLE_CLIENT_TAG (AXISTEN_IF_ENABLE_CLIENT_TAG ), + .AXISTEN_IF_RQ_PARITY_CHECK (AXISTEN_IF_RQ_PARITY_CHECK ), + .AXISTEN_IF_CC_PARITY_CHECK (AXISTEN_IF_CC_PARITY_CHECK ), + .AXISTEN_IF_MC_RX_STRADDLE (AXISTEN_IF_MC_RX_STRADDLE ), + .AXISTEN_IF_ENABLE_RX_MSG_INTFC (AXISTEN_IF_ENABLE_RX_MSG_INTFC ), + .AXISTEN_IF_ENABLE_MSG_ROUTE (AXISTEN_IF_ENABLE_MSG_ROUTE ) + ) top_sim ( + + //PCI Express + .pcie_rxn(pcie_7x_mgt_rxn), + .pcie_rxp(pcie_7x_mgt_rxp), + .pcie_txn(pcie_7x_mgt_txn), + .pcie_txp(pcie_7x_mgt_txp), + //10G Interface + + .qsfp0_rxp(rxp), + .qsfp0_rxn(rxn), + .qsfp0_txp(txp), + .qsfp0_txn(txn), + + // PCIe Clock + .pci_clk_p(sys_clkp), + .pci_clk_n(sys_clkn), + + //200MHz Clock + .fpga_sysclk_p(clk_ref_p), + .fpga_sysclk_n(clk_ref_n), + + // 156.25 MHz clock in + .qsfp_refclk_p (xphy_refclk_p), + .qsfp_refclk_n (xphy_refclk_n), + + .sys_reset_n(sys_reset_n) + ); + +//Reset handling + // Important! polarity here is opposite the one in the actual design + initial begin + sys_reset_n = 1'b0; + #(CORE_PERIOD * 200); + sys_reset_n = 1'b1; + $display("Reset Deasserted"); + end + +//Clock generation + initial begin + sys_clk = 1'b0; + #(PCIE_PERIOD/2); + forever + #(PCIE_PERIOD/2) sys_clk = ~sys_clk; + end + + assign sys_clkp = sys_clk; + assign sys_clkn = ~sys_clk; + + + initial begin + xphy_clk = 1'b0; + #(XPHY_PERIOD/2); + forever + #(XPHY_PERIOD/2) xphy_clk = ~xphy_clk; + end + + assign xphy_refclk_p = xphy_clk; + assign xphy_refclk_n = ~xphy_clk; + + initial begin + clk_ref = 1'b0; + #(CORE_PERIOD/2); + forever + #(CORE_PERIOD/2) clk_ref = ~clk_ref; + end + + assign clk_ref_p = clk_ref; + assign clk_ref_n = ~clk_ref; + +endmodule diff --git a/hw/projects/reference_dma/hw/tcl/export_registers.tcl b/hw/projects/reference_dma/hw/tcl/export_registers.tcl new file mode 100644 index 0000000..6e8f923 --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/export_registers.tcl @@ -0,0 +1,160 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang +# Copyright (c) 2021 Yuta Tokusashi +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +# The following list include all the items that are mapped to memory segments +# The structure of each item is as follows { } + +set DEF_LIST { + {INPUT_ARBITER 0 1 input_arbiter_v1_0_0/data/input_arbiter_regs_defines.txt} \ + {OUTPUT_QUEUES 0 1 output_queues_v1_0_0/data/output_queues_regs_defines.txt} \ + {OUTPUT_PORT_LOOKUP 0 1 switch_output_port_lookup_v1_0_1/data/output_port_lookup_regs_defines.txt} \ +} + +set target_path $::env(NF_DESIGN_DIR)/test/ +set target_file $target_path/nf_register_defines.h + +if {[file exists ${target_path}] == 0} { + exec mkdir -p ${target_path} +} + +###################################################### +# the following function writes the license header +# into the file +###################################################### + +proc write_header { target_file } { + +# creat a blank header file +# do a fresh rewrite in case the file already exits +file delete -force $target_file +open $target_file "w" +set h_file [open $target_file "w"] + + +puts $h_file "//-" +puts $h_file "// Copyright (c) 2015,2021 University of Cambridge" +puts $h_file "// All rights reserved." +puts $h_file "//" +puts $h_file "// This software was developed by Stanford University and the University of Cambridge Computer Laboratory " +puts $h_file "// under National Science Foundation under Grant No. CNS-0855268," +puts $h_file "// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and" +puts $h_file "// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 (\"MRC2\"), " +puts $h_file "// as part of the DARPA MRC research programme," +puts $h_file "// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project" +puts $h_file "// EP/P025374/1 alongside support from Xilinx Inc." +puts $h_file "//" +puts $h_file "// @NETFPGA_LICENSE_HEADER_START@" +puts $h_file "//" +puts $h_file "// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor" +puts $h_file "// license agreements. See the NOTICE file distributed with this work for" +puts $h_file "// additional information regarding copyright ownership. NetFPGA licenses this" +puts $h_file "// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the" +puts $h_file "// \"License\"); you may not use this file except in compliance with the" +puts $h_file "// License. You may obtain a copy of the License at:" +puts $h_file "//" +puts $h_file "// http://www.netfpga-cic.org" +puts $h_file "//" +puts $h_file "// Unless required by applicable law or agreed to in writing, Work distributed" +puts $h_file "// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR" +puts $h_file "// CONDITIONS OF ANY KIND, either express or implied. See the License for the" +puts $h_file "// specific language governing permissions and limitations under the License." +puts $h_file "//" +puts $h_file "// @NETFPGA_LICENSE_HEADER_END@" +puts $h_file "/////////////////////////////////////////////////////////////////////////////////" +puts $h_file "// This is an automatically generated header definitions file" +puts $h_file "/////////////////////////////////////////////////////////////////////////////////" +puts $h_file "" + +close $h_file + +}; # end of proc write_header + + +###################################################### +# the following function writes all the information +# of a specific core into a file +###################################################### + +proc write_core {target_file prefix id has_registers lib_name} { + + +set h_file [open $target_file "a"] + +#First, read the memory map information from the reference_project defines file +source $::env(NF_DESIGN_DIR)/hw/tcl/$::env(NF_PROJECT_NAME)_defines.tcl +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib/ + + +set baseaddr [set $prefix\_BASEADDR] +set highaddr [set $prefix\_HIGHADDR] +set sizeaddr [set $prefix\_SIZEADDR] + +puts $h_file "//######################################################" +puts $h_file "//# Definitions for $prefix" +puts $h_file "//######################################################" + +puts $h_file "#define NFPLUS_$prefix\_BASEADDR $baseaddr" +puts $h_file "#define NFPLUS_$prefix\_HIGHADDR $highaddr" +puts $h_file "#define NFPLUS_$prefix\_SIZEADDR $sizeaddr" +puts $h_file "" + +#Second, read the registers information from the library defines file +if $has_registers { + set lib_path "$public_repo_dir/std/$lib_name" + set regs_h_define_file $lib_path + set regs_h_define_file_read [open $regs_h_define_file r] + set regs_h_define_file_data [read $regs_h_define_file_read] + close $regs_h_define_file_read + set regs_h_define_file_data_line [split $regs_h_define_file_data "\n"] + + foreach read_line $regs_h_define_file_data_line { + if {[regexp "#define" $read_line]} { + puts $h_file "#define NFPLUS_[lindex $read_line 2]\_$id\_[lindex $read_line 3]\_[lindex $read_line 4] [lindex $read_line 5]" + } + } +} +puts $h_file "" +close $h_file +}; # end of proc write_core + + + +###################################################### +# the main function +###################################################### + + + +write_header $target_file + +foreach lib_item $DEF_LIST { + write_core $target_file [lindex $lib_item 0] [lindex $lib_item 1] [lindex $lib_item 2] [lindex $lib_item 3] +} + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl new file mode 100644 index 0000000..ad9db3c --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl @@ -0,0 +1,455 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +#### Change design settings here ####### +set design $::env(NF_PROJECT_NAME) +set top top +set device $::env(DEVICE) +set board $::env(BOARD) +set board_name $::env(BOARD_NAME) + +set proj_dir ./project +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib +set repo_dir ./ip_repo +set project_constraints "${public_repo_dir}/common/constraints/${board_name}_general.xdc" + +set start_time [exec date +%s] +set_param general.maxThreads 8 +set_param synth.elaboration.rodinMoreOptions "rt::set_parameter max_loop_limit 200000" +##################################### +# Design Parameters on NF_DATAPATH +##################################### +set datapath_width_bit 1024 +set datapath_freq_mhz 340 +set opl_bcam_size 16 + +set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Limit messages reported +# These are typically not helpful. +# But if you really want to see all messages +# then set suppress_unwanted_warnings to 0. +##################################### +set suppress_unwanted_warnings 1 +if {$suppress_unwanted_warnings == 1} { + set_msg_config -id "Synth 8-11241" -limit 1 + set_msg_config -id "Synth 8-6014" -limit 1 + set_msg_config -id "Synth 8-3848" -limit 1 + set_msg_config -id "Synth 8-7129" -limit 1 + set_msg_config -id "Synth 8-10592" -limit 1 + set_msg_config -id "Synth 8-7154" -limit 1 + set_msg_config -id "Synth 8-223" -limit 1 + set_msg_config -id "Synth 8-3332" -limit 1 + set_msg_config -id "Synth 8-3886" -limit 1 + set_msg_config -id "Synth 8-5396" -limit 1 +} + +##################################### +# Project Settings +##################################### +create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} +set_property board_part ${board} [current_project] +set_property source_mgmt_mode DisplayOnly [current_project] +set_property top ${top} [current_fileset] +if {[string match $board_name "au280"]} { + set_property verilog_define { {BOARD_AU280} {au280} {__synthesis__} } [current_fileset] + set board_param "AU280" +} elseif {[string match $board_name "au250"]} { + set_property verilog_define { {BOARD_AU250} {__synthesis__} } [current_fileset] + set board_param "AU250" +} elseif {[string match $board_name "au200"]} { + set_property verilog_define { {BOARD_AU200} {__synthesis__} } [current_fileset] + set board_param "AU200" +} elseif {[string match $board_name "vcu1525"]} { + set_property verilog_define { {BOARD_VCU1525} {__synthesis__} } [current_fileset] + set board_param "VCU1525" +} +set_property generic "C_NF_DATA_WIDTH=${datapath_width_bit} BOARD=\"${board_param}\"" [current_fileset] + +puts "Creating User Datapath reference project" +##################################### +# set IP paths +##################################### +create_fileset -constrset -quiet constraints +file copy ${public_repo_dir}/ ${repo_dir} +set_property ip_repo_paths ${repo_dir} [current_fileset] +##################################### +# Project Constraints +##################################### +add_files -fileset constraints -norecurse ${project_constraints} +if {[string match $board_name "au280"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au280_timing.tcl +} elseif {[string match $board_name "au200"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} elseif {[string match $board_name "vcu1525"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} elseif {[string match $board_name "au250"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au250_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} else { + puts "ERROR: Unknown Board type $board_name" +} +set_property is_enabled true [get_files ${project_constraints}] +set_property constrset constraints [get_runs synth_1] +set_property constrset constraints [get_runs impl_1] + +##################################### +# Project +##################################### +update_ip_catalog +# OPL +create_ip -name switch_output_port_lookup -vendor NetFPGA -library NetFPGA -module_name switch_output_port_lookup_ip +set_property CONFIG.C_CAM_LUT_DEPTH_BITS ${opl_cam_depth_bits} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property generate_synth_checkpoint false [get_files switch_output_port_lookup_ip.xci] +reset_target all [get_ips switch_output_port_lookup_ip] +generate_target all [get_ips switch_output_port_lookup_ip] +# input_arbiter +create_ip -name input_arbiter -vendor NetFPGA -library NetFPGA -module_name input_arbiter_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property generate_synth_checkpoint false [get_files input_arbiter_ip.xci] +reset_target all [get_ips input_arbiter_ip] +generate_target all [get_ips input_arbiter_ip] +# output_queues +create_ip -name output_queues -vendor NetFPGA -library NetFPGA -module_name output_queues_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property generate_synth_checkpoint false [get_files output_queues_ip.xci] +reset_target all [get_ips output_queues_ip] +generate_target all [get_ips output_queues_ip] + +create_ip -name xilinx_shell -vendor xilinx -library xilinx -module_name xilinx_shell_ip +set_property CONFIG.MAX_PKT_LEN 1518 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_QUEUE 2048 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_PHYS_FUNC 2 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_CMAC_PORT 2 [get_ips xilinx_shell_ip] +set_property generate_synth_checkpoint false [get_files xilinx_shell_ip.xci] +reset_target all [get_ips xilinx_shell_ip] +generate_target all [get_ips xilinx_shell_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_ip.xci] +reset_target all [get_ips nf_mac_attachment_ip] +generate_target all [get_ips nf_mac_attachment_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_dma_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_DEFAULT_VALUE_ENABLE 0 [get_ips nf_mac_attachment_dma_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_dma_ip.xci] +reset_target all [get_ips nf_mac_attachment_dma_ip] +generate_target all [get_ips nf_mac_attachment_dma_ip] + +create_ip -name axi_crossbar -vendor xilinx.com -library ip -module_name axi_crossbar_0 +set_property -dict [list \ +CONFIG.NUM_MI {3} \ +CONFIG.PROTOCOL {AXI4LITE} \ +CONFIG.CONNECTIVITY_MODE {SASD} \ +CONFIG.R_REGISTER {1} \ +CONFIG.S00_WRITE_ACCEPTANCE {1} \ +CONFIG.S01_WRITE_ACCEPTANCE {1} \ +CONFIG.S02_WRITE_ACCEPTANCE {1} \ +CONFIG.S03_WRITE_ACCEPTANCE {1} \ +CONFIG.S04_WRITE_ACCEPTANCE {1} \ +CONFIG.S05_WRITE_ACCEPTANCE {1} \ +CONFIG.S06_WRITE_ACCEPTANCE {1} \ +CONFIG.S07_WRITE_ACCEPTANCE {1} \ +CONFIG.S08_WRITE_ACCEPTANCE {1} \ +CONFIG.S09_WRITE_ACCEPTANCE {1} \ +CONFIG.S10_WRITE_ACCEPTANCE {1} \ +CONFIG.S11_WRITE_ACCEPTANCE {1} \ +CONFIG.S12_WRITE_ACCEPTANCE {1} \ +CONFIG.S13_WRITE_ACCEPTANCE {1} \ +CONFIG.S14_WRITE_ACCEPTANCE {1} \ +CONFIG.S15_WRITE_ACCEPTANCE {1} \ +CONFIG.S00_READ_ACCEPTANCE {1} \ +CONFIG.S01_READ_ACCEPTANCE {1} \ +CONFIG.S02_READ_ACCEPTANCE {1} \ +CONFIG.S03_READ_ACCEPTANCE {1} \ +CONFIG.S04_READ_ACCEPTANCE {1} \ +CONFIG.S05_READ_ACCEPTANCE {1} \ +CONFIG.S06_READ_ACCEPTANCE {1} \ +CONFIG.S07_READ_ACCEPTANCE {1} \ +CONFIG.S08_READ_ACCEPTANCE {1} \ +CONFIG.S09_READ_ACCEPTANCE {1} \ +CONFIG.S10_READ_ACCEPTANCE {1} \ +CONFIG.S11_READ_ACCEPTANCE {1} \ +CONFIG.S12_READ_ACCEPTANCE {1} \ +CONFIG.S13_READ_ACCEPTANCE {1} \ +CONFIG.S14_READ_ACCEPTANCE {1} \ +CONFIG.S15_READ_ACCEPTANCE {1} \ +CONFIG.M00_WRITE_ISSUING {1} \ +CONFIG.M01_WRITE_ISSUING {1} \ +CONFIG.M02_WRITE_ISSUING {1} \ +CONFIG.M03_WRITE_ISSUING {1} \ +CONFIG.M04_WRITE_ISSUING {1} \ +CONFIG.M05_WRITE_ISSUING {1} \ +CONFIG.M06_WRITE_ISSUING {1} \ +CONFIG.M07_WRITE_ISSUING {1} \ +CONFIG.M08_WRITE_ISSUING {1} \ +CONFIG.M09_WRITE_ISSUING {1} \ +CONFIG.M10_WRITE_ISSUING {1} \ +CONFIG.M11_WRITE_ISSUING {1} \ +CONFIG.M12_WRITE_ISSUING {1} \ +CONFIG.M13_WRITE_ISSUING {1} \ +CONFIG.M14_WRITE_ISSUING {1} \ +CONFIG.M15_WRITE_ISSUING {1} \ +CONFIG.M00_READ_ISSUING {1} \ +CONFIG.M01_READ_ISSUING {1} \ +CONFIG.M02_READ_ISSUING {1} \ +CONFIG.M03_READ_ISSUING {1} \ +CONFIG.M04_READ_ISSUING {1} \ +CONFIG.M05_READ_ISSUING {1} \ +CONFIG.M06_READ_ISSUING {1} \ +CONFIG.M07_READ_ISSUING {1} \ +CONFIG.M08_READ_ISSUING {1} \ +CONFIG.M09_READ_ISSUING {1} \ +CONFIG.M10_READ_ISSUING {1} \ +CONFIG.M11_READ_ISSUING {1} \ +CONFIG.M12_READ_ISSUING {1} \ +CONFIG.M13_READ_ISSUING {1} \ +CONFIG.M14_READ_ISSUING {1} \ +CONFIG.M15_READ_ISSUING {1} \ +CONFIG.S00_SINGLE_THREAD {1} \ +CONFIG.M00_A00_ADDR_WIDTH {16} \ +CONFIG.M01_A00_ADDR_WIDTH {16} \ +CONFIG.M02_A00_ADDR_WIDTH {16} \ +CONFIG.M00_A00_BASE_ADDR {0x0000000000000000}\ +CONFIG.M01_A00_BASE_ADDR {0x0000000000010000}\ +CONFIG.M02_A00_BASE_ADDR {0x0000000000020000}] [get_ips axi_crossbar_0] +set_property generate_synth_checkpoint false [get_files axi_crossbar_0.xci] +reset_target all [get_ips axi_crossbar_0] +generate_target all [get_ips axi_crossbar_0] + +create_ip -name axi_clock_converter -vendor xilinx.com -library ip -module_name axi_clock_converter_0 +set_property -dict { + CONFIG.PROTOCOL {AXI4LITE} + CONFIG.DATA_WIDTH {32} + CONFIG.ID_WIDTH {0} + CONFIG.AWUSER_WIDTH {0} + CONFIG.ARUSER_WIDTH {0} + CONFIG.RUSER_WIDTH {0} + CONFIG.WUSER_WIDTH {0} + CONFIG.BUSER_WIDTH {0} + CONFIG.SI_CLK.FREQ_HZ {250000000} + CONFIG.MI_CLK.FREQ_HZ ${datapath_freq_mhz}000000 + CONFIG.ACLK_ASYNC {1} + CONFIG.SYNCHRONIZATION_STAGES {3} +} [get_ips axi_clock_converter_0] +set_property generate_synth_checkpoint false [get_files axi_clock_converter_0.xci] +reset_target all [get_ips axi_clock_converter_0] +generate_target all [get_ips axi_clock_converter_0] + +#Add a clock wizard +create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name clk_wiz_1 +if {[string match "${datapath_freq_mhz}" "200"]} { +#200MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {200.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {6.000} \ + CONFIG.CLKOUT1_JITTER {119.392} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "250"]} { +#250MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {250.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {1} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {4.750} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.750} \ + CONFIG.CLKOUT1_JITTER {85.152} \ + CONFIG.CLKOUT1_PHASE_ERROR {78.266}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "260"]} { +#260MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {260.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {120.250} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.625} \ + CONFIG.CLKOUT1_JITTER {182.359} \ + CONFIG.CLKOUT1_PHASE_ERROR {351.991}] [get_ips clk_wiz_10] +} elseif {[string match "${datapath_freq_mhz}" "280"]} { +#280MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {280.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {119.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.250} \ + CONFIG.CLKOUT1_JITTER {183.720} \ + CONFIG.CLKOUT1_PHASE_ERROR {357.524}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "300"]} { +#300MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {300.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.000} \ + CONFIG.CLKOUT1_JITTER {111.430} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "320"]} { +#320MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {320.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.750} \ + CONFIG.CLKOUT1_JITTER {110.215} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "340"]} { +#340MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {340.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {119.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.500} \ + CONFIG.CLKOUT1_JITTER {179.007} \ + CONFIG.CLKOUT1_PHASE_ERROR {357.524}] [get_ips clk_wiz_1] +} else { + puts "Error: the specified clock is error" + exit -1 +} +#360MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {360.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {25} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {121.500} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.375} \ +# CONFIG.CLKOUT1_JITTER {171.636} \ +# CONFIG.CLKOUT1_PHASE_ERROR {346.603}] [get_ips clk_wiz_1] +#380MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {380.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {1} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {4.750} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.125} \ +# CONFIG.CLKOUT1_JITTER {78.466} \ +# CONFIG.CLKOUT1_PHASE_ERROR {78.266}] [get_ips clk_wiz_1] +#400MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {400.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {5} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.000} \ +# CONFIG.CLKOUT1_JITTER {106.119} \ +# CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +set_property generate_synth_checkpoint false [get_files clk_wiz_1.xci] +reset_target all [get_ips clk_wiz_1] +generate_target all [get_ips clk_wiz_1] + +read_verilog "./hdl/nf_datapath.v" +read_verilog -sv "${public_repo_dir}/common/hdl/top_wrapper.sv" +read_verilog -sv "${public_repo_dir}/common/hdl/nf_attachment.sv" +read_verilog "${public_repo_dir}/common/hdl/top.v" + +#Setting Synthesis options +create_run -flow {Vivado Synthesis 2020} synth +set_property write_incremental_synth_checkpoint true [get_runs synth_1] +set_property AUTO_INCREMENTAL_CHECKPOINT 1 [get_runs synth_1] +#Setting Implementation options +create_run impl -parent_run synth -flow {Vivado Implementation 2020} +set_property strategy Performance_ExplorePostRoutePhysOpt [get_runs impl_1] +set_property steps.phys_opt_design.is_enabled true [get_runs impl_1] +set_property STEPS.PHYS_OPT_DESIGN.ARGS.DIRECTIVE ExploreWithHoldFix [get_runs impl_1] +set_property STEPS.PLACE_DESIGN.ARGS.DIRECTIVE Explore [get_runs impl_1] +set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.is_enabled true [get_runs impl_1] + +set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.ARGS.DIRECTIVE AggressiveExplore [get_runs impl_1] +# The following implementation options will increase runtime, but get the best timing results +set_property SEVERITY {Warning} [get_drc_checks UCIO-1] +launch_runs synth +wait_on_run synth +launch_runs impl_1 +wait_on_run impl_1 +open_checkpoint project/${design}.runs/impl_1/top_postroute_physopt.dcp + +if {![file exists "../bitfiles"]} { + file mkdir "../bitfiles" +} +write_bitstream -force ../bitfiles/${design}_${board_name}.bit +write_debug_probes -file ../bitfiles/${design}_${board_name}.ltx -force + +# -- For Report -- +set end_time [exec date +%s] +set elapsed_time [expr ${end_time} - ${start_time}] +if {[catch {exec grep -A 4 "VIOLAT" project/${design}.runs/impl_1/top_timing_summary_postroute_physopted.rpt} timing_report_data]} { + set timing_report "Met" + set timing_report_data "" +} else { + set timing_report "VIOLATED" +} +puts " --- Report : ${design} for ${board_name} --- " +puts " Synth time : ${elapsed_time}" +puts " Timing Closure: ${timing_report}" +puts "${timing_report_data}" + +exit + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl new file mode 100644 index 0000000..75e1d79 --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl @@ -0,0 +1,81 @@ +# +# Copyright (c) 2015 Noa Zilberman +# Copyright (c) 2021 Yuta Tokusashi +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + + +####################### +# Segments Assignment # +####################### +#M00 +set M00_BASEADDR 0x00010000 +set M00_HIGHADDR 0x00010FFF +set M00_SIZEADDR 0x1000 + +#M01 +set M01_BASEADDR 0x00020000 +set M01_HIGHADDR 0x00020FFF +set M01_SIZEADDR 0x1000 + +#M02 +set M02_BASEADDR 0x00030000 +set M02_HIGHADDR 0x00030FFF +set M02_SIZEADDR 0x1000 + +##M03 +#set M03_BASEADDR 0x44030000 +#set M03_HIGHADDR 0x44030FFF +#set M03_SIZEADDR 0x1000 +# + +####################### +# IP_ASSIGNMENT # +####################### +# Note that physical connectivity must match this mapping + +##IDENTIFIER base address and size +#set IDENTIFIER_BASEADDR $M00_BASEADDR +#set IDENTIFIER_HIGHADDR $M00_HIGHADDR +#set IDENTIFIER_SIZEADDR $M00_SIZEADDR + + +#INPUT ARBITER base address and size +set INPUT_ARBITER_BASEADDR $M00_BASEADDR +set INPUT_ARBITER_HIGHADDR $M00_HIGHADDR +set INPUT_ARBITER_SIZEADDR $M00_SIZEADDR + +#OUTPUT_QUEUES base address and size +set OUTPUT_QUEUES_BASEADDR $M02_BASEADDR +set OUTPUT_QUEUES_HIGHADDR $M02_HIGHADDR +set OUTPUT_QUEUES_SIZEADDR $M02_SIZEADDR + +#OUPUT_PORT_LOOKUP base address and size +set OUTPUT_PORT_LOOKUP_BASEADDR $M01_BASEADDR +set OUTPUT_PORT_LOOKUP_HIGHADDR $M01_HIGHADDR +set OUTPUT_PORT_LOOKUP_SIZEADDR $M01_SIZEADDR + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl new file mode 100644 index 0000000..152b5db --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl @@ -0,0 +1,253 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +#### Change design settings here ####### +set design $::env(NF_PROJECT_NAME) +set top top_sim +set sim_top top_tb +set device $::env(DEVICE) +set board $::env(BOARD) +set board_name $::env(BOARD_NAME) + +set proj_dir ./project +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib/ +set repo_dir ./ip_repo +set project_constraints ./constraints/${board_name}_switch.xdc + +set test_name [lindex $argv 0] +source $::env(NF_DESIGN_DIR)/hw/tcl/$::env(NF_PROJECT_NAME)_defines.tcl + +set_param general.maxThreads 8 +##################################### +# Design Parameters on NF_DATAPATH +##################################### +set datapath_width_bit 1024 +set opl_bcam_size 16 + +set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Project Settings +##################################### +create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} +set_property board_part ${board} [current_project] +set_property source_mgmt_mode DisplayOnly [current_project] +set_property top ${top} [current_fileset] +puts "Creating User Datapath reference project" +##################################### +# set IP paths +##################################### +create_fileset -constrset -quiet constraints +file copy ${public_repo_dir}/ ${repo_dir} +set_property ip_repo_paths ${repo_dir} [current_fileset] + +##################################### +# Project +##################################### +update_ip_catalog +# OPL +create_ip -name switch_output_port_lookup -vendor NetFPGA -library NetFPGA -module_name switch_output_port_lookup_ip +set_property CONFIG.C_CAM_LUT_DEPTH_BITS ${opl_cam_depth_bits} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property generate_synth_checkpoint false [get_files switch_output_port_lookup_ip.xci] +reset_target all [get_ips switch_output_port_lookup_ip] +generate_target all [get_ips switch_output_port_lookup_ip] +# input_arbiter +create_ip -name input_arbiter -vendor NetFPGA -library NetFPGA -module_name input_arbiter_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property generate_synth_checkpoint false [get_files input_arbiter_ip.xci] +reset_target all [get_ips input_arbiter_ip] +generate_target all [get_ips input_arbiter_ip] +# output_queues +create_ip -name output_queues -vendor NetFPGA -library NetFPGA -module_name output_queues_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property generate_synth_checkpoint false [get_files output_queues_ip.xci] +reset_target all [get_ips output_queues_ip] +generate_target all [get_ips output_queues_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_ip.xci] +reset_target all [get_ips nf_mac_attachment_ip] +generate_target all [get_ips nf_mac_attachment_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_dma_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_DEFAULT_VALUE_ENABLE 0 [get_ips nf_mac_attachment_dma_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_dma_ip.xci] +reset_target all [get_ips nf_mac_attachment_dma_ip] +generate_target all [get_ips nf_mac_attachment_dma_ip] + +create_ip -name barrier -vendor NetFPGA -library NetFPGA -module_name barrier_ip +reset_target all [get_ips barrier_ip] +generate_target all [get_ips barrier_ip] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip0 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/nf_interface_0_log.axi] [get_ips axis_sim_record_ip0] +reset_target all [get_ips axis_sim_record_ip0] +generate_target all [get_ips axis_sim_record_ip0] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip1 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/nf_interface_1_log.axi] [get_ips axis_sim_record_ip1] +reset_target all [get_ips axis_sim_record_ip1] +generate_target all [get_ips axis_sim_record_ip1] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip2 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/dma_0_log.axi] [get_ips axis_sim_record_ip2] +reset_target all [get_ips axis_sim_record_ip2] +generate_target all [get_ips axis_sim_record_ip2] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip0 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/nf_interface_0_stim.axi] [get_ips axis_sim_stim_ip0] +generate_target all [get_ips axis_sim_stim_ip0] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip1 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/nf_interface_1_stim.axi] [get_ips axis_sim_stim_ip1] +generate_target all [get_ips axis_sim_stim_ip1] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip2 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/dma_0_stim.axi] [get_ips axis_sim_stim_ip2] +generate_target all [get_ips axis_sim_stim_ip2] + +create_ip -name axi_sim_transactor -vendor NetFPGA -library NetFPGA -module_name axi_sim_transactor_ip +set_property -dict [list CONFIG.STIM_FILE $::env(NF_DESIGN_DIR)/test/reg_stim.axi CONFIG.EXPECT_FILE $::env(NF_DESIGN_DIR)/test/reg_expect.axi CONFIG.LOG_FILE $::env(NF_DESIGN_DIR)/test/reg_stim.log] [get_ips axi_sim_transactor_ip] +reset_target all [get_ips axi_sim_transactor_ip] +generate_target all [get_ips axi_sim_transactor_ip] + + +create_ip -name axi_crossbar -vendor xilinx.com -library ip -module_name axi_crossbar_0 +set_property -dict [list \ +CONFIG.NUM_MI {3} \ +CONFIG.PROTOCOL {AXI4LITE} \ +CONFIG.CONNECTIVITY_MODE {SASD} \ +CONFIG.R_REGISTER {1} \ +CONFIG.S00_WRITE_ACCEPTANCE {1} \ +CONFIG.S01_WRITE_ACCEPTANCE {1} \ +CONFIG.S02_WRITE_ACCEPTANCE {1} \ +CONFIG.S03_WRITE_ACCEPTANCE {1} \ +CONFIG.S04_WRITE_ACCEPTANCE {1} \ +CONFIG.S05_WRITE_ACCEPTANCE {1} \ +CONFIG.S06_WRITE_ACCEPTANCE {1} \ +CONFIG.S07_WRITE_ACCEPTANCE {1} \ +CONFIG.S08_WRITE_ACCEPTANCE {1} \ +CONFIG.S09_WRITE_ACCEPTANCE {1} \ +CONFIG.S10_WRITE_ACCEPTANCE {1} \ +CONFIG.S11_WRITE_ACCEPTANCE {1} \ +CONFIG.S12_WRITE_ACCEPTANCE {1} \ +CONFIG.S13_WRITE_ACCEPTANCE {1} \ +CONFIG.S14_WRITE_ACCEPTANCE {1} \ +CONFIG.S15_WRITE_ACCEPTANCE {1} \ +CONFIG.S00_READ_ACCEPTANCE {1} \ +CONFIG.S01_READ_ACCEPTANCE {1} \ +CONFIG.S02_READ_ACCEPTANCE {1} \ +CONFIG.S03_READ_ACCEPTANCE {1} \ +CONFIG.S04_READ_ACCEPTANCE {1} \ +CONFIG.S05_READ_ACCEPTANCE {1} \ +CONFIG.S06_READ_ACCEPTANCE {1} \ +CONFIG.S07_READ_ACCEPTANCE {1} \ +CONFIG.S08_READ_ACCEPTANCE {1} \ +CONFIG.S09_READ_ACCEPTANCE {1} \ +CONFIG.S10_READ_ACCEPTANCE {1} \ +CONFIG.S11_READ_ACCEPTANCE {1} \ +CONFIG.S12_READ_ACCEPTANCE {1} \ +CONFIG.S13_READ_ACCEPTANCE {1} \ +CONFIG.S14_READ_ACCEPTANCE {1} \ +CONFIG.S15_READ_ACCEPTANCE {1} \ +CONFIG.M00_WRITE_ISSUING {1} \ +CONFIG.M01_WRITE_ISSUING {1} \ +CONFIG.M02_WRITE_ISSUING {1} \ +CONFIG.M03_WRITE_ISSUING {1} \ +CONFIG.M04_WRITE_ISSUING {1} \ +CONFIG.M05_WRITE_ISSUING {1} \ +CONFIG.M06_WRITE_ISSUING {1} \ +CONFIG.M07_WRITE_ISSUING {1} \ +CONFIG.M08_WRITE_ISSUING {1} \ +CONFIG.M09_WRITE_ISSUING {1} \ +CONFIG.M10_WRITE_ISSUING {1} \ +CONFIG.M11_WRITE_ISSUING {1} \ +CONFIG.M12_WRITE_ISSUING {1} \ +CONFIG.M13_WRITE_ISSUING {1} \ +CONFIG.M14_WRITE_ISSUING {1} \ +CONFIG.M15_WRITE_ISSUING {1} \ +CONFIG.M00_READ_ISSUING {1} \ +CONFIG.M01_READ_ISSUING {1} \ +CONFIG.M02_READ_ISSUING {1} \ +CONFIG.M03_READ_ISSUING {1} \ +CONFIG.M04_READ_ISSUING {1} \ +CONFIG.M05_READ_ISSUING {1} \ +CONFIG.M06_READ_ISSUING {1} \ +CONFIG.M07_READ_ISSUING {1} \ +CONFIG.M08_READ_ISSUING {1} \ +CONFIG.M09_READ_ISSUING {1} \ +CONFIG.M10_READ_ISSUING {1} \ +CONFIG.M11_READ_ISSUING {1} \ +CONFIG.M12_READ_ISSUING {1} \ +CONFIG.M13_READ_ISSUING {1} \ +CONFIG.M14_READ_ISSUING {1} \ +CONFIG.M15_READ_ISSUING {1} \ +CONFIG.S00_SINGLE_THREAD {1} \ +CONFIG.M00_A00_ADDR_WIDTH {16} \ +CONFIG.M01_A00_ADDR_WIDTH {16} \ +CONFIG.M02_A00_ADDR_WIDTH {16} \ +CONFIG.M00_A00_BASE_ADDR {0x0000000000010000}\ +CONFIG.M01_A00_BASE_ADDR {0x0000000000020000}\ +CONFIG.M02_A00_BASE_ADDR {0x0000000000030000}] [get_ips axi_crossbar_0] +set_property generate_synth_checkpoint false [get_files axi_crossbar_0.xci] +reset_target all [get_ips axi_crossbar_0] +generate_target all [get_ips axi_crossbar_0] + + +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/nf_datapath.v" +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/top_sim.v" +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/top_tb.v" + + +update_compile_order -fileset sources_1 +update_compile_order -fileset sim_1 + +set_property top ${sim_top} [get_filesets sim_1] +set_property include_dirs ${proj_dir} [get_filesets sim_1] +set_property simulator_language Mixed [current_project] +set_property verilog_define { {SIMULATION=1} } [get_filesets sim_1] +set_property -name xsim.more_options -value {-testplusarg TESTNAME=basic_test} -objects [get_filesets sim_1] +set_property runtime {} [get_filesets sim_1] +set_property target_simulator xsim [current_project] +set_property compxlib.compiled_library_dir {} [current_project] +set_property top_lib xil_defaultlib [get_filesets sim_1] +update_compile_order -fileset sim_1 + +unset env(PYTHONPATH) +unset env(PYTHONHOME) +set env(PYTHONPATH) ".:$::env(NFPLUS_FOLDER)/tools/scripts/:$::env(NFPLUS_FOLDER)/tools/scripts/NFTest" +set output [exec $::env(PYTHON_BNRY) $::env(NF_DESIGN_DIR)/test/${test_name}/run.py] +puts $output + +launch_simulation -simset sim_1 -mode behavioral +run 10us + diff --git a/hw/projects/reference_dma/test/both_learning_sw/run.py b/hw/projects/reference_dma/test/both_learning_sw/run.py new file mode 100755 index 0000000..ba80527 --- /dev/null +++ b/hw/projects/reference_dma/test/both_learning_sw/run.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# Copyright (c) 2015 Neelakandan Manihatty Bojan, Georgina Kalogeridou +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# Author: +# Modified by Neelakandan Manihatty Bojan, Georgina Kalogeridou + +import logging +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) + +from NFTest import * +import sys +import os +from scapy.layers.all import Ether, IP, TCP +from reg_defines_reference_dma import * + +phy2loop0 = ('../connections/conn', []) +nftest_init(sim_loop = [], hw_config = [phy2loop0]) + + +if isHW(): + # Clearing the LUT_HIT and LUT_MISS by asserting the reset_counters + nftest_regwrite(NFPLUS_INPUT_ARBITER_0_RESET(), 0x1) + nftest_regwrite(NFPLUS_OUTPUT_PORT_LOOKUP_0_RESET(), 0x101) + nftest_regwrite(NFPLUS_OUTPUT_QUEUES_0_RESET(), 0x1) + + # Reset the switch table lookup counters (value is reset every time is read) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT()) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS()) + +nftest_start() + + +routerMAC = [] +routerIP = [] +for i in range(2): + routerMAC.append("00:0a:35:03:00:0%d"%(i+1)) + routerIP.append("192.168.%s.40"%i) + +num_broadcast = 10 + +pkts = [] +pkta = [] +for i in range(num_broadcast): + pkt = make_IP_pkt(src_MAC="aa:bb:cc:dd:ee:ff", dst_MAC=routerMAC[0], + src_IP="192.168.0.1", dst_IP="192.168.1.1", pkt_len=512) + + pkt.time = ((i*(1e-8)) + (2e-6)) + pkts.append(pkt) + if isHW(): + nftest_send_phy('nf0', pkt) + nftest_expect_phy('nf1', pkt) + +if not isHW(): + nftest_send_phy('nf0', pkts) + nftest_expect_phy('nf1', pkts) + +nftest_barrier() + +num_normal = 10 + +for i in range(num_normal): + pkt = make_IP_pkt(dst_MAC="aa:bb:cc:dd:ee:ff", src_MAC=routerMAC[1], + src_IP="192.168.0.1", dst_IP="192.168.1.1", pkt_len=512) + pkt.time = (((i+5)*(1e-8)) + (2e-6)) + pkta.append(pkt) + if isHW(): + nftest_send_phy('nf1', pkt) + nftest_expect_phy('nf0', pkt) + +if not isHW(): + nftest_send_phy('nf1', pkta) + nftest_expect_phy('nf0', pkta) + +nftest_barrier() + +if isHW(): + # Now we expect to see the lut_hit and lut_miss registers incremented and we + # verify this by doing a regread_expect + rres1= nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), num_normal) + rres2= nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) + # List containing the return values of the reg_reads + mres=[rres1,rres2] +else: + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), num_normal) # lut_hit + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) # lut_miss + mres=[] + +nftest_finish(mres) diff --git a/hw/projects/reference_dma/test/both_simple_broadcast/run.py b/hw/projects/reference_dma/test/both_simple_broadcast/run.py new file mode 100755 index 0000000..10aa9ae --- /dev/null +++ b/hw/projects/reference_dma/test/both_simple_broadcast/run.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# Copyright (c) 2015 Neelakandan Manihatty Bojan, Georgina Kalogeridou +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# Author: +# Modified by Neelakandan Manihatty Bojan, Georgina Kalogeridou + +import logging +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) + +from NFTest import * +import sys +import os +from scapy.layers.all import Ether, IP, TCP +from reg_defines_reference_dma import * + +phy2loop0 = ('../connections/conn', []) +nftest_init(sim_loop = [], hw_config = [phy2loop0]) + +if isHW(): + # reset_counters (triggered by Write only event) for all the modules + nftest_regwrite(NFPLUS_INPUT_ARBITER_0_RESET(), 0x1) + nftest_regwrite(NFPLUS_OUTPUT_PORT_LOOKUP_0_RESET(), 0x101) + nftest_regwrite(NFPLUS_OUTPUT_QUEUES_0_RESET(), 0x1) + + # Reset the switch table lookup counters (value is reset every time is read) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT()) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS()) + +nftest_start() + + +routerMAC = [] +routerIP = [] +for i in range(2): + routerMAC.append("00:0a:35:03:00:0%d"%(i+1)) + routerIP.append("192.168.%s.40"%i) + +num_broadcast = 20 + +pkts = [] +for i in range(num_broadcast): + pkt = make_IP_pkt(src_MAC="aa:bb:cc:dd:ee:ff", dst_MAC=routerMAC[0], + EtherType=0x800, src_IP="192.168.0.1", + dst_IP="192.168.1.1", pkt_len=60) + + pkt.time = ((i*(1e-8)) + (2e-6)) + pkts.append(pkt) + if isHW(): + nftest_expect_phy('nf1', pkt) + nftest_send_phy('nf0', pkt) + +if not isHW(): + nftest_send_phy('nf0', pkts) + nftest_expect_phy('nf1', pkts) + +nftest_barrier() + +if isHW(): + # Expecting the LUT_MISS counter to be incremented by 0x14, 20 packets + rres1=nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) + rres2=nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), 0) + mres=[rres1,rres2] +else: + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) # lut_miss + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), 0) # lut_hit + mres=[] + +nftest_finish(mres) diff --git a/hw/projects/reference_dma/test/connections/conn b/hw/projects/reference_dma/test/connections/conn new file mode 100644 index 0000000..0827e9b --- /dev/null +++ b/hw/projects/reference_dma/test/connections/conn @@ -0,0 +1,30 @@ +# +# Copyright (c) 2015 University of Cambridge +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + + +nf0:eth1 +nf1:eth2 diff --git a/hw/projects/reference_dma/test/global/setup b/hw/projects/reference_dma/test/global/setup new file mode 100644 index 0000000..1d4cdb9 --- /dev/null +++ b/hw/projects/reference_dma/test/global/setup @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +from subprocess import Popen, PIPE + +proc = Popen(["ifconfig","eth1","192.168.100.1"], stdout=PIPE) +proc = Popen(["ifconfig","eth2","192.168.101.1"], stdout=PIPE) +proc = Popen(["ifconfig","nf0","192.168.200.1"], stdout=PIPE) +proc = Popen(["ifconfig","nf1","192.168.201.1"], stdout=PIPE) diff --git a/tools/settings.sh b/tools/settings.sh index 368218b..9c2e459 100644 --- a/tools/settings.sh +++ b/tools/settings.sh @@ -25,7 +25,7 @@ ### User defined export NFPLUS_FOLDER=${HOME}/NetFPGA-PLUS-GW export BOARD_NAME=au250 -export NF_PROJECT_NAME=reference_switch +export NF_PROJECT_NAME=reference_dma export PYTHON_BNRY=/usr/bin/python3 ### Don't change From feead6d721d87d3c15e9a683f1945cbd55e422f3 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Wed, 24 Jan 2024 12:20:20 -0800 Subject: [PATCH 05/28] updated opennic-driver.patch --- sw/driver/opennic-driver.patch | 85 ++++++++++++++-------------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/sw/driver/opennic-driver.patch b/sw/driver/opennic-driver.patch index a33a7bd..9ecf90e 100644 --- a/sw/driver/opennic-driver.patch +++ b/sw/driver/opennic-driver.patch @@ -36,16 +36,26 @@ diff -uprN ./onic_hardware.h ./onic_hardware.h diff -uprN ./onic_main.c ./onic_main.c --- ./onic_main.c 2023-12-07 12:27:36.237535443 +0000 +++ ./onic_main.c 2023-12-07 12:33:38.980629056 +0000 -@@ -129,6 +129,7 @@ static const struct net_device_ops onic_ +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include "onic.h" + #include "onic_hardware.h" +@@ -129,6 +130,9 @@ static const struct net_device_ops onic_ .ndo_start_xmit = onic_xmit_frame, .ndo_set_mac_address = onic_set_mac_address, .ndo_do_ioctl = onic_do_ioctl, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) + .ndo_siocdevprivate = onic_siocdevprivate, ++#endif .ndo_change_mtu = onic_change_mtu, .ndo_get_stats64 = onic_get_stats64, }; -@@ -203,7 +204,9 @@ static int onic_probe(struct pci_dev *pd - +@@ -203,7 +207,9 @@ static int onic_probe(struct pci_dev *pd + memset(&saddr, 0, sizeof(struct sockaddr)); memcpy(saddr.sa_data, onic_default_dev_addr, 6); - get_random_bytes(saddr.sa_data + 3, 3); @@ -53,12 +63,12 @@ diff -uprN ./onic_main.c ./onic_main.c + saddr.sa_data[4] = PCI_SLOT(pdev->devfn); + saddr.sa_data[5] = PCI_FUNC(pdev->devfn); onic_set_mac_address(netdev, (void *)&saddr); - + priv = netdev_priv(netdev); -@@ -241,6 +244,15 @@ static int onic_probe(struct pci_dev *pd +@@ -241,6 +247,15 @@ static int onic_probe(struct pci_dev *pd netif_set_real_num_tx_queues(netdev, priv->num_tx_queues); netif_set_real_num_rx_queues(netdev, priv->num_rx_queues); - + +#ifdef NF_IOCTL + rv = onic_create_nfdp_dev(&priv->hw.nfdp_handle, priv->pdev); + if (rv < 0) { @@ -81,7 +91,7 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c +#ifdef NF_IOCTL +#define NFDP_OFFSET 0x0000 -+#define NFDP_END 0x70000 ++#define NFDP_END 0x400000 +#define NFDP_MAXLEN NFDP_END - NFDP_OFFSET + +#define NFDP_IOCTL_CMD_WRITE_REG (SIOCDEVPRIVATE+1) @@ -208,9 +218,12 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c int onic_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *saddr = addr; -@@ -758,6 +877,90 @@ int onic_set_mac_address(struct net_devi +@@ -756,11 +875,61 @@ int onic_set_mac_address(struct net_devi + return 0; + } - int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +-int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++int nf_onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { +#ifdef NF_IOCTL + struct onic_private *priv = netdev_priv(dev); @@ -251,53 +264,23 @@ diff -uprN ./onic_netdev.c ./onic_netdev.c + break; + } +#endif /*NF_IOCTL*/ -+ return 0; + return 0; + } + ++int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ return nf_onic_do_ioctl(dev, ifr, cmd); +} + +int onic_siocdevprivate(struct net_device *dev, struct ifreq *ifr, + void *data, int cmd) +{ -+#ifdef NF_IOCTL -+ struct onic_private *priv = netdev_priv(dev); -+ struct nfdp_dev *nfdev = onic_get_nfdp_dev(priv->hw.nfdp_handle); -+ struct onic_ioctl_ifreq sifr; -+ int err; ++ return nf_onic_do_ioctl(dev, ifr, cmd); ++} + -+ switch(cmd) { -+ case NFDP_IOCTL_CMD_WRITE_REG: -+ err = copy_from_user(&sifr, ifr->ifr_data, -+ sizeof(struct onic_ioctl_ifreq)); -+ if (err != 0) { -+ err = -EFAULT; -+ break; -+ } -+ err = ioctl_write_reg(nfdev, &sifr); -+ break; -+ case NFDP_IOCTL_CMD_READ_REG: -+ err = copy_from_user(&sifr, ifr->ifr_data, -+ sizeof(struct onic_ioctl_ifreq)); -+ if (err != 0) { -+ err = -EFAULT; -+ break; -+ } -+ err = ioctl_read_reg(nfdev, &sifr); -+ if (err != 0) { -+ err = -EFAULT; -+ break; -+ } -+ err = copy_to_user(ifr->ifr_data, &sifr, -+ sizeof(struct onic_ioctl_ifreq)); -+ if (err != 0) -+ err = -EFAULT; -+ break; -+ default: -+ pr_info("unspported ioctl 0x%8x", cmd); -+ err = -EOPNOTSUPP; -+ break; -+ } -+#endif /*NF_IOCTL*/ - return 0; - } + int onic_change_mtu(struct net_device *dev, int mtu) + { + netdev_info(dev, "Requested MTU = %d", mtu); diff -uprN ./onic_netdev.h ./onic_netdev.h --- ./onic_netdev.h 2023-12-07 12:27:36.237535443 +0000 @@ -305,7 +288,7 @@ diff -uprN ./onic_netdev.h ./onic_netdev.h @@ -43,10 +43,32 @@ int onic_set_mac_address(struct net_devi int onic_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); - + +int onic_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void *data, int cmd); + int onic_change_mtu(struct net_device *dev, int mtu); From 7192053aa191f49cec96f5e1b2e385587b04d63e Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Fri, 26 Jan 2024 11:10:56 -0800 Subject: [PATCH 06/28] Simple send_pkt using scapy --- sw/app/pkt_send/send_pkt.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 sw/app/pkt_send/send_pkt.py diff --git a/sw/app/pkt_send/send_pkt.py b/sw/app/pkt_send/send_pkt.py new file mode 100644 index 0000000..97c1896 --- /dev/null +++ b/sw/app/pkt_send/send_pkt.py @@ -0,0 +1,7 @@ +from scapy.all import * + +# create a TCP SYN packet with IP and Ethernet layers +packet = Ether()/IP(dst="192.168.1.250")/TCP(dport=80, flags="S") + +# send the packet using the eth0 interface +sendp(packet, iface="nf0") From 609805209211292b6b23e1d661e052bacd708b85 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Tue, 30 Jan 2024 15:23:32 -0800 Subject: [PATCH 07/28] Modified nf_data_sink_v1_0_0 to have measure pkts, bytes amd time --- .../data/module_generation_nf_data_sink.ods | Bin 0 -> 40846 bytes .../data/module_generation_nf_data_sink.xlsm | Bin 17251 -> 0 bytes .../data/nf_data_sink_defines.tcl | 56 - .../data/nf_data_sink_defines.txt | 56 - .../data/nf_data_sink_regs_defines.h | 78 +- .../std/nf_data_sink_v1_0_0/data/regs_gen.py | 1856 +++++++++++++++++ .../data/regs_template.txt | 1787 ++++++++++++++++ .../nf_data_sink_v1_0_0/hdl/nf_data_sink.v | 169 +- .../std/nf_data_sink_v1_0_0/nf_data_sink.tcl | 5 +- .../reference_dma/hw/hdl/nf_datapath.v | 62 +- .../reference_dma/hw/tcl/reference_dma.tcl | 7 + tools/infrastructure/regs_template.txt | 1787 ++++++++++++++++ 12 files changed, 5631 insertions(+), 232 deletions(-) create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods delete mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm delete mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl delete mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py create mode 100644 hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt create mode 100644 tools/infrastructure/regs_template.txt diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods new file mode 100644 index 0000000000000000000000000000000000000000..ad8c7c4db955eb50eb3c8bdcae29448ae13c5949 GIT binary patch literal 40846 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%0A{0+=W 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 Tw&DG5wR;=G7JWpV{Jr;oXRSZ= literal 0 HcmV?d00001 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.xlsm deleted file mode 100644 index aa4f658e2ee284ad562f8b32041975843782f861..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17251 zcmbVzV_+p)vuHB0ZQGpKm?RV1wrx*r+qP|MVmq1Gwv(4R=e~E&ckaFC$E&@&_v+QV zs=I5gF0CpVaUfu10B~?{0Kg0u6@b41)Ms1U&d|c1j`sJyBDP1Wj~+Vk!abDofq9(| zJg2Zt;(Hqb6K*%L6;?w?UccY<{Wl~;=!n|BNLw%OcfEpN5?0i|=t;%3LKIa)zI2f4 zdlvPNzT3Lev5e<>4I;3K$XN?g+C@o=-HvVXkL0^MM2kTl-bjj110Lv~8US$f1=(pT zIy1f-1n>K+o`xgZ8Y|^4c>}lmOIn&UTZ!UfyYYP8Rwj%iaQZ1Gk>^pw){Y2c7zpY5 z%h0oBbmJl(76Y38yCgyq!T$MA)Y+y;g17k5qvT|y)|P!c8@*f5@peRidSeH7Ng~hh z66aYcIA68J!qhTfNB5Cr#KFJ=QkhcEKbbJ`1pq+ie`OQg=RaI5=$x(X%=N6T&1qdM zEh6M4qgLqQJ06t3bqex4lH>P=g3f4`tSeQob8`;+H?uhzz(Lg?dtVR}#Fx4s5`=K$ zcDY*rGVpSyEVzLjgsc$Qf8gH#A?8RrM{BT=x&6zZ9kpeoc@9#*33T)v^t%b5x?PS+82#4|znmM5 z{OXyb9N++&V8G#+rBwliM4J7U=*u-oI~PUn>sS*JjlwZa4O4GssovSQoKOl*1NJ1; z?+OZeWgcRFyjAT3D?{ipA6yE$M`4W_ZJsg+RnshlT3AACABlf#2m zzE1Ahv2=k(o&x-&3aa>pPAoGkR`alp-!sejw#@d@aN2O($kf(vo}*>akjLkbMkWc3r3DlPHsC?sRA(fi)*`kD&4-Y~9;hz?sm5Q> zIPGnNiYYHOdx|C*tu^GV*%^$h*%jGYNl}rT>2EN`o>H=GnozmTx1D7|lCNbRsXr>V zn;q_}SZ*UO{s}h_zk+uaK5^aG(cZRX-{n4$X@9SGFEPD#6}M;HQ)ECj%+Q z9$2k+gog#-;&r<7^z>A)^@Md@5c@IQlnMi3z>COV*8;q@im^()a&5}{?YZHxV!#%s_kjCjrD5Nr zY~a1%pbMTlA3(-mM}&MrJ5QJ7IEkQKKqW#ZvKln!i!MzshyNWod=6rd&*rzKAJquD zNCGInP(2aV7+a+NX8xG|YW^I+kUf5zLd7B`d?w#a1WYC-i%=TWuiw&SR}(L+MJnLd zg7sr`()6v1DX*M zm|o~SN$?>fJ4s9%N#^8aloQ+M!o$yE2yf|esb5&y&owQ$cW61FIq>U|e6DV)^2>*8D<(4iq@F20XNI&mNzinGs+OQZF9JV-F9k z*k9%Rrs|W!5P*VM4ooB<*WPE=Io31V*wk6@3(LYR+w9AhQt99hgul6(0L&dTvXH!w zQdCeb=8>nm^Ru9Ol|kfrc|~x#?)E8;xcRy14U3W>OlIKog4t5Or^A1w z!Sp1wcFRH*Pg8pJRZDCZ?vhXK_ba7zKkcDAtika8wJghKY<{Iam;2dmOC4h6~B z@%;cDL?FU{EC~c+wuE|FoKc{t2Wy~bXZBrzNdhDuayo3PqWpjZ|AIn?qB9%;JAfh= zhRD;tOUrF#)i(~R(fcE2ZdJ1RZ9pU+uokYo8;5mgKcSiUCEovM-Rk8$BcHrvw(2Dh zlQ~tY&U6O)lqIgkMwmq6jU3FK0t`K(KM!B3Lw1g7)-0461=$|71qLusdNjPq9zQ%z z5?Cu(D&{3W&Pj#hV=|J1b0B_(V!sCFQx*APW-4UQxj}50bWm$goG41gHxI_!db9p6 z2ApfqJ{o>VCSWtnH{DiH7xJjCK|JU?mQsRLB_J5eqj?<2k|-E)3Cuvip*lu~h=w1e z5BP51W(a8yCHy#>n~A@uN>I|L>iy^^1#Row0tff!g7M?bU2ik@%gC7UYb?PncEdEI zSi(tTgV7;Fi$gc%VnU%yeS&W*wn!70mJ+O<@$-1Z9s_-bJCsm8cS=@8@_qJu<1^hs&@4UdI#Jxbvhh|x-S zU|G#9;}vx4>ZxN+LJwR?w)=tVtCRrX;)lHrh3JvSME~3dkX?(@*<(}1CJs%Ay$bg- z4-)w4sipxzgiYUscR9Fos{52V6KPtP9-;b7O5~;;JA4gk+G9;XZM(}} zUVX1~QZbAA=EUd3LB$d2lQc6w<+Jvy=&7R* zhDEkbS3491yr`9DQ{Pp~$yL!EJ&oGI!A`(wjDN#CNJbAuC*oP&tYnm+K(UWLIw(*z zhvh3Q_PmXBxp+KZ>Q*1Q^UsS(VnA>R2<_!JX5#ZzhF^W;6b--wksidu_#ed?1X^D` zsu@}$W^D+>v8G9E$W*&#c z2Jn^qwwfH)0-ESy6%eq0y6?x8lEmh$%Ebik$o9Qvs|^ ziMt-_@)FpzK^aP61T`O~>CG^NhmM6))(wwYhTt0%N!D$2@{YL^GQUptI86X<11a6nLmkA}Qpw=4EvJ2?lJW_+ zA(jO*(8fu^9=dEPPjpmQo-%APBBaUEp8quu$0^x@S0{JL>$()DiI(R6#$43uR;z}* zX=Pmj#)xOdtuy?}Z4@ovIkNOvMvOYqLmujv$Bm<4<27;Xb!;*{oeLKFEGCT#vuXkH z6Qbyrf=9E?NhFW^sCb0}ODz0Sb1iqr=`o zd84v|N3U{Vft#^yq2$1hJAItKO`ucB+B$l5vA$CDUP(_u)mITc zG6@WF6ms-EVa>2C))>k)`3Hp&+G_6NQ}%+?i3wn}C}DH2Isu=4?-{oS?|B zfnNjPwy|CY-t@>Y4C0bHmFur{D)0K#`~0R*M)w!Wqu1d;sBEQtue$0b8Lm{Jw>3Px zR;Rpfwx>mV&yxF|PU13OR!gz#;G97-Q_h@)qL`KN+y*?IE4#M_jEyt#_1e+lq9hP- z3@lmdUh>T|UUIK;V|wSh0&I^go%Sp2UnUZp*U)zAT0`I-z*?GToL<0|t~3GeL-Xvl ztzSg|{0OnXPYcpc{yLH;nH6;IvVFB|pDHS2;dJx(i9p-GUp_V7 z=mnd21MfOmdlh-S*yyTTy6SlwaG&^q^xl7cj`%2bFdu04+E2UoLwTJGbVVyjcfDq)sx(;1doe_{$BR8XpV!nmE z96ty-%$%noE+CphX|v<=g;X{s8dgNH5769K(x^UOmy%dQzR@$%Y|OVd@v4kKSMv*( z^X-*so-GJtfc#q;#4G7xN~1$)hTeW>tRQc5pY0ql)x3IqIkC>e2tOpoq~r?3I-eMo zj!sfBAM+fJ6A6klx~~)sx3E8SW=1vDyjt%oNEKog){62*DIUO@dYMsS4FKH;wTkVx z134K-X@w`;C~*AJ@8sG!#a+o&{%Y#Zfe9YX^w#qsjt& z0u&mSp(M6M{rV1uBNbJ%CPD0DQB4j6q(de7=}^XLEv;8t4?NK3@##o+WS9*2<^c<~s&tF{s6JiqmE<45V%< zl_hCMaOTP)I=#Ardo!gjcwm~=XFv%qc-OQpW62Z%U|@A_t4gobX#=`YxA$g`f}ehz zSH9m3DJyP+QBLTcmo3nFJ8qlZL6uH=6l;j=g*_#C`Nr4=j3l+uXepcv^rFK?-v`(& zJ|CP#qv=COWkec*lSXo58@Z$mC|N*%r_Q5iNT<`>@Vh3#+UWkuhbIbPoaJv^5jmv- ziUCDca;QIxktu6u0l$~c{TLYZW~QXn&-7sYO@?(Zy>;ca>uzYj%B%_t)8~W!8Nr7k z;)fUwLNgvpViLsT3K~Q^F0)Z0_~t1hAhORjFvoTh1pEvlV7ew@Hl;XlbVC3+=!3ZBkXh6or|%A-_YG#8IwGkwsox3OrWjw^s)Bwmg`(WGJTKf**Nen zwF!31Z2FpyKJDIBsJ_}qocNSM^}y>s1?k|Y4*vph*arK?@`LVhk!^gE?n86thj-?? zY;>pa8;R?icy0QHN!Jnhlh+rUpZkk+gY90H8!j!+4I8nPH?Kk0xbzMgiR2>BcbjnT zo1;%s5GrdM3%j!~N{f`KZ%OwfNo8HgTU8NZZ_-xLnr+A$L2v5tnLt_d-W{*Z9jVeZ z${$Mp2RCo#t7k9e@!DV?mf&QG6Pn~uMO><%T5p>S*JOxq=gL6ZoZUTc}o<2FQyhv;j@R8kqGKc z7=ZP@8@`?OHl{QS+RdH*Enh0| zUjT)xm!t9f)MLOx-B$_j`xL}No9`7s2Qk7;Ik%yji5V&=0r04b1}C2vCdMTI7_xWE zIn(AnMN|uAz_D&lD_=*dP+nTSd+vJ%rSR45mMLGeV{JK4#~m9ND5MwT$-+46IP$XL z1<&npUfM{=V~2G|$~6HArxMnWXP$hBLZA;Oz- z*G6h@QCMWbp^$qp5lZ~0oh*tnElSQxSGMLp5I8S`UssY)*PT1^PbXK7n4x75P3!9S zUtPPI_h?$N-Rsy4WXsk4AYF!%l)29I8UqMyW{(I&Up!(f%o(pNw)bEfn0vS2j#FWj z%HGl^6Zwg6Q-Zr(HHmb@-v#=2w8#rDmc((3tMPfl{ix~Z3(T-6R*+HjgP}a*PAcUUYx&*3eMLNrsgGD+HSL zX#pPVmNPBHzKs|7Dg!C0O~Mo@rb8Ka%ir|9ih3sEIs&%qjAH!?Ixy+il|@ofd1Bjn zO2-<2(Ox~wWZs!u!?ekQ*zf{f-9lNG#WtoDv$<1}dDCRW%IttS!T2%ct#G+x$$dX% zWZXiRgGwCr;e=5{c7EO|!pPFitI zTY{Qcv1){+?#VA8&%EK*7d~%N^}8&oCbFjU>tU-lVK?sSZ zTu(=b2JSYk%NDaCr8?A-k%{mT)V$ho3iW81M{>!MRD}=woWg^}lT3V+y|TfxozXQ5 zD$ec2N7^6MeaG_mYCI(saV8@b)LNG*xkx&9-P$`?9P8hff4C{cR~mchpNAjJ z&?J*ayj3-cwJ9Ta?P4C0lngrcq#S$KuIK7d%%Y~j$I|aB50?0Z<^CL9eF#JW5;x0! z(|=b-Uq&HPH>vMI?|-kX#!$2XjapXFi=c8Midh%=p}K%ZDm7q0&bU?X`9#;P{c0eO zyA*ysd1OKdygEa7bbG2+4K&_@wU3^XhIV<^-^joCFz_z@;4VG=l`4q_eC>_oZa37q zfMelOusmitne>Hhfj)ye653}haCjiK=JqXlU!_!+qlPtQT*a(!S8rT*gGd&;CPEPI ziqjE$wAKxy5ANSL?O%E)q3>n?iE+`-H|>9p?lG_#8}f@ z=_K=Pu&aI$(e7Eb<6;TSY{LEvz?&d1K1`r_{tqYMP_K+V~9nSgwS)tHkb`>v`r zD|0GQ_i#lJX2lM{(7v}a_z2?Vt#jE95VI&{GN(T7fy62CmPaS|I-|48JflLTx^#CAk-uZ;&*<+A zkT7#V`x!fTcyHAS3BCbQV(sUCZ? zeVw=I8_;ajk>JS29~M3r7`as}iUWaa%vVh-qW0mmr%hDoEoeS7DA8e>^Gmb^b8PFF zh!qYoXKF{3p6)rgA=g2|El;G55f0H|NZ9mh44$zlJLB<)?Ub2<@o&8=+T8A6TRyr8 zF0jS`@iq3KT?N$MuUwYRbew?Q)&P~ZwGbUxr+mXjE`nd94kdcZ_H-B$ta$CP*_WkG zaTyi-IhsC*;pa}#VYn#qo_hRpP2>&d8$&e^+LCcq9T$ZI*9Q)-py~{q7PV%7F+X=v zLfblIjj(DE&=^PaXaxCQp_gh|VY)R*2uYXcZ`guB^V-dd#`O;J<41~O`xO~bf8!T~ zb=vMeah4>`gxHBn)v+(by+B`;sWAK!PJ;Hrhd5yf(qd6Kf$ORA}l_QJzaBTGj#7FXf%5j4J8#oPKiHvD`TQJuYv>|+a}w3 z6@3%4RxS`7%7K?EadWU^)d=!+7!T)6N=61TDv$G=5tU_i7L_jzJF|2vbX(wSwWkLN z-pG@o6+X{CLvmQax_!fui%!-~_QiPxJu?12bkFhWyk^rarw&Z1x5>x*xFKmBbU(X* zCmTI`2UtnWmPhyKB#3s7tus=nebfCJD^|C%AN$KM>XKFLc0+=v7@DFy0`uDnyud+= zdS5ta4>fN z7u?{i!6zdnH2UC5CX5fak~|7TYQ4u37iAAPkOI5JJ)`A34Go?;T*6*Kn! zNwQzD{ml>XE$SdByVkb8fZ?>RLU(PhJb|oA_>4$oJg_JGh?wD91xnhSS@>FN@fm6j z?k=601yb0YN%*)gtf1q#mJN;1d1$zg51}-)j%7CI?&EEVtx0f`H7wfeE!u1BkF-l8 zu%0UJ2&a}@=HEj~pF&2-VzAB*HBq9N7G}n+oUqrNu+vtdUi0(|m!!B!nN=P1YxV71 zn-N^dGbH_ABszh|pKc*c@*Qt0Wlh?$9it~C8_$Fa4982WO&b#259U<|UP9b--b0ra zbON9JdQIMBmA`pgG4Irty&3HyeOy4xDU}_Hwg^OfU2*Mca`lN{G;+<-s*!fJT%fQh z0e3+ZHtT|okVIz`vuaYeolE0%Nbyz~7>j|Uz-l?=L7|pcFV-MKK|qV~nBrZV!O*U| zVMcO0Nm!A6FcsR#)fpuDR+UD91SpATIY7W z2qlR(y^5H%Lf6ZP6$UB|Zz85*C=hV1y$Z&k0KkSeneEj!s$ZQ7ys?s`<=W!R#rG zSaZ0RYe>t}k0p6Xmh?f#MIXtnX|F*BDyguk=_F|GzEsnFi5>c?3*&mz;b*ByL+H^5 zW3SQ%wRFH6*r=Kk&WpFm>-SvVYIY=Qh^6s1Ro;J2GYtY)CJ260Ncb^5%(V=%tqZ8+eoh?$ekc+AFQ`Lk9wo5N z2FLJ%c0Z1ZBj%#g*16N&MZ0H%kIt6iGkpw85o~%*D$6R;g$Y;FRzj+JFYnww+*ok0 z>6wODbuy7xrkF4zTo!3D{YKZ1vahs%YyFzdq2_8Z003R4{|~MIhXFL8p=qDThU&SY zy>;EUAaNERVZb+a;zD`$SU0;WpO%?Y>PaLVSu)rSAjR=^qWmK|pi*E~k<|5&iCx2? z^1P)LF|^{yT03fMGp0}#UPM`ti7^le^GuI77`HOe+e7R97#d9VT&NRm5TOH;XV&6z z^%QTmi0v&FhkP8Y+=sjk6Ze|Sl@-^x4T#%qnOw@G|NM04_HgfX@m4pTgyQb?I!B*v zFisnw^eb^Kzv<148K%yxf-MtxsWH+?=OoQXByLi|ysqNsLXXcPfqh`{j_=rv z_x4ysXbz0QfDMUwnuzfA~5$Y5nP+E&76pd7c&a)P_)vbR>RMFnT5Cg3+30vDG zt{Ivp(3ETX)QW1XY6KgXKIA*FRnSZQaU?6K z;nNIxN8_1K;GTW^eGpx6zR$MLXE{EAnaUd#5VnJuig-8TTuK!euf;gwdr zd(D}-` z9S4v+Az{)^u7Uvy8c7X|o!#qj7UOylBF6mY*wL?u6W=GozaJamiE*UQu*>W5F9T(b zK55`+OAFRUS5N{4TFFQ~6QDGRD0`4D{H$@quPB3?NyHn%P}Q7G)L%EtRE$Dln!dc3 zzpGY+OS*=vUh$OS@ST}1;W#RQ*BwQvuar`*OETzn;(+qH}~_ z)!S}#)E_$LvGWRcBvf%E3c6(&)mcT%FASVJ3YtUBZwy3^lU}wS0#9w?xI8CsN@zf6(jYHI_t_&~eQcEBC5A+hs55U3b}K;nYa+yI zv05&0V3CZntPLhu##65zTa*`$ zgK2hIkf>9o=|MO*5bv2UPMP=GJmczV3X94+MUJRl6BpT=W4rd?4HjOELE|yzXK~Z1BU#^K zetV9)x^ZZybD7JpVHThqFz>P4)wQP5RI|fs>0c5f*OL6pBZss`-)`xM#0NKyyItCABGDd z#o*q8I(F~_M*JMagh$cAn6%Ns`GSN_QwHKpA;lApz{G^p#M@A#I0p$x)1T)P#`9x> z#S~LGt&@YliG6dN-s?7Gl(j%@_im;^Xo=v8KxF>>SxyXI6V`g-_?&f92BWJnXbO>P z2tr-o2s!8xGSDbcFF**{%NO{pc7ltn*a)MXL@Ib%6BAY`qonsIMDQbkp8fuR* zgXHug;u9%JETs3JOlEXT3cuRTCrz&$N}`%a)~lpZg*B`& zsIn@1dRIiKZD5(@Euewn;HXs33rEB|&-tHZk0)X=YvF1rOR`B`MCTAcT3Q-**ITU9 zo#}@Gr)XZw>H9;=*p9JENHE1PB9(AbHJCR~1JZ}3Xxh!5#-?HNB&QiAt(|61CSrM# zu?k)AEqHnhHYUX`844;H`$ON6$b1ofMnJ^S39)Z&yo zkI30qjp8yOruAF4kX>N0+E03=t)0{|mwy!iO^%{#<9zjNF&=IyvdY3Ar=?@;jxS&R z0@h;eJlsLsHsV&qckZ~XQW>%GiN^4t_7FkGJFkQlQbiqX^^=1CI|r zPEh}23Q>Rxyn>+KXQ~m98EEdgCS?>1yyt(w!^l>CJDp%2q~`-j6*K|NA@Ns&R}(Y= z%CQ7811)x>+PMZy{qs)#envR&45l^6B$*!bzhTL}*UNZVw=o-E9{S>8%tkkf&9Sn( zOuI;4H%fQk^7AC}6du)OdAsRuDudxy2T95Db1GQFw9|)Y{R+~$E%1WLGsP@&o)-~F z5rnuQ$SFxe)6VWHdO|9gu6|v3lf)!ry_#(S0%<1CeE(io&ZV{ait;8IpKgaz)j6!? z!N=$=g^mrXs?{#5NCuI;%=^JJ@YMAINyzIp;?)9^JG%&}N5|hFX&Dg~wG@1E)VwSW zU{Gfo3o83gQ9|gDt!3LNM9Ohv!_&eibbk1h!7SxxZ5!{tl`hOKSrB!=Gs6VubUE0} z5x$j|!~-18Mm@<&FYKS?(p{yxIZBn-`(Qh9o%?QKMUHd~ch6 zVjVF62w!9n?IJPRwyA#Ca2}pzC6lfogA3imD--@$wf+6aR<_Buyjty7{@h70Oi#TI z1Bh7A@;F0{szA~7{Svg@v8$<7&z8v7E?9oriB$B*60(fL>O5VxsHlMw993I#!8!0_ zNkn9I%|Z55V*@lY{v4^NN@XEKRZyKxuovzymv}lqCQf;X$G8hR+({s7mI%)-jtJj^ z5QlNvGE^!RjnPkLe8+2F|H_MM5ZwutJaaTi_mRkpI+Qc^4)@!TMi4QT1^UbgmJ|9n zLmKnX@Y$b1#J^|6{t-s(h?V@zAchZk;11a1c0%;>mr1vRmvaUm0n{*#O&-iNv4HI0 z78YVcF;!MnUf^22@Vu8`|FGj;1po=ty3#O6_hD60-=KVN^k{88xG_`eK;+;A zPCS3ic0t>@#5bhJVZ#B2-JF&3+jWp2X|S6zs!)#>N?aGkbiX|Aj-xRfFqJ(>r)dIu zy>VKA2erthKO|;}V3x16tDBkhztGWRoS73)@Tdw&xYLj#LlcQ5(`pFw{&us~Jwy=> z-^A_D-CKz|e4z4r$G*cGvycOX?%A6azv-3uiaa(Rpc^Vr-(+klQ3P?k_}#Q~=nZ4E zi@r_{SHklS<~I``yh6F(K3PQluW6sie=^bDMAy#HK;FU5)XMmeMYjqSbNL+(#JA3_ zTq<>D5XERPXPsq?KzDA}v3%Mc87K66uUuqx(fXxWkywbQht*h%pL6HyW_6=z-(`5` z);SKoD|hiEfpFPc`p0Iu<-J#fX&6zW+1->lH>GE2-FK^y+AEO{^WNRB-FkJrk0vmn zPAQ~HcT_aY2laFtsB1CKDx)MlW;M)^)IG{tgBH%D?-`A@(1i6Y+qf{0r$lrARG^^= z>}WpZrx}P!jY_i)OzJqHBC4$NNQNua!w?qX4Ll+H)fQ=-N6_y9wxOVfhTUm1%v>j? z4Rd-o->v$Nb~5JMJFB?)DQ_VBidrZDraRqbcx|voP{aXcr=VhUQ zQUi0ngLZ`N+?6^|0u;28&-!)YG!C~XlxguwCrQ+iE~a_KNM#7I2T}NdlQVQW_2vMw zi7Fhwsf46+g^b+?W~sU7Ihu8oCPSakUP~GMg~c1Y7_`ZI9%||V@#-Y47V`FVu26$w zegFmC8iRgAn!=tp(Nt(S$^dRMgC5b_CbrcR@Is}wqpnZ@_}0UXy{HaZ=ocky=%(rw zcev{UfM-K4Mv{tXf%!l*cT7qK)jC4|6NMN~rfLht=og`~4RiGl`+Uwa5avM@(U5sG z>E0Qq3$PqS6ohX`o%@&&$-MnH33tAV+k=NH804OYY(v~}ZX=i=pUYvyv*Z$7e24cEn`D-z|> z6rkEJZ1St>d+58-rUfPHN(n@41xx-mY{?XCG#qgNJ3jS7-TJ!vbm_pvfs+M0`RfBG z^4D8&!rLPaMpi&qq;&L1w%&?c_TbN7aGQ`DT!nQs+0APvN{Q(UgOdRxxTYG|CZY9C zy^@7Od(VPcg`Ps678r;usI(z%GH~q<`DpsYx6AB`j|s>acR=0ac~dllj7w(0aehN3 zzgdEOp@!H^Njcsb-)?KR=DJn7>ArCfu87&AzC}}}6jHb&MzO@MX>y%=`jEtFL5?VI zve<}hORC84qvuW7idea`phvvC>@x5C$%-0nP|W!cUax0uU6Fx!qM2RDWrjO8y$+`+a2m|_3#blCfGs0RXz(i#I|_rY%M3sz-g&yWn>PM(Nd(W*mG zgr@6sd2scr-%**ojW1LR#)i(|y-BApeOb6W%T$6oO4A6gXsn;FP}=svpO`FDT2dP0 z?tKP2oV#P{e7Y&eeFOD)+=fV2{S;8moL6mtcJi(d!j(}EfP-?&A^R7@n*;;SF-6#L zyqRd{MhKk%Zv^M=uM2TBUjS2;YuBw7lh!KBU^vIW?Pm@Z!^s4SF`V6drxsg9U`}&5 zkU@!%oXszl04wRXFnZTfE=}N=dfRXV>-acfPG+yAcXx0m1&Q2e4_K~OV+B#!i2tVR{W&Tz1IJ9eTPx*|vgskd6IzWyd3_8v_uIc4g3+PN(OMO0=a0498h&RL%Ka&wVk382Hix$$}BitCtDnlF9_>@AcwB(urn`5Ag0UR zp6tDWDp^4cyMILGg9eDbF?Bc1e$~7|SI88EcINuAf$o7RZSu-ZD}(S{q`z|0 zP8=xMg?LX)Z@I4lXz%TK#fsFP%?&er*Jsk~3P16H`5{tfQsny_a(IvVSaf%32NcQF z)R1@%f51Q2gG6QKbxKvh8Q>SF!w$mk*nYX`fsI*YFO#A7&9y?Pkg8YQ=P%!AAMO$tj^JcS{H_q=k&>s%c6z)X^ z#Zl#cwkAim`z$YG7Tudxwy?R+eY932l6XpoK(-%28xzk`EvY`1F-**4v`$1mY0I!e zv>Fnk(+vY%zv=_zx4xD3h#R8)jQ#~-|C`YQ|EIpyxBm1ltQ_qBi29Aot(vX!!FygP zLt`DP*Va-<+L8op_UFsk*s9&OCk`(3YOO6d=s%ormWd-Z0Y9Vr^pCL{M;bYib+M}f zf#qj+Q1$OpBK@emk8oNQczx__ekI2Lwufoh-Y1YwADnirspW1yJpiC_AwaN#?);TP za6MOXYvf{zq3+5+aW}q^@f2JUNv+=`BHd_N#5BPv*Etyn>lrU8a1QB#g`=Im;{-!? z-waP(S{GXE=N^0npnV^Jwqvk2BK{ikwiRV|lBX$TOpR_oQCM?&=M~wjuOFj_3KD^Q z$rW(DCYoN&&sMUY`peVBqy3RX<|BWr`1$?0zS+uFMPwUzsmdxO(zdRC2im%7dFCt* zX^d!C@)7kV&Nut0&3K_ptY8}7yYXK-wEC3$O&7|r@^8$)`hr-wewjfeRc})T6nrgu zK#M!QF=O`*=~>IpjVy_6Cd9c?)ug$Y zYP3?yOt!aQl0c8c^GCUvLCXBO6$qnM1#nlvvqU%}2Z=X-2n)aWhYwv*hl0L~f5|Sa z4Q5XZT_z;h<8u^qG+G+1I6SXmwh+1mmcw$FaWSH(C?5Vvu};xbXq1Ay@*J#_27gky zo!zjxAe0=9Npirz5%yUeA>Az=g>FEbu$`SP^;0o2Dp(Uv6FP;rh4b>5P&ZqG!X$st zuGD{bqAy6zCk8dhueJfOp>Dg?;7<5hCS+~KwH{jn8CU{z^VosN@8Fu-Jr-_icV4*7@GmT*)1#m%(c}YI^)E9)DD9h1oh_&`s z#tN8?c~2wH1@nQ&MyjeZ5Yi-wusbSUV_@Z2>&fFEs>9{ZIQps@vU=054;gK23)4A+ z+AtA*n~2vT`hG&B&U-Ba5FPA`Txp=YnuDqV4a#HAtp&~_Faz#Js+X>B{t)FJ{aM|u zJ!VHDOJR63sLo4Ycep#Ze`*mnb><$e^21Mp@%xXuz>k6U0HXmHjZO~_s$Nj9=?~Ai z7lvQ968Wy6G#p?S_S?ZCpf!O|*z>&dLoYdhm z^77FBDT%A#oe(60>cl$-cOrYajSu1?3%E^pj`Y~v4bMJwX&9Y+txrSR_!^~N8Q%}` zGq}jkUWM{;ws`HIp?=FQKr_e5{Ld0GBk+HdUB64j46OA(>%(m9>GZAb41Xsoc*>3b z_Ose=P+~4ZcJh&fR}{X?Atg{UqZG65SjY=*t2DkmyPwuGfKXbseXZNMTFD#EDe?PU za8PFuCJvPa@NFPLn@6V!Gj)mjVp&XXx(QQOfBT zt6Q7{sLMo((6gZiR64B;#<4H3Y-1m9qqq{M12NUnZ{8MV^Zp{4oRzpHIv!57dXO$iU`ARbpwvN9Rb4&YX;!>fBQrk>M zY70;#F*{{@X32Ss^BPR&B{kH{JSo!;JSj|So8TdxdEUqf&ucu#gG()nY6&BiidKUh z?=1(vBrNk+#j6J0b(zV8@W(kJhCc&DTt0q(tKrqA9$E)~l3-6{n{-;ydPt|E^8D%p zoX&nd*v8U|jeH-(`6w?Q`^T5xBZvu8{v#T>aKQ|8E3!ZESuIU`Dj0b?@&| z+ZPnY{svJBEc|#-%TyRwSpXP9S;jS&(`y=^7CGis(oaD<9wpf~Ud!S9fIF%T>)CRwrC2#5o?&{1qn zmgl#$=$UpHPW^Wsh?mFxI^Cpl%Jb>n$=zbn1zlgJ1DZMVKLiSpie9!Gxu3`M>p^yy zrMt;n3M#}knnnQ1PRg~Zo=-cJe2Xj~R*NqHE)H-Ee2iUuPKJe-bx%7JZ>-)`)?gf- zg7Dx&#!81rv+Jq9KHxeLTGMIO9U)cPrGvdQiCHz){;_1I3s-sd^vRU8e@)au`a9e7 z9qk>gE&t%$M9pWW5^})SdJ*{YssdQdOnn#|r@}+@uSP(7>z|Tgp6*1x=aE5pJW{jV zZ-V9U%LryIbW{`oG%&DaG}dngY@$8Gn>x7u*?XYWZBC0CL?FS#fML}5=IlktW(7+V zn=nc2`m{ts)^eG)a!ipEy(y>LfN>lO^RmkUNKb?w>`zz6%x~hb1{)WTzpM$|E%UsL zSJ8e?hph#GA4#8gef7Eh@72V=pG#fP+REY66wy|2wK25U{QX=5isIJWe`>9kNiQw80?SD%eYpP3Brei|kIo%`o^KS$J}dHwlO9niwx?TrE2+6Y!7FXD%f=nG z0Aw9ARy>p!7nNn&dwY+1E)VDcP$Q0Plqd1M)}OIt9S}ymZdrrFS-s_(O81Q!ji%%_Sj_?9xtSNB{YIwCM zB&k+j!nKl!0=-0Hws0(;mC>rC=0^_%7iid1rK}@)`}Uy*V70&C1znp!m%cg3|8khs z0z>yI@{H~g7i9%){cwi{^Tiy2|4lq*VzlmJplJ=v`bS0jKau~Q_x)Rk`~^Or(&`iWKZ}n4iT?NO!r#f^e*q-oALxIjivJV! z?|FDcf8l+$cF_LcZU0*`;y(%geTn~f`rcn~`+4|ZeE2Vde;6n2Uo&Odb{3nIK+seOH%wKT$ znF{gAmH%*e{)zo} z;`|%>f2qxXV*g#@{+6qMK?c{~u>aB?|0MAD_x3*tICB4wVp>KV1oZb+;66X=pD&UP I@9(4k17#m)*8l(j diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl deleted file mode 100644 index a8b9a2b..0000000 --- a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.tcl +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (c) 2015 University of Cambridge -# All rights reserved. -# -# -# File: -# input_arbiter_regs_defines.tcl -# -# Description: -# This file is automatically generated with tcl defines for the software -# -# This software was developed by -# Stanford University and the University of Cambridge Computer Laboratory -# under National Science Foundation under Grant No. CNS-0855268, -# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and -# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), -# as part of the DARPA MRC research programme. -# -# @NETFPGA_LICENSE_HEADER_START@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# @NETFPGA_LICENSE_HEADER_END@ -# - -set INPUT_ARBITER_REGS_ID_0_OFFSET 0x0 -set INPUT_ARBITER_REGS_ID_0_DEFAULT 0x0000DA01 -set INPUT_ARBITER_REGS_ID_0_WIDTH 32 -set INPUT_ARBITER_REGS_VERSION_0_OFFSET 0x4 -set INPUT_ARBITER_REGS_VERSION_0_DEFAULT 0x1 -set INPUT_ARBITER_REGS_VERSION_0_WIDTH 32 -set INPUT_ARBITER_REGS_RESET_0_OFFSET 0x8 -set INPUT_ARBITER_REGS_RESET_0_DEFAULT 0x0 -set INPUT_ARBITER_REGS_RESET_0_WIDTH 16 -set INPUT_ARBITER_REGS_FLIP_0_OFFSET 0xC -set INPUT_ARBITER_REGS_FLIP_0_DEFAULT 0x0 -set INPUT_ARBITER_REGS_FLIP_0_WIDTH 32 -set INPUT_ARBITER_REGS_DEBUG_0_OFFSET 0x10 -set INPUT_ARBITER_REGS_DEBUG_0_DEFAULT 0x0 -set INPUT_ARBITER_REGS_DEBUG_0_WIDTH 32 -set INPUT_ARBITER_REGS_PKTIN_0_OFFSET 0x14 -set INPUT_ARBITER_REGS_PKTIN_0_DEFAULT 0x0 -set INPUT_ARBITER_REGS_PKTIN_0_WIDTH 32 -set INPUT_ARBITER_REGS_PKTOUT_0_OFFSET 0x18 -set INPUT_ARBITER_REGS_PKTOUT_0_DEFAULT 0x0 -set INPUT_ARBITER_REGS_PKTOUT_0_WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt deleted file mode 100644 index 224df27..0000000 --- a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_defines.txt +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) 2015 University of Cambridge -// All rights reserved. -// -// -// File: -// input_arbiter_regs_defines.txt -// -// Description: -// This file is automatically generated with header defines for the software -// -// This software was developed by -// Stanford University and the University of Cambridge Computer Laboratory -// under National Science Foundation under Grant No. CNS-0855268, -// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and -// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), -// as part of the DARPA MRC research programme. -// -// @NETFPGA_LICENSE_HEADER_START@ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// @NETFPGA_LICENSE_HEADER_END@ -// - -#define NFPLUS INPUT_ARBITER ID OFFSET 0x0 -#define NFPLUS INPUT_ARBITER ID DEFAULT 0x0000DA01 -#define NFPLUS INPUT_ARBITER ID WIDTH 32 -#define NFPLUS INPUT_ARBITER VERSION OFFSET 0x4 -#define NFPLUS INPUT_ARBITER VERSION DEFAULT 0x1 -#define NFPLUS INPUT_ARBITER VERSION WIDTH 32 -#define NFPLUS INPUT_ARBITER RESET OFFSET 0x8 -#define NFPLUS INPUT_ARBITER RESET DEFAULT 0x0 -#define NFPLUS INPUT_ARBITER RESET WIDTH 16 -#define NFPLUS INPUT_ARBITER FLIP OFFSET 0xC -#define NFPLUS INPUT_ARBITER FLIP DEFAULT 0x0 -#define NFPLUS INPUT_ARBITER FLIP WIDTH 32 -#define NFPLUS INPUT_ARBITER DEBUG OFFSET 0x10 -#define NFPLUS INPUT_ARBITER DEBUG DEFAULT 0x0 -#define NFPLUS INPUT_ARBITER DEBUG WIDTH 32 -#define NFPLUS INPUT_ARBITER PKTIN OFFSET 0x14 -#define NFPLUS INPUT_ARBITER PKTIN DEFAULT 0x0 -#define NFPLUS INPUT_ARBITER PKTIN WIDTH 32 -#define NFPLUS INPUT_ARBITER PKTOUT OFFSET 0x18 -#define NFPLUS INPUT_ARBITER PKTOUT DEFAULT 0x0 -#define NFPLUS INPUT_ARBITER PKTOUT WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h index 751ee8d..74ef9c4 100644 --- a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h @@ -4,31 +4,32 @@ // // // File: -// input_arbiter_regs_defines.h +// nf_data_sink_regs_defines.h // // Description: // This file is automatically generated with header defines for the software // -// This software was developed by -// Stanford University and the University of Cambridge Computer Laboratory +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory // under National Science Foundation under Grant No. CNS-0855268, // the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and -// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), // as part of the DARPA MRC research programme. // // @NETFPGA_LICENSE_HEADER_START@ // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +// license agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. NetFPGA licenses this +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +// "License"); you may not use this file except in compliance with the +// License. You may obtain a copy of the License at: // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.netfpga-cic.org // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Unless required by applicable law or agreed to in writing, Work distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. // // @NETFPGA_LICENSE_HEADER_END@ // @@ -36,24 +37,33 @@ ##########This text should be copied to the head file ############# #Registers offset definitions -#define NFPLUS_INPUT_ARBITER_ID_0_OFFSET 0x0 -#define NFPLUS_INPUT_ARBITER_ID_0_DEFAULT 0x0000DA01 -#define NFPLUS_INPUT_ARBITER_ID_0_WIDTH 32 -#define NFPLUS_INPUT_ARBITER_VERSION_0_OFFSET 0x4 -#define NFPLUS_INPUT_ARBITER_VERSION_0_DEFAULT 0x1 -#define NFPLUS_INPUT_ARBITER_VERSION_0_WIDTH 32 -#define NFPLUS_INPUT_ARBITER_RESET_0_OFFSET 0x8 -#define NFPLUS_INPUT_ARBITER_RESET_0_DEFAULT 0x0 -#define NFPLUS_INPUT_ARBITER_RESET_0_WIDTH 16 -#define NFPLUS_INPUT_ARBITER_FLIP_0_OFFSET 0xC -#define NFPLUS_INPUT_ARBITER_FLIP_0_DEFAULT 0x0 -#define NFPLUS_INPUT_ARBITER_FLIP_0_WIDTH 32 -#define NFPLUS_INPUT_ARBITER_DEBUG_0_OFFSET 0x10 -#define NFPLUS_INPUT_ARBITER_DEBUG_0_DEFAULT 0x0 -#define NFPLUS_INPUT_ARBITER_DEBUG_0_WIDTH 32 -#define NFPLUS_INPUT_ARBITER_PKTIN_0_OFFSET 0x14 -#define NFPLUS_INPUT_ARBITER_PKTIN_0_DEFAULT 0x0 -#define NFPLUS_INPUT_ARBITER_PKTIN_0_WIDTH 32 -#define NFPLUS_INPUT_ARBITER_PKTOUT_0_OFFSET 0x18 -#define NFPLUS_INPUT_ARBITER_PKTOUT_0_DEFAULT 0x0 -#define NFPLUS_INPUT_ARBITER_PKTOUT_0_WIDTH 32 +#define SUME_NF_DATA_SINK_ID_0_OFFSET 0x0 +#define SUME_NF_DATA_SINK_ID_0_DEFAULT 0x0000DAD1 +#define SUME_NF_DATA_SINK_ID_0_WIDTH 32 +#define SUME_NF_DATA_SINK_VERSION_0_OFFSET 0x4 +#define SUME_NF_DATA_SINK_VERSION_0_DEFAULT 0x1 +#define SUME_NF_DATA_SINK_VERSION_0_WIDTH 32 +#define SUME_NF_DATA_SINK_RESET_0_OFFSET 0x8 +#define SUME_NF_DATA_SINK_RESET_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_RESET_0_WIDTH 16 +#define SUME_NF_DATA_SINK_FLIP_0_OFFSET 0xC +#define SUME_NF_DATA_SINK_FLIP_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_FLIP_0_WIDTH 32 +#define SUME_NF_DATA_SINK_DEBUG_0_OFFSET 0x10 +#define SUME_NF_DATA_SINK_DEBUG_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_DEBUG_0_WIDTH 32 +#define SUME_NF_DATA_SINK_ENABLE_0_OFFSET 0x14 +#define SUME_NF_DATA_SINK_ENABLE_0_DEFAULT 0x2'b00 +#define SUME_NF_DATA_SINK_ENABLE_0_WIDTH 2 +#define SUME_NF_DATA_SINK_PKTIN_0_OFFSET 0x18 +#define SUME_NF_DATA_SINK_PKTIN_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_PKTIN_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET 0x1c +#define SUME_NF_DATA_SINK_BYTESINLO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINLO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET 0x20 +#define SUME_NF_DATA_SINK_BYTESINHI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINHI_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TIME_0_OFFSET 0x24 +#define SUME_NF_DATA_SINK_TIME_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TIME_0_WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py new file mode 100644 index 0000000..efe1aa3 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py @@ -0,0 +1,1856 @@ +#! /usr/bin/env python +###################################################################################### +# NetFPGA-10G http://www.netfpga.org +# +# File: +# regs_gen.py +# +# Author: +# Noa Zilberman +# +# Description: +# This file generates the required registers-related verilog modules +# +# Copyright notice: +# Copyright (C) 2013 University of Cambridge +# +# Licence: +# This file is part of the NetFPGA 10G development base package. +# +# This file is free code: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License version 2.1 as +# published by the Free Software Foundation. +# +# This package is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the NetFPGA source package. If not, see +# http://www.gnu.org/licenses/. +# +####################################################################################### + +################################################################## +#Define the list of registers (busses) and their characteristics +################################################################## + +module_name='nf_data_sink' + +block_name=module_name.upper() + +def create_mems_list(): + return [] + +def create_regs_list(): + regsDict=[ +{'reg':"ID",'type':"RO",'endian':"little", 'name':"id",'bits':"31:0",'width':"32",'addr':"32'h0",'default':"32'h0000DAD1"}, + +{'reg':"Version",'type':"RO",'endian':"little", 'name':"version",'bits':"31:0",'width':"32",'addr':"32'h4",'default':"32'h1"}, + +{'reg':"Reset",'type':"WOE",'endian':"little", 'name':"reset",'bits':"15:0",'width':"16",'addr':"32'h8",'default':"16'h0"}, + +{'reg':"Flip",'type':"RWA",'endian':"little", 'name':"flip",'bits':"31:0",'width':"32",'addr':"32'hC",'default':"32'h0"}, + +{'reg':"Debug",'type':"RWA",'endian':"little", 'name':"debug",'bits':"31:0",'width':"32",'addr':"32'h10",'default':"32'h0"}, + +{'reg':"Enable",'type':"RWA",'endian':"little", 'name':"enable",'bits':"1:0",'width':"2",'addr':"32'h14",'default':"2'b00"}, + +{'reg':"PktIn",'type':"RO",'endian':"little", 'name':"pktin",'bits':"31:0",'width':"32",'addr':"32'h18",'default':"32'h0"}, + +{'reg':"BytesInLo",'type':"RO",'endian':"little", 'name':"bytesinlo",'bits':"31:0",'width':"32",'addr':"32'h1c",'default':"32'h0"}, + +{'reg':"BytesInHi",'type':"RO",'endian':"little", 'name':"bytesinhi",'bits':"31:0",'width':"32",'addr':"32'h20",'default':"32'h0"}, + +{'reg':"Time",'type':"RO",'endian':"little", 'name':"time",'bits':"31:0",'width':"32",'addr':"32'h24",'default':"32'h0"}, + +] + return(regsDict) +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt new file mode 100644 index 0000000..d90222b --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt @@ -0,0 +1,1787 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() diff --git a/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v index f1ec0a7..c6fdbba 100644 --- a/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v +++ b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v @@ -117,6 +117,7 @@ module nf_data_sink ); + function integer log2; input integer number; begin @@ -127,7 +128,22 @@ module nf_data_sink end endfunction // log2 - // ------------ Internal Params -------- + localparam TKEEP_WIDTH = C_S_AXIS_DATA_WIDTH / 8; + localparam VALID_COUNT_WIDTH = log2(TKEEP_WIDTH) + 1; + + function [VALID_COUNT_WIDTH-1:0] count_bytes_valid; + input [TKEEP_WIDTH-1:0] valid_vector; + integer i; + begin + count_bytes_valid = 0; + for (i = 0 ; i < TKEEP_WIDTH; i = i + 1) + begin + count_bytes_valid = count_bytes_valid + valid_vector[i]; + end + end + endfunction // count_bytes_valid + +// ------------ Internal Params -------- // localparam NUM_QUEUES_WIDTH = log2(NUM_QUEUES); @@ -161,53 +177,64 @@ module nf_data_sink // reg [NUM_STATES-1:0] state; // reg [NUM_STATES-1:0] state_next; - reg [`REG_ID_BITS] id_reg; - reg [`REG_VERSION_BITS] version_reg; - wire [`REG_RESET_BITS] reset_reg; - reg [`REG_FLIP_BITS] p2cpu_flip_reg; - wire [`REG_FLIP_BITS] cpu2ip_flip_reg; - reg [`REG_PKTIN_BITS] pktin_reg; - wire pktin_reg_clear; - reg [`REG_PKTSUM_BITS] pktsum_reg; - wire pktsum_reg_clear; - reg [`REG_DEBUG_BITS] ip2cpu_debug_reg; - wire [`REG_DEBUG_BITS] cpu2ip_debug_reg; + reg [`REG_ID_BITS] id_reg; + reg [`REG_VERSION_BITS] version_reg; + wire [`REG_RESET_BITS] reset_reg; + reg [`REG_FLIP_BITS] ip2cpu_flip_reg; + wire [`REG_FLIP_BITS] cpu2ip_flip_reg; + reg [`REG_DEBUG_BITS] ip2cpu_debug_reg; + wire [`REG_DEBUG_BITS] cpu2ip_debug_reg; + reg [`REG_ENABLE_BITS] ip2cpu_enable_reg; + wire [`REG_ENABLE_BITS] cpu2ip_enable_reg; + reg [`REG_PKTIN_BITS] pktin_reg; + reg [`REG_BYTESINLO_BITS] bytesinlo_reg; + reg [`REG_BYTESINHI_BITS] bytesinhi_reg; + reg [`REG_TIME_BITS] time_reg; wire clear_counters; wire reset_registers; wire unused; + reg enabled; + reg sample_reg; + reg sample_reg_d1; + wire sample; + assign sample = sample_reg & ~sample_reg_d1; // rising edge sample. + reg [63:0] bytesin_count; + reg [31:0] pktin_count; + reg[31:0] time_count; // counts clocks since first active SOP + reg[31:0] time_at_last_eop; // Time spent active. Updated ONLY at EOP. + + wire enabled_sop; + wire enabled_mop; + wire enabled_eop; + + wire [VALID_COUNT_WIDTH-1:0] number_of_last_bytes; // num bytes valid in tlast transaction. + assign number_of_last_bytes = in_tlast ? count_bytes_valid(in_tkeep) : 0; + + reg active_reg; // 0 after enable. Goes 1 at first SOP after enabled. + reg in_packet; // 1 after SOP and before EOP. + + // current_pkt_byte_count keeps track of number of bytes received for current packet. + // EOP is assumed to be true when tlast is asserted. + reg [15:0] current_pkt_byte_count; // ------------ Modules ------------- // ------------- Logic ------------ - always @(posedge axi_aclk) begin + always @(posedge axis_aclk) begin in_tdata <= s_axis_2_tdata; in_tkeep <= s_axis_2_tkeep; in_tuser <= s_axis_2_tuser; in_tvalid <= s_axis_2_tvalid; in_tlast <= s_axis_2_tlast; - - s_axis_2_tready <= 1'b1; // always accept data - - end + assign s_axis_2_tready = 1'b1; // always accept data - - //Find the next non-empty queue - assign extended_empty = {empty,empty}; - assign extended_next_queue = !extended_empty[cur_queue+1] ? cur_queue+1 : - !extended_empty[cur_queue+2] ? cur_queue+2 : - !extended_empty[cur_queue+3] ? cur_queue+3 : - cur_queue+1; - assign {unused,next_queue} = (extended_next_queue > NUM_QUEUES-1) ? extended_next_queue - NUM_QUEUES : extended_next_queue; - - assign m_axis_tuser = fifo_out_tuser[cur_queue]; - assign m_axis_tdata = fifo_out_tdata[cur_queue]; - assign m_axis_tlast = fifo_out_tlast[cur_queue]; - assign m_axis_tkeep = fifo_out_tkeep[cur_queue]; - assign m_axis_tvalid = ~empty[cur_queue]; + assign enabled_sop = enabled & s_axis_2_tvalid & ~in_packet & s_axis_2_tready; + assign enabled_eop = enabled & s_axis_2_tvalid & s_axis_2_tlast & s_axis_2_tready; + assign enabled_mop = enabled & s_axis_2_tvalid & ~s_axis_2_tlast & s_axis_2_tready; //Registers section @@ -216,7 +243,7 @@ module nf_data_sink .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH), .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH), .C_BASE_ADDRESS (C_BASEADDR) - ) arbiter_cpu_regs_inst + ) nf_data_sink_cpu_regs_inst ( // General ports .clk (axis_aclk), @@ -248,13 +275,16 @@ module nf_data_sink .reset_reg (reset_reg), .ip2cpu_flip_reg (ip2cpu_flip_reg), .cpu2ip_flip_reg (cpu2ip_flip_reg), - .pktin_reg (pktin_reg), - .pktin_reg_clear (pktin_reg_clear), - .pktsum_reg (pktsum_reg), - .pktsum_reg_clear (pktsum_reg_clear), .ip2cpu_debug_reg (ip2cpu_debug_reg), .cpu2ip_debug_reg (cpu2ip_debug_reg), - + + .ip2cpu_enable_reg (ip2cpu_enable_reg), + .cpu2ip_enable_reg (cpu2ip_enable_reg), + .pktin_reg (pktin_reg), + .bytesinlo_reg (bytesinlo_reg), + .bytesinhi_reg (bytesinhi_reg), + .time_reg (time_reg), + // Global Registers - user can select if to use .cpu_resetn_soft(),//software reset, after cpu module .resetn_soft (),//software reset to cpu module (from central reset management) @@ -266,25 +296,62 @@ module nf_data_sink always @(posedge axis_aclk) if (~resetn_sync | reset_registers) begin - id_reg <= #1 `REG_ID_DEFAULT; - version_reg <= #1 `REG_VERSION_DEFAULT; - ip2cpu_flip_reg <= #1 `REG_FLIP_DEFAULT; - pktin_reg <= #1 `REG_PKTIN_DEFAULT; - pktsum_reg <= #1 `REG_PKTOUT_DEFAULT; - ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT; + id_reg <= #1 `REG_ID_DEFAULT; + version_reg <= #1 `REG_VERSION_DEFAULT; + ip2cpu_flip_reg <= #1 `REG_FLIP_DEFAULT; + ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT; + pktin_reg <= #1 `REG_PKTIN_DEFAULT; + ip2cpu_enable_reg <= #1 `REG_ENABLE_DEFAULT; + pktin_reg <= #1 `REG_PKTIN_DEFAULT; + bytesinlo_reg <= #1 `REG_BYTESINLO_DEFAULT; + bytesinhi_reg <= #1 `REG_BYTESINHI_DEFAULT; + time_reg <= #1 `REG_TIME_DEFAULT; + + enabled <= 1'b0; + sample_reg <= 1'd0; + sample_reg_d1 <= 1'd0; + bytesin_count <= 64'd0; + pktin_count <= 0; + time_count <= 0; + in_packet <= 1'b0; + active_reg <= 1'b0; + time_at_last_eop <= 0; + + current_pkt_byte_count <= 0; end else begin - id_reg <= #1 `REG_ID_DEFAULT; - version_reg <= #1 `REG_VERSION_DEFAULT; - ip2cpu_flip_reg <= #1 ~cpu2ip_flip_reg; - pktin_reg <= #1 clear_counters | pktin_reg_clear ? 'h0 : pktin_reg + (in_tvalid & in_tlast & s_axis_2_tready); + id_reg <= #1 `REG_ID_DEFAULT; + version_reg <= #1 `REG_VERSION_DEFAULT; + ip2cpu_flip_reg <= #1 ~cpu2ip_flip_reg; + ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT+cpu2ip_debug_reg; + ip2cpu_enable_reg <= {active_reg, cpu2ip_enable_reg[0]}; - // Pktsum is just here to make sure data logic is not deleted in synthesis - pktsum_reg <= #1 clear_counters | pktsum_reg_clear ? 'h0 : pktsum_reg + (m_axis_tvalid && m_axis_tlast && m_axis_tready ) ? in_tdata[`REG_PKTSUM_BITS] : '0 ; + enabled <= cpu2ip_enable_reg[0]; - ip2cpu_debug_reg <= #1 `REG_DEBUG_DEFAULT+cpu2ip_debug_reg; - end + // do not go active in the middle of a packet - wait until end of current packet. + in_packet <= enabled_sop | (in_packet & ~enabled_eop); + active_reg <= enabled & (active_reg | (~active_reg & enabled_sop)); + + // counters count when enabled. + + current_pkt_byte_count <= enabled_eop ? 0 : + enabled_mop ? (current_pkt_byte_count + TKEEP_WIDTH) : + enabled ? current_pkt_byte_count : 0; + pktin_count <= pktin_count + {31'd0, active_reg & enabled_eop}; + bytesin_count <= enabled_eop & active_reg ? current_pkt_byte_count + number_of_last_bytes : + active_reg ? bytesin_count : 64'd0; + time_count <= active_reg | enabled_sop ? time_count + 1 : enabled ? time_count : 0; + + time_at_last_eop <= (enabled_sop & ~active_reg) | enabled_eop ? time_count + 1 : + enabled ? time_at_last_eop : 0; + + pktin_reg <= sample & active_reg ? pktin_count : active_reg ? pktin_reg : 0; + bytesinlo_reg <= sample & active_reg ? bytesin_count[31:0] : active_reg ? bytesinlo_reg : 0; + bytesinhi_reg <= sample & active_reg ? bytesin_count[63:32] : active_reg ? bytesinhi_reg : 0; + time_reg <= sample & active_reg ? time_at_last_eop : active_reg ? time_reg : 0; + + end endmodule diff --git a/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl b/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl index 4f3d92f..4873001 100644 --- a/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl +++ b/hw/lib/std/nf_data_sink_v1_0_0/nf_data_sink.tcl @@ -44,7 +44,7 @@ create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} -ip set_property source_mgmt_mode All [current_project] set_property top ${top} [current_fileset] set_property ip_repo_paths $::env(NFPLUS_FOLDER)/hw/lib/ [current_fileset] -puts "Creating Input Arbiter IP" +puts "Creating Data Sink IP" ##################################### # Project Structure & IP Build ##################################### @@ -119,9 +119,6 @@ set_property display_name {C_BASEADDR} [ipx::get_user_parameters C_BASEADDR] set_property value {0x00000000} [ipx::get_user_parameters C_BASEADDR] set_property value_format {bitstring} [ipx::get_user_parameters C_BASEADDR] -ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces m_axis -of_objects [ipx::current_core]] -ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_0 -of_objects [ipx::current_core]] -ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_1 -of_objects [ipx::current_core]] ipx::add_bus_parameter FREQ_HZ [ipx::get_bus_interfaces s_axis_2 -of_objects [ipx::current_core]] ipx::infer_user_parameters [ipx::current_core] diff --git a/hw/projects/reference_dma/hw/hdl/nf_datapath.v b/hw/projects/reference_dma/hw/hdl/nf_datapath.v index dc0361e..56ade74 100644 --- a/hw/projects/reference_dma/hw/hdl/nf_datapath.v +++ b/hw/projects/reference_dma/hw/hdl/nf_datapath.v @@ -167,41 +167,41 @@ module nf_datapath #( ); // tie off unused output connections to CMAC - assign s_axis_0_tready = '0; - assign s_axis_1_tready = '0; + assign s_axis_0_tready = 1'b0; + assign s_axis_1_tready = 1'b0; - assign m_axis_0_tdata = '0; - assign m_axis_0_tkeep = '0; - assign m_axis_0_tuser = '0; - assign m_axis_0_tlast = '0; - assign m_axis_1_tdata = '0; - assign m_axis_1_tkeep = '0; - assign m_axis_1_tuser = '0; - assign m_axis_1_tlast = '0; + assign m_axis_0_tdata = 0; + assign m_axis_0_tkeep = 0; + assign m_axis_0_tuser = 0; + assign m_axis_0_tlast = 1'b0; + assign m_axis_1_tdata = 0; + assign m_axis_1_tkeep = 0; + assign m_axis_1_tuser = 0; + assign m_axis_1_tlast = 1'b0; // not using S1_AXI or S2_AXI register interfaces at the moment. - assign S1_AXI_ARREADY = '0; - assign S1_AXI_RDATA = '0; - assign S1_AXI_RRESP = '0; - assign S1_AXI_RVALID = '0; - assign S1_AXI_WREADY = '0; - assign S1_AXI_BRESP = '0; - assign S1_AXI_BVALID = '0; - assign S1_AXI_AWREADY = '0; - assign S2_AXI_ARREADY = '0; - assign S2_AXI_RDATA = '0; - assign S2_AXI_RRESP = '0; - assign S2_AXI_RVALID = '0; - assign S2_AXI_WREADY = '0; - assign S2_AXI_BRESP = '0; - assign S2_AXI_BVALID = '0; - assign S2_AXI_AWREADY = '0; + assign S1_AXI_ARREADY = 1'b0; + assign S1_AXI_RDATA = 0; + assign S1_AXI_RRESP = 1'b0; + assign S1_AXI_RVALID = 1'b0; + assign S1_AXI_WREADY = 1'b0; + assign S1_AXI_BRESP = 1'b0; + assign S1_AXI_BVALID = 1'b0; + assign S1_AXI_AWREADY = 1'b0; + assign S2_AXI_ARREADY = 1'b0; + assign S2_AXI_RDATA = 0; + assign S2_AXI_RRESP = 1'b0; + assign S2_AXI_RVALID = 1'b0; + assign S2_AXI_WREADY = 1'b0; + assign S2_AXI_BRESP = 1'b0; + assign S2_AXI_BVALID = 1'b0; + assign S2_AXI_AWREADY = 1'b0; - // temporarirly tie of m_axis until we code up the outbound DMA side. - assign m_axis_2_tdata = '0; - assign m_axis_2_tkeep = '0; - assign m_axis_2_tuser = '0; - assign m_axis_2_tlast = '0; + // temporarirly tie off m_axis until we code up the outbound DMA side. + assign m_axis_2_tdata = 0; + assign m_axis_2_tkeep = 0; + assign m_axis_2_tuser = 0; + assign m_axis_2_tlast = 1'b0; // Data sink (data from DMA) nf_data_sink nf_data_sink_v1_0 ( diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl index ad9db3c..d0213dd 100644 --- a/hw/projects/reference_dma/hw/tcl/reference_dma.tcl +++ b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl @@ -121,6 +121,13 @@ set_property constrset constraints [get_runs impl_1] # Project ##################################### update_ip_catalog +# nf_data_sink +create_ip -name nf_data_sink -vendor NetFPGA -library NetFPGA -module_name nf_data_sink_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property generate_synth_checkpoint false [get_files nf_data_sink_ip.xci] +reset_target all [get_ips nf_data_sink_ip] +generate_target all [get_ips nf_data_sink_ip] # OPL create_ip -name switch_output_port_lookup -vendor NetFPGA -library NetFPGA -module_name switch_output_port_lookup_ip set_property CONFIG.C_CAM_LUT_DEPTH_BITS ${opl_cam_depth_bits} [get_ips switch_output_port_lookup_ip] diff --git a/tools/infrastructure/regs_template.txt b/tools/infrastructure/regs_template.txt new file mode 100644 index 0000000..d90222b --- /dev/null +++ b/tools/infrastructure/regs_template.txt @@ -0,0 +1,1787 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() From f2a37395ecada64a986692a7cfcf43d4ca6ff6e0 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Sun, 4 Feb 2024 14:59:27 -0800 Subject: [PATCH 08/28] Updated reference_dma to get simulation working. --- Makefile | 1 + .../data/module_generation_nf_data_sink.ods | Bin 40846 -> 41820 bytes .../nf_data_sink_v1_0_0/hdl/nf_data_sink.v | 25 ++-- .../std/nf_data_sink_v1_0_0/nf_data_sink.tcl | 2 + .../hw/tcl/reference_dma_sim.tcl | 9 ++ .../reference_dma/test/sim_simple_send/run.py | 111 ++++++++++++++++++ 6 files changed, 139 insertions(+), 9 deletions(-) create mode 100755 hw/projects/reference_dma/test/sim_simple_send/run.py diff --git a/Makefile b/Makefile index eb6ec03..c0027f5 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ cores: make -C $(LIB_HW_DIR)/contrib/nf_endianess_manager_v1_0_0/ make -C $(LIB_HW_DIR)/std/axis_fifo_v1_0_0/ make -C $(LIB_HW_DIR)/std/nf_axis_converter_v1_0_0/ + make -C $(LIB_HW_DIR)/std/nf_data_sink_v1_0_0/ make -C $(LIB_HW_DIR)/std/nf_mac_attachment_v1_0_0/ make -C $(LIB_HW_DIR)/std/input_arbiter_v1_0_0/ make -C $(LIB_HW_DIR)/std/output_queues_v1_0_0/ diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods index ad8c7c4db955eb50eb3c8bdcae29448ae13c5949..9b44e76e8b3cb645b34915f9840e3641c8d8e5ba 100644 GIT binary patch delta 35953 zcmZU(by!_7vp0%6MGM6pic4{a;!xb7Y@}FmcNXq$8+Uj2LUDI@FYaF0aQmKfzVA8r z-dTUl%*rp5iBe|WqReqw(b zUPBtRAmV@YhGitS|68Dyj@Q780{35fg9xg?e+xcn{QoVqqm%xZkf@A7ktmOe`=9!W znV1xbzF8ko|5ua$-hDy*pXL+0{$Z~&Q4+~8k^T$+AH56%`+wvw|HYLtxc-O#2Md>g zf%#u54hA>4?4@FV0SRu(ft zR2E{r&`*2~e6^<8ALSR6h_?E=FnEKB$K5qKX+P2>-TpXsjq%}UZgdk*>=JkvWKCd2 ze%AF%RoU9HA)a z*hR@+l&LO}oYy}^sCYReac3W+YZuH&w1K2YnujHZq7|4Gi&>+~zD&3zmmOQKXBQHf zL~WQGO4v&&Wp*Ap^YF-QZr!jFXXKW`e>mB@IgsiW6CdZ`qlr=R9?dpki^T2&Ldz^L z&bG~I0)|8SS5I=~1B*gActL_(+g}`=tl)mubXXmmp-U%zn~k+@%lByEcv29S zH>B^bl(!l{Mut<6TuEKwe)WEQfQSgz(ZSPNFbp!(Xs=01{k zeMlQ&*qvdBxFl_~0lA7Sj%{%0=p(r{xpj*o0KLZ>Lz+av=1Mh?!MEJ@wq=xxMGS*T zJH5BGBG4zF%rF3VDfg8MopazO+LIx6^%i3~s9F-IQ6KGI`2yYWSeM8Vx1jEGPpT8M zVsZJ}qsO1W*zsj9Yv0*5?WghPOV7wOVua`KAFtbT1B$Q?k`zC%hEq~$)r778HHqw2 zCYDD;Vz+dm3Or@R-M^Iu# zxEFhtHrus>U&6$~{#0!D>ez@<&HD{XD8S7aa+pzb@f%?Y8+~#0n$x1O4&R0ON|eF3=A>e)p_Ox2{EiiPTB5@}uh2eg zl*>{z!^Fn^gGd=}_%5C-7GfAR1q*+YCqljnS?Xz+Eq|>2DAO3Pou8v`c$hyKqC~6Z z;x}v+4ms4z~LLs=R)dLO{@*9$$pJxyBE`ByS!ZnJb*Bw*3>HG+79STxt6%PY(npMbQ>1Dql;_85Kr8v8uZT=FJcxfycvhbqNdq^wkQ9} z5%I@eLF6C4@$=i?QIL1ZF~coS34>F(L!w(8;Z(V_5$RghLicc=h_K;Qz^ojzUqTOP zim6`kdNv}BrGlix$}$VZ^Zu~$UKsVbdhoWIQhq(%xHOdk5|-yBd2N}=Uf_xbSCoyHIEGRNvlbK50>9FwsLB+j zPSVyyjuIGaa(&(YD&Xgv^vjn9Run_;hR6K$=gk)}Kdc``d7@z|&Y&2r634J#{>W+~ z@+&JJOjr5|Xx|YejzV%{;N^zn*n3a2UcRy1^Fy$0q>7glJn-- z&Zw!b?h+R!=yq65o4tB*e&|Q)fxA`y7QO2}QbyirZcC}gc_^n7BJZX??sH?`ajt)? z^ZAfg44R&5$zc7)+>if>ggP3b5>IYJCN)zisss&91T$NeRX-1fELj