summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/.gitignore5
-rw-r--r--util/bitstream2mcs.py162
-rw-r--r--util/requirements.txt1
3 files changed, 168 insertions, 0 deletions
diff --git a/util/.gitignore b/util/.gitignore
new file mode 100644
index 0000000..03fbf09
--- /dev/null
+++ b/util/.gitignore
@@ -0,0 +1,5 @@
+.idea/
+venv/
+
+*.bin
+*.mcs
diff --git a/util/bitstream2mcs.py b/util/bitstream2mcs.py
new file mode 100644
index 0000000..571375f
--- /dev/null
+++ b/util/bitstream2mcs.py
@@ -0,0 +1,162 @@
+# ---------------------------------------------------------------------------------------------------------------------
+# bitstream2mcs.py
+# ---------------------------------------------------------------------------------------------------------------------
+#
+# Convert iCE40 bitstream into .mcs format suitable for programming using Xilinx iMPACT tool. Xilinx .mcs is in fact
+# just plain Intel Hex. Since the beginning of our configuration memory is occupied by the main FPGA bitstream, we
+# have to move iCE40 bitstream to the end of the configuration memory space.
+#
+# ---------------------------------------------------------------------------------------------------------------------
+#
+# 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 typing import Union
+from intelhex import IntelHex
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Settings
+# ---------------------------------------------------------------------------------------------------------------------
+LATTICE_MAGIC_MARKER = b'\x7E\xAA\x99\x7E'
+
+PROM_SECTOR_SIZE = 256 * 256
+PROM_NUM_SECTORS = 256
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _load_bitstream(filename: str) -> Union[bytes, None]:
+
+ # 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))
+
+ # try to strip header
+ while not bitstream.startswith(LATTICE_MAGIC_MARKER):
+ bitstream = bitstream[1:]
+ if not bitstream:
+ print("Magic marker not found??")
+ return
+
+ # 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_mcs(offset: int, bitstream: bytes, filename: str) -> int:
+
+ # create Intel Hex class
+ ih = IntelHex()
+
+ # initialize memory from bitstream
+ ih.frombytes(bitstream, offset=offset)
+
+ # write memory to file
+ with open(filename, 'w') as f:
+ ih.write_hex_file(f)
+
+ # done
+ return 0
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def _bitstream2mcs(filename_in: str, filename_out: str) -> int:
+
+ # load bitstream
+ bitstream = _load_bitstream(filename_in)
+ if bitstream is None:
+ return 1
+
+ # determine number of sectors needed
+ num_sectors = math.ceil(len(bitstream) / PROM_SECTOR_SIZE)
+ print("Number of PROM sectors needed: %d" % num_sectors)
+ prom_offset = (PROM_NUM_SECTORS - num_sectors) * PROM_SECTOR_SIZE
+ print("Bitstream offset: 0x%x" % prom_offset)
+
+ # save mcs
+ return _save_mcs(prom_offset, bitstream, filename_out)
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def print_usage() -> int:
+ print("USAGE: %s <bitstream.bin> <bitstream.mcs>" % os.path.basename(sys.argv[0]))
+ return 2
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+def main() -> int:
+
+ # check, that exactly two arguments were supplied
+ if len(sys.argv) != 3:
+ return print_usage()
+
+ # now run the script
+ return _bitstream2mcs(sys.argv[1], sys.argv[2])
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+if __name__ == '__main__':
+ sys.exit(main())
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+# End-of-File
+# ---------------------------------------------------------------------------------------------------------------------
diff --git a/util/requirements.txt b/util/requirements.txt
new file mode 100644
index 0000000..e4a435a
--- /dev/null
+++ b/util/requirements.txt
@@ -0,0 +1 @@
+intelhex==2.3.0