mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-05-06 07:54:59 -04:00
hw/tool: UDI/UDS storage
Describe how the UDI and UDS are actually stored in the FPGA, how they are accessed, and how they are initialled by the patch_uds_udi.py script. Co-authored-by: Joachim Strömbergson <joachim@assured.se>
This commit is contained in:
parent
1c90b1aa3d
commit
3cf218469c
3 changed files with 87 additions and 32 deletions
|
@ -5,32 +5,40 @@
|
|||
# Written by Myrtle Shah <gatecat@ds0.me>
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# patch_uds_udi.py
|
||||
# --------------
|
||||
# Python program that patches the UDS and UDI implemented using
|
||||
# named LUT4 instances to have unique initial values, not the generic
|
||||
# values used during synthesis, p&r and mapping. This allows us to
|
||||
# generate device unique bitstreams without running the complete flow.
|
||||
# Script to patch in a Unique Device Secret (UDS) and a Unique Device
|
||||
# Identifier (UDI) from files into a bitstream.
|
||||
#
|
||||
# Both the UDI and UDS are using bit indexing from 32 LUTs for each
|
||||
# word, i.e., the first word consists of bit 0 from each 32 LUTs and
|
||||
# so on.
|
||||
# It's supposed to be run like this:
|
||||
#
|
||||
# The size requirements for the UDI and UDS are specified as 1 bit (8
|
||||
# bytes of data) and 3 bits (32 bytes of data), respectively. The UDI
|
||||
# does not occupy the entire LUT4 instance, and to conserve resources,
|
||||
# the pattern of the UDI is repeated over the unused portion of the
|
||||
# LUT4 instance. This eliminates the need to drive the three MSB pins
|
||||
# while still achieving the correct output.
|
||||
# nextpnr-ice40 --up5k --package sg48 --ignore-loops \
|
||||
# --json application_fpga_par.json --run patch_uds_udi.py
|
||||
#
|
||||
# In the case of UDS, a read-enable signal is present, and the most
|
||||
# significant bit serves as the read-enable input. This requires the
|
||||
# lower half of initialization bits to be forced to zero, ensuring
|
||||
# that the memory outputs zero when the read-enable signal is
|
||||
# inactive.
|
||||
# with this environment:
|
||||
#
|
||||
# - UDS_HEX: path to the UDS file, typically the path to
|
||||
# ../data/uds.hex
|
||||
# - UDI_HEX: path to the UDI file, typically the path to ../data/udi.hex
|
||||
# - OUT_ASC: path to the ASC output that is then used by icebram and icepack.
|
||||
#
|
||||
#=======================================================================
|
||||
# The script changes the UDS and UDI that are stored in named 4-bit
|
||||
# LUT instances in the JSON file so we can generate device
|
||||
# unique bitstreams without running the complete flow just to change
|
||||
# UDS and UDI. Then we can just run the final bitstream generation
|
||||
# from the ASC file.
|
||||
#
|
||||
# We represent our UDI and UDS values as a number of 32 bit words:
|
||||
#
|
||||
# - UDI: 2 words.
|
||||
# - UDS: 8 words.
|
||||
#
|
||||
# We reserve 32 named 4-bit LUTs *each* to store the data: UDS in
|
||||
# "uds_rom_idx" and UDI in "udi_rom_idx".
|
||||
#
|
||||
# The script repeats the value in the LUTs so we don't have to care
|
||||
# about the value of the unused address bits.
|
||||
#
|
||||
# See documentation in their implementation in ../core/uds/README.md
|
||||
# and ../core/tk1/README.md
|
||||
|
||||
import os
|
||||
|
||||
|
@ -49,7 +57,8 @@ def rewrite_lut(lut, idx, data, has_re=False):
|
|||
new_init = 0
|
||||
for i, word in enumerate(data):
|
||||
if (word >> idx) & 0x1:
|
||||
# repeat so inputs above address have a don't care value
|
||||
# repeat so we don't have to care about inputs above
|
||||
# address
|
||||
repeat = (16 // len(data))
|
||||
for k in range(repeat):
|
||||
# UDS also has a read enable
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue