[Vivado] Export VTA configuration variables to TCL for hardware builds (#11)

* generate tcl file for hardware tools from vta_config.py

* add comment to function

* remove this
diff --git a/config/vta_config.py b/config/vta_config.py
index d7ea0df..6396ae5 100644
--- a/config/vta_config.py
+++ b/config/vta_config.py
@@ -32,6 +32,67 @@
     PkgConfig = libpkg["PkgConfig"]
     return PkgConfig(cfg)
 
+def gen_target_name(pkg):
+    """Emit target macro from config"""
+    if pkg.TARGET == "pynq":
+        return "VTA_TARGET_PYNQ"
+    elif pkg.TARGET == "de10nano":
+        return "VTA_TARGET_DE10_NANO"
+    elif pkg.TARGET == "ultra96":
+        return "VTA_TARGET_ULTRA96"
+    else:
+        return None
+
+def gen_target_cflags(pkg):
+    """Emit target cflags from config"""
+    cflags_str = " ".join(pkg.cflags)
+    target = gen_target_name(pkg)
+    if target:
+        cflags_str += " -D{}".format(target)
+    return cflags_str
+
+def calculate_num_wgt_uram(pkg):
+    """Calculate number of weight uram from config"""
+    if hasattr(pkg, 'num_wgt_mem_uram'):
+        return pkg.num_wgt_mem_uram
+    else:
+        return 0
+
+def gen_tcl_vivado(pkg, file):
+    """Export variables to tcl file"""
+    const_func = """proc const {name value} {
+    uplevel 1 [list set $name $value]
+    uplevel 1 [list trace var $name w {error constant ;#} ]
+}"""
+    with open(file, "w") as fo:
+        fo.write(const_func)
+        fo.write("\nconst CFLAGS \"{}\"".format(gen_target_cflags(pkg)))
+        fo.write("\nconst TARGET {}".format(pkg.TARGET))
+        fo.write("\nconst FPGA_DEVICE {}".format(pkg.fpga_device))
+        fo.write("\nconst FPGA_FAMILY {}".format(pkg.fpga_family))
+        fo.write("\nconst FPGA_PERIOD {}".format(pkg.fpga_per))
+        fo.write("\nconst FPGA_FREQ {}".format(pkg.fpga_freq))
+        fo.write("\nconst INP_MEM_AXI_RATIO {}".format(pkg.inp_mem_axi_ratio))
+        fo.write("\nconst WGT_MEM_AXI_RATIO {}".format(pkg.wgt_mem_axi_ratio))
+        fo.write("\nconst OUT_MEM_AXI_RATIO {}".format(pkg.out_mem_axi_ratio))
+        fo.write("\nconst INP_MEM_BANKS {}".format(pkg.inp_mem_banks))
+        fo.write("\nconst WGT_MEM_BANKS {}".format(pkg.wgt_mem_banks))
+        fo.write("\nconst OUT_MEM_BANKS {}".format(pkg.out_mem_banks))
+        fo.write("\nconst INP_MEM_WIDTH {}".format(pkg.inp_mem_width))
+        fo.write("\nconst WGT_MEM_WIDTH {}".format(pkg.wgt_mem_width))
+        fo.write("\nconst OUT_MEM_WIDTH {}".format(pkg.out_mem_width))
+        fo.write("\nconst INP_MEM_DEPTH {}".format(pkg.inp_mem_depth))
+        fo.write("\nconst WGT_MEM_DEPTH {}".format(pkg.wgt_mem_depth))
+        fo.write("\nconst OUT_MEM_DEPTH {}".format(pkg.out_mem_depth))
+        fo.write("\nconst NUM_WGT_MEM_URAM {}".format(calculate_num_wgt_uram(pkg)))
+        fo.write("\nconst AXI_CACHE_BITS {}".format(pkg.axi_cache_bits))
+        fo.write("\nconst AXI_PROT_BITS {}".format(pkg.axi_prot_bits))
+        fo.write("\nconst IP_REG_MAP_RANGE {}".format(pkg.ip_reg_map_range))
+        fo.write("\nconst FETCH_BASE_ADDR {}".format(pkg.fetch_base_addr))
+        fo.write("\nconst LOAD_BASE_ADDR {}".format(pkg.load_base_addr))
+        fo.write("\nconst COMPUTE_BASE_ADDR {}".format(pkg.compute_base_addr))
+        fo.write("\nconst STORE_BASE_ADDR {}".format(pkg.store_base_addr))
+
 def main():
     """Main funciton"""
     parser = argparse.ArgumentParser()
@@ -103,6 +164,8 @@
                         help="returns FPGA frequency")
     parser.add_argument("--get-fpga-per", action="store_true",
                         help="returns HLS target clock period")
+    parser.add_argument("--export-tcl", type=str, default="",
+                        help="export variables to tcl file")
     args = parser.parse_args()
 
     if len(sys.argv) == 1:
@@ -137,14 +200,7 @@
         print(" ".join(pkg.lib_source))
 
     if args.cflags:
-        cflags_str = " ".join(pkg.cflags)
-        if pkg.TARGET == "pynq":
-            cflags_str += " -DVTA_TARGET_PYNQ"
-        elif pkg.TARGET == "de10nano":
-            cflags_str += " -DVTA_TARGET_DE10_NANO"
-        elif pkg.TARGET == "ultra96":
-            cflags_str += " -DVTA_TARGET_ULTRA96"
-        print(cflags_str)
+        print(gen_target_cflags(pkg))
 
     if args.ldflags:
         print(" ".join(pkg.ldflags))
@@ -196,10 +252,7 @@
         print(pkg.out_mem_axi_ratio)
 
     if args.get_num_wgt_mem_uram:
-        if hasattr(pkg, 'num_wgt_mem_uram'):
-            print(pkg.num_wgt_mem_uram)
-        else:
-            print(0)
+        print(calculate_num_wgt_uram(pkg))
 
     if args.get_axi_cache_bits:
         print(pkg.axi_cache_bits)
@@ -234,5 +287,8 @@
     if args.get_fpga_per:
         print(pkg.fpga_per)
 
+    if args.export_tcl:
+        gen_tcl_vivado(pkg, args.export_tcl)
+
 if __name__ == "__main__":
     main()
diff --git a/hardware/xilinx/Makefile b/hardware/xilinx/Makefile
index 2651583..f2dafba 100644
--- a/hardware/xilinx/Makefile
+++ b/hardware/xilinx/Makefile
@@ -34,6 +34,9 @@
 IP_BUILD_PATH := $(BUILD_DIR)/hls/$(CONF)
 HW_BUILD_PATH := $(BUILD_DIR)/vivado/$(CONF)
 
+# Config files
+CONFIG_TCL = $(BUILD_DIR)/include/vta_config.tcl
+
 # IP file path
 IP_PATH := $(BUILD_DIR)/hls/$(CONF)/vta_compute/soln/impl/ip/xilinx_com_hls_compute_1_0.zip
 
@@ -46,14 +49,20 @@
 ip: $(IP_PATH)
 bit: $(BIT_PATH)
 
-$(IP_PATH): $(SRC_DIR)/*
+$(BUILD_DIR)/include:
+	mkdir -p $@
+
+$(CONFIG_TCL): | $(BUILD_DIR)/include
+	python $(VTA_CONFIG) --export-tcl $@
+
+$(IP_PATH): $(SRC_DIR)/* $(CONFIG_TCL)
 	mkdir -p $(IP_BUILD_PATH)
 	cd $(IP_BUILD_PATH) && \
 		$(VIVADO_HLS) \
 		-f $(SCRIPT_DIR)/hls.tcl \
 		-tclargs \
 			$(VTA_HW_DIR) \
-			${VTA_CONFIG}
+			$(CONFIG_TCL)
 
 $(BIT_PATH): $(IP_PATH)
 	mkdir -p $(HW_BUILD_PATH)
@@ -63,7 +72,7 @@
 		-source $(SCRIPT_DIR)/vivado.tcl \
 		-tclargs \
 			$(BUILD_DIR)/hls/$(CONF) \
-			${VTA_CONFIG}
+			$(CONFIG_TCL)
 
 clean:
 	rm -rf *.out *.log
diff --git a/hardware/xilinx/scripts/hls.tcl b/hardware/xilinx/scripts/hls.tcl
index 724bdbf..ef46698 100644
--- a/hardware/xilinx/scripts/hls.tcl
+++ b/hardware/xilinx/scripts/hls.tcl
@@ -32,21 +32,24 @@
 set sim_dir "$root_dir/hardware/xilinx/sim"
 set test_dir "$root_dir/tests/hardware/common"
 
+# Source vta config variables
+source $vta_config
+
 # C define flags that we want to pass to the compiler
-set cflags [exec python $vta_config --cflags]
+set cflags $CFLAGS
 
 # Get the VTA configuration paramters
-set ::device        [exec python $vta_config --get-fpga-dev]
-set ::period        [exec python $vta_config --get-fpga-per]
+set ::device $FPGA_DEVICE
+set ::period $FPGA_PERIOD
 
 # Get the VTA SRAM reshape/partition factors to get all memories
 # to be of the same axi width.
-set ::inp_reshape_factor    [exec python $vta_config --get-inp-mem-axi-ratio]
-set ::inp_partition_factor  [exec python $vta_config --get-inp-mem-banks]
-set ::wgt_reshape_factor    [exec python $vta_config --get-wgt-mem-axi-ratio]
-set ::wgt_partition_factor  [exec python $vta_config --get-wgt-mem-banks]
-set ::out_reshape_factor    [exec python $vta_config --get-out-mem-axi-ratio]
-set ::out_partition_factor  [exec python $vta_config --get-out-mem-banks]
+set ::inp_reshape_factor    $INP_MEM_AXI_RATIO
+set ::inp_partition_factor  $INP_MEM_BANKS
+set ::wgt_reshape_factor    $WGT_MEM_AXI_RATIO
+set ::wgt_partition_factor  $WGT_MEM_BANKS
+set ::out_reshape_factor    $OUT_MEM_AXI_RATIO
+set ::out_partition_factor  $OUT_MEM_BANKS
 
 
 # Initializes the HLS design and sets HLS pragmas for memory partitioning.
diff --git a/hardware/xilinx/scripts/vivado.tcl b/hardware/xilinx/scripts/vivado.tcl
index e45d24d..77d00ac 100644
--- a/hardware/xilinx/scripts/vivado.tcl
+++ b/hardware/xilinx/scripts/vivado.tcl
@@ -35,33 +35,37 @@
   return 1
 }
 
+# Source vta config variables
+source $vta_config
+
 # Get the VTA configuration paramters
-set target            [exec python $vta_config --target]
-set device_family     [exec python $vta_config --get-fpga-family]
-set clock_freq        [exec python $vta_config --get-fpga-freq]
+set target            $TARGET
+set device            $FPGA_DEVICE
+set device_family     $FPGA_FAMILY
+set clock_freq        $FPGA_FREQ
 
 # SRAM dimensions
-set inp_part          [exec python $vta_config --get-inp-mem-banks]
-set inp_mem_width     [exec python $vta_config --get-inp-mem-width]
-set inp_mem_depth     [exec python $vta_config --get-inp-mem-depth]
-set wgt_part          [exec python $vta_config --get-wgt-mem-banks]
-set wgt_mem_width     [exec python $vta_config --get-wgt-mem-width]
-set wgt_mem_depth     [exec python $vta_config --get-wgt-mem-depth]
-set out_part          [exec python $vta_config --get-out-mem-banks]
-set out_mem_width     [exec python $vta_config --get-out-mem-width]
-set out_mem_depth     [exec python $vta_config --get-out-mem-depth]
-set num_wgt_mem_uram  [exec python $vta_config --get-num-wgt-mem-uram]
+set inp_part          $INP_MEM_BANKS
+set inp_mem_width     $INP_MEM_WIDTH
+set inp_mem_depth     $INP_MEM_DEPTH
+set wgt_part          $WGT_MEM_BANKS
+set wgt_mem_width     $WGT_MEM_WIDTH
+set wgt_mem_depth     $WGT_MEM_DEPTH
+set out_part          $OUT_MEM_BANKS
+set out_mem_width     $OUT_MEM_WIDTH
+set out_mem_depth     $OUT_MEM_DEPTH
+set num_wgt_mem_uram  $NUM_WGT_MEM_URAM
 
 # AXI bus signals
-set axi_cache         [exec python $vta_config --get-axi-cache-bits]
-set axi_prot          [exec python $vta_config --get-axi-prot-bits]
+set axi_cache         $AXI_CACHE_BITS
+set axi_prot          $AXI_PROT_BITS
 
 # Address map
-set ip_reg_map_range  [exec python $vta_config --get-ip-reg-map-range]
-set fetch_base_addr   [exec python $vta_config --get-fetch-base-addr]
-set load_base_addr    [exec python $vta_config --get-load-base-addr]
-set compute_base_addr [exec python $vta_config --get-compute-base-addr]
-set store_base_addr   [exec python $vta_config --get-store-base-addr]
+set ip_reg_map_range  $IP_REG_MAP_RANGE
+set fetch_base_addr   $FETCH_BASE_ADDR
+set load_base_addr    $LOAD_BASE_ADDR
+set compute_base_addr $COMPUTE_BASE_ADDR
+set store_base_addr   $STORE_BASE_ADDR
 
 # Paths to IP library of VTA modules
 set proj_name vta
@@ -74,7 +78,6 @@
 set store_ip "${ip_path}/vta_store/soln/impl/ip/xilinx_com_hls_store_1_0.zip"
 
 # Create custom project
-set device [exec python $vta_config --get-fpga-dev]
 create_project -force $proj_name $proj_path -part $device
 
 # Update IP repository with generated IP