summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2021-12-20 12:50:54 +0300
committerPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2021-12-20 12:50:54 +0300
commit9ecc9e83e8d182b7dbc3e21f3ba7870747c81e92 (patch)
tree2b7b2b8aab5082e058d34ff555accef2007e3a86
parent69eda72fa8db3e332de6a66a92f994dfed99de94 (diff)
Script to combine main FPGA bitstream with the MKM bitmap so that the combined
binary blob can be flashed using the upload script.
-rw-r--r--util/.gitignore1
-rw-r--r--util/link_bitstreams.py205
2 files changed, 206 insertions, 0 deletions
diff --git a/util/.gitignore b/util/.gitignore
index 03fbf09..f7d1bfe 100644
--- a/util/.gitignore
+++ b/util/.gitignore
@@ -1,5 +1,6 @@
.idea/
venv/
+*.bit
*.bin
*.mcs
diff --git a/util/link_bitstreams.py b/util/link_bitstreams.py
new file mode 100644
index 0000000..7e1439a
--- /dev/null
+++ b/util/link_bitstreams.py
@@ -0,0 +1,205 @@
+# ---------------------------------------------------------------------------------------------------------------------
+# link_bitstreams.py
+# ---------------------------------------------------------------------------------------------------------------------
+#
+# Glue iCE40 bitstream to the main FPGA bitstream. The MKM bitstream is aligned on a sector boundary.
+#
+# ---------------------------------------------------------------------------------------------------------------------
+#
+# Copyright 2021 The Commons Conservancy Cryptech Project
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of the copyright holder nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Imports
+# ---------------------------------------------------------------------------------------------------------------------
+import os
+import sys
+import math
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# More Imports
+# ---------------------------------------------------------------------------------------------------------------------
+from enum import Enum
+from typing import Optional
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Markers
+# ---------------------------------------------------------------------------------------------------------------------
+MARKER_XILINX = b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \
+ b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \
+ b"\x00\x00\x00\xBB\x11\x22\x00\x44\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" \
+ b"\xAA\x99\x55\x66"
+
+MARKER_LATTICE = b"\x7E\xAA\x99\x7E"
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+class FPGA(Enum):
+ Artix7 = 'artix7'
+ iCE40 = 'ice40'
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Settings
+# ---------------------------------------------------------------------------------------------------------------------
+PROM_PAGE_BYTES = 256
+PROM_SECTOR_BYTES = 256 * PROM_PAGE_BYTES
+
+MARKER_DICT = {FPGA.Artix7: MARKER_XILINX,
+ FPGA.iCE40: MARKER_LATTICE}
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _load_bitstream(filename: str, fpga: FPGA) -> Optional[bytes]:
+
+ # try to load input bitstream
+ try:
+ with open(filename, 'rb') as f:
+ bitstream = f.read()
+
+ except FileNotFoundError:
+ print("File '%s' not found." % filename)
+ return
+
+ finally:
+ len_bitstream_orig = len(bitstream)
+ print("File '%s' loaded, %d bytes." % (filename, len_bitstream_orig))
+
+ # check magic marker and strip leading bytes
+ bitstream = _check_marker(bitstream, fpga)
+
+ # done
+ return bitstream
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _check_marker(bitstream: bytes, fpga: FPGA) -> Optional[bytes]:
+
+ len_bitstream_orig = len(bitstream)
+ marker = MARKER_DICT[fpga]
+
+ # check, that marker is present
+ if marker not in bitstream:
+ print(" Magic marker for device '%s' not found, did you specify the right filename?" % fpga.value)
+ return
+
+ # try to strip leading redundant bytes
+ while not bitstream.startswith(marker):
+ bitstream = bitstream[1:]
+
+ # print how many bytes we stripped
+ num_stripped_bytes = len_bitstream_orig - len(bitstream)
+ print(" Stripped %d bytes before the magic marker." % num_stripped_bytes)
+
+ # done
+ return bitstream
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _save_bit(bitstream: bytes, filename: str) -> int:
+
+ # write memory to file
+ with open(filename, 'wb') as f:
+ f.write(bitstream)
+
+ print("Output bitstream written.")
+
+ # done
+ return 0
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _link_bitstreams(filename_artix7: str, filename_ice40: str, filename_output: str) -> int:
+
+ # load bitstream
+ bitstream_artix7 = _load_bitstream(filename_artix7, FPGA.Artix7)
+ bitstream_ice40 = _load_bitstream(filename_ice40, FPGA.iCE40)
+ if bitstream_artix7 is None or bitstream_ice40 is None:
+ return 1
+
+ # grow main bitstream to sector boundary
+ num_sectors_artix7 = math.ceil(len(bitstream_artix7) / PROM_SECTOR_BYTES)
+ num_padding_bytes = num_sectors_artix7 * PROM_SECTOR_BYTES - len(bitstream_artix7)
+ print("Added %d byte(s) after the main bitstream to align the MKM bitmap on sector boundary." % num_padding_bytes)
+ padding_bytes = bytes(0xFF for _ in range(num_padding_bytes))
+ bitstream_artix7_padded = bitstream_artix7 + padding_bytes
+
+ # glue two bitstreams
+ bitstream_output = bitstream_artix7_padded + bitstream_ice40
+
+ # fill bitstream with 0xFF's up to page boundary
+ num_padding_bytes = PROM_PAGE_BYTES - (len(bitstream_output) % 256)
+ print("Added %d byte(s) after the mkm bitmap to align output on page boundary." % num_padding_bytes)
+ padding_bytes = bytes(0xFF for _ in range(num_padding_bytes))
+ bitstream_output += padding_bytes
+
+ # save bit
+ return _save_bit(bitstream_output, filename_output)
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def print_usage() -> int:
+ print("USAGE: %s <fpga_bitstream.bit> <mkm_bitmap.bin> <combined_bitstream.bit>" %
+ os.path.basename(sys.argv[0]))
+ return 2
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def main() -> int:
+
+ # check, that exactly three arguments were supplied
+ if len(sys.argv) != 4:
+ return print_usage()
+
+ # now run the script
+ return _link_bitstreams(*sys.argv[1:4])
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+if __name__ == '__main__':
+ sys.exit(main())
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# End-of-File
+# ---------------------------------------------------------------------------------------------------------------------