Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypted IP #417

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ env.sh
build.ninja
.ninja_log
.ninja_deps

/_build
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "third_party/gmt_tools"]
path = third_party/gmt_tools
url = [email protected]:byuccl/gmt_tools.git
[submodule "third_party/encrypted_ip"]
path = third_party/encrypted_ip
url = [email protected]:byuccl/encrypted_ip.git
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VIVADO_PATH := "/tools/Xilinx/Vivado/2022.2/bin/vivado"
VIVADO_PATH := "/tools/Xilinx/Vivado/2021.1/bin/vivado"
IN_ENV = if [ -e .venv/bin/activate ]; then . .venv/bin/activate; fi;
CAPNPJ := $(shell which capnpc-java)
PYTHON311 := $(shell which python3.11)
Expand All @@ -10,7 +10,8 @@ PUBLIC_SUBMODULES = \
third_party/WaFoVe

PRIVATE_SUBMODULES = \
third_party/gmt_tools
third_party/gmt_tools \
third_party/encrypted_ip

include external_tools.mk

Expand Down
2 changes: 1 addition & 1 deletion bfasst/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
BUILD = "build"

PART_FAMILY = "artix7"
PART = "xc7a200tsbg484-1"
PART = "xc7a100t-csg324-3"
5 changes: 5 additions & 0 deletions bfasst/external_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from bfasst.config import PART, VIVADO_BIN_PATH
from bfasst.paths import (
ENCRYPTED_IP_PATH,
RAPIDWRIGHT_PATH,
ROOT_PATH,
THIRD_PARTY_PATH,
Expand Down Expand Up @@ -61,6 +62,10 @@ def check_yosys():
return (YOSYS_PATH / "yosys").is_file()


def check_encrypted_ip():
return (ENCRYPTED_IP_PATH / "README.md").is_file()


################################################################################
# Command Line Interface
################################################################################
Expand Down
184 changes: 184 additions & 0 deletions bfasst/flows/encrypted_ip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
"""Flow to create Vivado synthesis and implementation ninja snippets."""
import pathlib
import re
import pandas as pd

import yaml
from bfasst.flows.flow import Flow
from bfasst.tools.impl.vivado_impl import VivadoImpl

from bfasst.tools.ip.ipencrypter import IpEncrypter
from bfasst.tools.ip.loader import EncryptedIpLoader
from bfasst.tools.synth.vivado_synth import VivadoSynth
from bfasst.utils.vivado import parse_hierarchical_utilization


class EncryptedIP(Flow):
def __init__(self, design):
super().__init__(design)

encrypted_ip_paths = []
encrypted_ip_ciphertext_paths = []

assert self.design_props.encrypted_ip, "No encrypted IPs specified"

# ip_definitions = [ip["definition"] for ip in self.design_props.encrypted_ip["ip"]]

# Perform the regular vivado CAD flow
self.synth_regular = VivadoSynth(self, design)
self.impl_regular = VivadoImpl(self, design)

self.synth_tool_per_ip = {}
self.ip_encrypter_tool_per_ip = {}

# Synthesize and encrypt each encrypte IP
for ip in self.design_props.encrypted_ip["ip"]:
ip_definition = ip["definition"]
synth_tool = VivadoSynth(
self,
design,
ooc=True,
top=ip_definition,
synth_options="-flatten_hierarchy full",
)
self.synth_tool_per_ip[ip_definition] = synth_tool
synth_tool.override_build_path(
synth_tool.build_path.parent / f"{synth_tool.build_path.name}_{ip_definition}"
)
synth_tool._init_outputs()

ip_encrypter_tool = IpEncrypter(
self, design, ip_definition, synth_tool.outputs["synth_dcp"]
)
self.ip_encrypter_tool_per_ip[ip_definition] = ip_encrypter_tool
# ip_encrypter_tool.override_build_path(
# ip_encrypter_tool.build_path.parent
# / f"{ip_encrypter_tool.build_path.name}_{ip_definition}"
# )
encrypted_ip_paths.append(ip_encrypter_tool.outputs["encrypted_verilog"])
ip["ciphertext_path"] = str(ip_encrypter_tool.outputs["lut_ciphertext"])

# Synthesize the top module
self.top_synth_tool = VivadoSynth(
self, design, ooc=True, synth_options="-flatten_hierarchy rebuilt"
)
self.top_synth_tool.verilog = [
self.design_path / v for v in self.design_props.encrypted_ip["user_files"]
]
self.top_synth_tool.verilog.extend(encrypted_ip_paths)

# Encrypted IP Shell
self.loader_tool = EncryptedIpLoader(
self,
design,
user_synth_dcp_path=self.top_synth_tool.outputs["synth_dcp"],
encrypted_ip_data=self.design_props.encrypted_ip["ip"],
)

def get_top_level_flow_path(self):
return pathlib.Path(__file__)

def parse_runtime(self, log_path, str_identifier):
with open(log_path, 'r') as f:
txt = f.read()

match = re.search(f"^{str_identifier} start time: (.*)$", txt, re.MULTILINE)
assert match

# Parse the datetime. Example: Fri Mar 1 08:44:27 AM MST 2024
start_time = pd.to_datetime(match.group(1), format="%a %b %d %I:%M:%S %p %Z %Y")

match = re.search(f"^{str_identifier} end time: (.*)$", txt, re.MULTILINE)
assert match

end_time = pd.to_datetime(match.group(1), format="%a %b %d %I:%M:%S %p %Z %Y")

return (end_time - start_time).total_seconds()

def post_execute(self):
print("Running post_execute for EncryptedIP flow")
out_csv_path = self.design_build_path / "area_results.csv"
out_csv_runtime_path = self.design_build_path / "runtime_results.csv"

# Get regular synthesis results
reg_utilization_file = self.synth_regular.outputs["utilization"]
encrypted_utilization_file = self.top_synth_tool.outputs["utilization"]

regular_data = parse_hierarchical_utilization(reg_utilization_file)
encrypted_data = parse_hierarchical_utilization(encrypted_utilization_file)

instances = ["top"] + [
f"top/{definition}"
for ip in self.design_props.encrypted_ip["ip"]
for definition in ip["instances"]
]

df = pd.DataFrame(
columns=["Instance", "LUTs-Regular", "FFs-Regular", "LUTs-Encrypted", "FFs-Encrypted"]
)
for instance in instances:
assert instance in regular_data, f"Instance {instance} not found in regular data"
assert instance in encrypted_data, f"Instance {instance} not found in encrypted data"

row = pd.Series(
{
"Instance": instance,
"LUTs-Regular": regular_data[instance]["Total LUTs"],
"FFs-Regular": regular_data[instance]["FFs"],
"RAMB-Regular": regular_data[instance]["RAMB36"]
+ regular_data[instance]["RAMB18"],
"DSP-Regular": regular_data[instance]["DSP Blocks"],
"LUTs-Encrypted": encrypted_data[instance]["Total LUTs"],
"FFs-Encrypted": encrypted_data[instance]["FFs"],
"RAMB-Encrypted": encrypted_data[instance]["RAMB36"]
+ encrypted_data[instance]["RAMB18"],
"DSP-Encrypted": encrypted_data[instance]["DSP Blocks"],
}
)
df = pd.concat(
[df, row.to_frame().T],
)

df.to_csv(out_csv_path, index=False)


# Get runtimes
df = pd.DataFrame(
columns=["Instance", "Synth-Regular", "Impl-Regular", "Synth-Encrypted", "Impl-Encrypted", "IP-Encryption"]
)
synth_regular_runtime = self.parse_runtime(self.synth_regular.build_path / "vivado.log", "Synth")
impl_regular_runtime = self.parse_runtime(self.impl_regular.build_path / "vivado.log", "Impl")
synth_encrypted_runtime = self.parse_runtime(self.top_synth_tool.build_path / "vivado.log", "Synth")
impl_encrypted_runtime = self.parse_runtime(self.loader_tool.build_path / "vivado.log", "Loader impl")

row = pd.Series({
"Instance": instance,
"Synth-Regular": synth_regular_runtime,
"Impl-Regular": impl_regular_runtime,
"Synth-Encrypted": synth_encrypted_runtime,
"Impl-Encrypted": impl_encrypted_runtime,
"IP-Encryption": "-",
}
)
df = pd.concat(
[df, row.to_frame().T],
)

for ip in self.design_props.encrypted_ip["ip"]:
synth_encrypted_runtime = self.parse_runtime(self.synth_tool_per_ip[ip["definition"]].build_path / "vivado.log", "Synth")
ip_encryption_runtime = self.parse_runtime(self.ip_encrypter_tool_per_ip[ip["definition"]].build_path / "log.txt", "Encryption") + self.parse_runtime(self.ip_encrypter_tool_per_ip[ip["definition"]].build_path / "vivado.log", "DCP to verilog")

row = pd.Series({
"Instance": instance,
"Synth-Regular": "-",
"Impl-Regular": "-",
"Synth-Encrypted": synth_encrypted_runtime,
"Impl-Encrypted": "-",
"IP-Encryption": ip_encryption_runtime,
}
)
df = pd.concat(
[df, row.to_frame().T],
)
df.to_csv(out_csv_runtime_path, index=False)

3 changes: 3 additions & 0 deletions bfasst/flows/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import abc

from bfasst.paths import BUILD_PATH, DESIGNS_PATH
from bfasst.yaml_parser import DesignParser


class FlowBase(abc.ABC):
Expand Down Expand Up @@ -40,6 +41,7 @@ def get_top_level_flow_path(self) -> str:
def create_tool_build_dirs(self):
"""Create the build directories for all tools used by this flow"""
for tool in self.tools:
assert tool.build_path is not None, f"Tool build path must be set for tool {tool}"
tool.build_path.mkdir(parents=True, exist_ok=True)

def post_execute(self):
Expand All @@ -53,6 +55,7 @@ class Flow(FlowBase):
def __init__(self, design_path):
super().__init__()
self.design_path = design_path
self.design_props = DesignParser(design_path / "design.yaml")
self.design_build_path = BUILD_PATH / design_path.relative_to(DESIGNS_PATH)


Expand Down
11 changes: 10 additions & 1 deletion bfasst/flows/flow_descriptions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,13 @@ flows:
class: RandSoc
external_tools:
- vivado
- gmt_tools
- gmt_tools

- name: EncryptedIP
description: Encrypt IP in Vivado
module: encrypted_ip
class: EncryptedIP
external_tools:
- vivado
- encrypted_ip
- rapidwright
3 changes: 2 additions & 1 deletion bfasst/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

ROOT_PATH = pathlib.Path(__file__).resolve().parent.parent

BUILD_PATH = pathlib.Path().cwd() / "build"
BUILD_PATH = pathlib.Path().cwd() / "_build"

DESIGNS_PATH = ROOT_PATH / "designs"
BFASST_PATH = ROOT_PATH / "bfasst"
Expand Down Expand Up @@ -35,6 +35,7 @@
ONESPIN_RESOURCES = RESOURCES_PATH / "onespin"
YOSYS_INSTALL_DIR = THIRD_PARTY_PATH / "yosys"
GMT_TOOLS_PATH = THIRD_PARTY_PATH / "gmt_tools"
ENCRYPTED_IP_PATH = THIRD_PARTY_PATH / "encrypted_ip"
RAPIDWRIGHT_PATH = THIRD_PARTY_PATH / "RapidWright"
YOSYS_PATH = THIRD_PARTY_PATH / "yosys"

Expand Down
10 changes: 10 additions & 0 deletions bfasst/tools/common/dcp_to_v.tcl.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set timen [exec date]
puts "DCP to verilog start time: $timen"

open_checkpoint {{ dcp }}
write_verilog {{ verilog }} -force

set timen [exec date]
puts "DCP to verilog end time: $timen"

close_project
4 changes: 4 additions & 0 deletions bfasst/tools/common/dont_touch.ninja
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rule apply_dont_touch
command = python bfasst/utils/dont_touch.py $in $out $module_name
description = applying don't touch to $in

6 changes: 2 additions & 4 deletions bfasst/tools/common/vivado_rules.ninja.mustache
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
rule vivado
command = export tempjou=$$(mktemp); export templog=$$(mktemp); cd $cwd && {{ utils_path }}/retry.sh {{ vivado_path }} -mode batch -journal $$tempjou -log $$templog -source $in >&- && mv $$tempjou $journal && mv $$templog $log
command = cd $cwd && {{ utils_path }}/retry.sh {{ vivado_path }} -mode batch -journal $journal -log $log -source $in >&- 2>&-
description = vivado $in

{{#in_context}}
rule vivado_ioparse
command = python3 bfasst/utils/vivado_ioparse.py <$in >$out
description = vivado_ioparse <$in >$out

{{/in_context}}

6 changes: 5 additions & 1 deletion bfasst/tools/impl/vivado_impl.tcl.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ read_xdc {{ . }}

{{/xdc}}
set_property design_mode GateLvl [current_fileset]
set timen [exec date]
puts "Impl start time: $timen"
opt_design
place_design
route_design
set timen [exec date]
puts "Impl end time: $timen"
write_checkpoint -force -file {{ impl_output }}/impl.dcp
write_edif -force -file {{ impl_output }}/viv_impl.edf
write_verilog -force -file {{ impl_output }}/viv_impl.v
report_utilization -file {{ impl_output }}/utilization.txt
report_utilization -file {{ impl_output }}/utilization.txt -hierarchical
{{#bit}}
write_bitstream -force {{ . }}

Expand Down
Loading