From 6d893207214bb99c66a806af21935e7a421d8d35 Mon Sep 17 00:00:00 2001 From: Javier Valenzuela Date: Mon, 4 Dec 2023 13:59:49 +0000 Subject: [PATCH] fpga: x400: Add netlist make flow Original-commit: 789fa8f65727afabdeb4eea30a941015c6cd2ad5 --- tools/make/viv_design_builder.mak | 1 + tools/scripts/viv_secure_synth.tcl | 19 +++++ tools/scripts/viv_utils.tcl | 118 +++++++++++++++++++++++++++-- top/x400/Makefile | 4 + top/x400/Makefile.x4xx.inc | 5 +- 5 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 tools/scripts/viv_secure_synth.tcl diff --git a/tools/make/viv_design_builder.mak b/tools/make/viv_design_builder.mak index 2dafacb..8519ddf 100644 --- a/tools/make/viv_design_builder.mak +++ b/tools/make/viv_design_builder.mak @@ -29,6 +29,7 @@ BUILD_VIVADO_DESIGN = \ export VIV_DESIGN_SRCS=$(call RESOLVE_PATHS,$(call uniq,$(DESIGN_SRCS))); \ export VIV_VERILOG_DEFS="$(VERILOG_DEFS) UHD_FPGA_DIR=$(BASE_DIR)/../.."; \ export VIV_INCR_BUILD=$(INCR_BUILD); \ + export VIV_SECURE_KEY=$(call RESOLVE_PATH,$(abspath $(SECURE_KEY))); \ cd $(BUILD_DIR); \ $(TOOLS_DIR)/scripts/launch_vivado.py --parse-config $(MAKEFILE_DIR)/dev_config.json -mode $(VIVADO_MODE) -source $(call RESOLVE_PATH,$(1)) -log build.log -journal $(2).jou diff --git a/tools/scripts/viv_secure_synth.tcl b/tools/scripts/viv_secure_synth.tcl new file mode 100644 index 0000000..149c70e --- /dev/null +++ b/tools/scripts/viv_secure_synth.tcl @@ -0,0 +1,19 @@ +# +# Copyright 2024 Ettus Research, a National Instruments Brand +# + +source $::env(VIV_TOOLS_DIR)/scripts/viv_utils.tcl +source $::env(VIV_TOOLS_DIR)/scripts/viv_strategies.tcl + +# STEP#1: Create project, add sources, refresh IP +vivado_utils::initialize_project + +# STEP#2: Run synthesis +vivado_utils::synthesize_design -mode out_of_context +vivado_utils::generate_post_synth_reports + +# STEP#3: Generate encrypted netlist +vivado_utils::export_encrypted_netlist + +# Cleanup +vivado_utils::close_batch_project diff --git a/tools/scripts/viv_utils.tcl b/tools/scripts/viv_utils.tcl index 449b4b9..481d511 100644 --- a/tools/scripts/viv_utils.tcl +++ b/tools/scripts/viv_utils.tcl @@ -10,6 +10,9 @@ namespace eval ::vivado_utils { namespace export \ initialize_project \ synthesize_design \ + export_synth_netlist \ + separate_encrypted \ + export_encrypted_netlist \ check_design \ generate_post_synth_reports \ generate_post_place_reports \ @@ -27,6 +30,7 @@ namespace eval ::vivado_utils { variable g_source_files $::env(VIV_DESIGN_SRCS) variable g_vivado_mode $::env(VIV_MODE) variable g_project_save $::env(VIV_PROJECT) + variable g_secure_key $::env(VIV_SECURE_KEY) # Optional environment variables variable g_verilog_defs "" @@ -73,23 +77,29 @@ proc ::vivado_utils::initialize_project { {save_to_disk 0} } { foreach src_file $g_source_files { set src_ext [file extension $src_file ] if [expr [lsearch {.vhd .vhdl} $src_ext] >= 0] { - puts "BUILDER: Adding VHDL : $src_file" + puts "BUILDER: Adding VHDL: $src_file" read_vhdl -library work $src_file - } elseif [expr [lsearch {.v .vh .sv .svh} $src_ext] >= 0] { - puts "BUILDER: Adding Verilog : $src_file" + } elseif [expr [lsearch {.v .vh} $src_ext] >= 0] { + puts "BUILDER: Adding Verilog: $src_file" read_verilog $src_file + } elseif [expr [lsearch {.vp} $src_ext] >= 0] { + puts "BUILDER: Adding encrypted Verilog: $src_file" + read_verilog $src_file + } elseif [expr [lsearch {.sv .svh} $src_ext] >= 0] { + puts "BUILDER: Adding SystemVerilog: $src_file" + read_verilog -sv $src_file } elseif [expr [lsearch {.xdc} $src_ext] >= 0] { - puts "BUILDER: Adding XDC : $src_file" + puts "BUILDER: Adding XDC: $src_file" read_xdc $src_file } elseif [expr [lsearch {.sdc} $src_ext] >= 0] { - puts "BUILDER: Adding SDC : $src_file" + puts "BUILDER: Adding SDC: $src_file" read_xdc $src_file } elseif [expr [lsearch {.xci} $src_ext] >= 0] { - puts "BUILDER: Adding IP : $src_file" + puts "BUILDER: Adding IP: $src_file" read_ip $src_file set_property generate_synth_checkpoint true [get_files $src_file] } elseif [expr [lsearch {.ngc .edif .edf} $src_ext] >= 0] { - puts "BUILDER: Adding Netlist : $src_file" + puts "BUILDER: Adding Netlist: $src_file" read_edif $src_file } elseif [expr [lsearch {.bd} $src_ext] >= 0] { puts "BUILDER: Adding Block Design to list (added after IP regeneration): $src_file" @@ -98,7 +108,7 @@ proc ::vivado_utils::initialize_project { {save_to_disk 0} } { puts "BUILDER: Adding Block Design XML to list (added after IP regeneration): $src_file" append bd_files "$src_file " } elseif [expr [lsearch {.dat} $src_ext] >= 0] { - puts "BUILDER: Adding Data File : $src_file" + puts "BUILDER: Adding Data File: $src_file" add_files $src_file } else { puts "BUILDER: \[WARNING\] File ignored!!!: $src_file" @@ -148,6 +158,98 @@ proc ::vivado_utils::synthesize_design {args} { eval $synth_cmd } +# --------------------------------------------------- +# Generate netlist from Synthesis +# --------------------------------------------------- +proc ::vivado_utils::export_synth_netlist { {suffix ""} } { + variable g_output_dir + variable g_top_module + + puts "BUILDER: Writing EDIF netlist for $g_top_module" + set filename ${g_output_dir}/${g_top_module} + if { [expr [string length $suffix] > 0] } { + set filename ${filename}_${suffix} + } + write_edif -security_mode all -force ${filename}.edf + write_verilog -mode synth_stub -force -file ${filename}_stub.v +} + +# --------------------------------------------------- +# Extract encrypted sections from a file +# --------------------------------------------------- +proc ::vivado_utils::separate_encrypted {input_filename unencrypted_filename encrypted_filename} { + set protected_sections "" + set unprotected_sections "" + set inside_protected_section 0 + + # Read each line from the input file and separate it into protected and + # unprotected sections. + set input_file [open $input_filename r] + while {[gets $input_file line] >= 0} { + # Check if we are inside a protected section + if {[string match "*`pragma protect begin_protected*" $line]} { + set inside_protected_section 1 + } + + # Append the line to the appropriate section + if {$inside_protected_section} { + append protected_sections "$line\n" + } else { + append unprotected_sections "$line\n" + } + + if {[string match "*`pragma protect end_protected*" $line]} { + set inside_protected_section 0 + } + } + close $input_file + + # Write the extracted portions to files + set encrypted_file [open $encrypted_filename w] + puts $encrypted_file $protected_sections + close $encrypted_file + set unencrypted_file [open $unencrypted_filename w] + puts $unencrypted_file $unprotected_sections + close $unencrypted_file +} + +# --------------------------------------------------------- +# Generate an IEEE-1735 encrypted netlist in a single file +# --------------------------------------------------------- +proc ::vivado_utils::export_encrypted_netlist { {suffix ""} } { + variable g_output_dir + variable g_top_module + variable g_secure_key + + puts "BUILDER: Writing encrypted netlist for $g_top_module" + set filename ${g_output_dir}/${g_top_module} + if { [expr [string length $suffix] > 0] } { + set filename ${filename}_${suffix} + } + + # Uniquify the module names to prevent collisions when the netlist is used + rename_ref -prefix_all $g_top_module + + # Write the design to a Verilog netlist + write_verilog -force ${filename}_netlist.v + puts "BUILDER: Unencrypted netlist written to ${filename}_netlist.v" + write_xdc -force ${filename}.xdc + puts "BUILDER: Constraints written to ${filename}.xdc" + if {$g_secure_key ne ""} { + # The netlist may have parts that are already encrypted and Vivado doesn't + # let us encrypt stuff that's already encrypted, so we need to split it up. + vivado_utils::separate_encrypted ${filename}_netlist.v ${filename}_netlist_user.v ${filename}_netlist_other.vp + # Encrypt the parts that aren't already encrypted + encrypt -key ${g_secure_key} -lang verilog -ext .vp ${filename}_netlist_user.v + # Merge the two encrypted files + set combined_netlists [read [open ${filename}_netlist_user.vp r]][read [open ${filename}_netlist_other.vp r]] + set combined_netlists_file [open ${filename}.vp w] + puts $combined_netlists_file $combined_netlists + close $combined_netlists_file + puts "BUILDER: Encrypted netlist written to ${filename}.vp" + } +} + # --------------------------------------------------- # Check design (Shortcut for Vivado's synth_design -rtl) # --------------------------------------------------- diff --git a/top/x400/Makefile b/top/x400/Makefile index f68012f..dff0978 100644 --- a/top/x400/Makefile +++ b/top/x400/Makefile @@ -48,6 +48,9 @@ ifndef TARGET TARGET = synth else ifeq ($(IP_ONLY), 1) TARGET = viv_ip + else ifeq ($(SECURE_CORE), 1) + TARGET = secure_core + TOP = secure_image_core else TARGET = bin endif @@ -174,6 +177,7 @@ help: ##Show this help message. ##CHECK=1 Launch the syntax checker instead of building a bitfile. ##IP_ONLY=1 Launch the build but stop after IP generation. ##SYNTH=1 Launch the build but stop after synthesis. +##SECURE_CORE=1 Launch a build of the secure image core only. ##BUILD_SEED= Build seed to used to affect build results. (Default is 0) ##TOP= Specify a top module for syntax checking. (Default is the bitfile top) diff --git a/top/x400/Makefile.x4xx.inc b/top/x400/Makefile.x4xx.inc index 35b09b3..95c8a42 100644 --- a/top/x400/Makefile.x4xx.inc +++ b/top/x400/Makefile.x4xx.inc @@ -187,4 +187,7 @@ rtl: .prereqs viv_ip: .prereqs $$(DESIGN_SRCS) ip @echo "IP build for $(NAME) DONE . . ." -.PHONY: bin synth rtl viv_ip +secure_core: .prereqs + $(call BUILD_VIVADO_DESIGN,$(TOOLS_DIR)/scripts/viv_secure_synth.tcl,$(TOP_MODULE),$(ARCH),$(PART_ID)) + +.PHONY: bin synth rtl viv_ip secure_synth_netlist