mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2024-12-25 07:29:25 -05:00
Add script to split app into simulation ram
Co-authored-by: Mikael Ågren <mikael@tillitis.se>
This commit is contained in:
parent
3cd902f792
commit
fe9055ea23
149
hw/application_fpga/tools/app_bin_to_spram_hex.py
Normal file
149
hw/application_fpga/tools/app_bin_to_spram_hex.py
Normal file
@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2024 Tillitis AB
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Converts one TKey app binary into four files suitable to load into SPRAM"
|
||||
" during simulation."
|
||||
)
|
||||
)
|
||||
|
||||
arg_parser.add_argument("app_bin")
|
||||
arg_parser.add_argument("output_spram0_hex")
|
||||
arg_parser.add_argument("output_spram1_hex")
|
||||
arg_parser.add_argument("output_spram2_hex")
|
||||
arg_parser.add_argument("output_spram3_hex")
|
||||
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
|
||||
def abort(msg: str, exitcode: int):
|
||||
sys.stderr.write(msg + "\n")
|
||||
sys.exit(exitcode)
|
||||
|
||||
|
||||
with (
|
||||
open(args.app_bin, "rb") as app,
|
||||
open(args.output_spram0_hex, "w") as spram0,
|
||||
open(args.output_spram1_hex, "w") as spram1,
|
||||
open(args.output_spram2_hex, "w") as spram2,
|
||||
open(args.output_spram3_hex, "w") as spram3,
|
||||
):
|
||||
|
||||
# For debug
|
||||
# app = open("app.bin", "rb")
|
||||
# spram0 = open("output_spram0_hex", "w")
|
||||
# spram1 = open("output_spram1_hex", "w")
|
||||
# spram2 = open("output_spram2_hex", "w")
|
||||
# spram3 = open("output_spram3_hex", "w")
|
||||
|
||||
SPRAM_SIZE_BYTES = int(256 * 1024 / 8)
|
||||
RAM_SIZE_BYTES = SPRAM_SIZE_BYTES * 4
|
||||
|
||||
rows, cols = int(SPRAM_SIZE_BYTES / 2), 2
|
||||
ram0 = [[0] * cols for _ in range(rows)]
|
||||
ram1 = [[0] * cols for _ in range(rows)]
|
||||
ram2 = [[0] * cols for _ in range(rows)]
|
||||
ram3 = [[0] * cols for _ in range(rows)]
|
||||
|
||||
# Input data is little endian
|
||||
input_data_le = app.read()
|
||||
|
||||
if len(input_data_le) % 2 != 0:
|
||||
abort("Error: File size not a multiple of 2 bytes", -1)
|
||||
|
||||
if len(input_data_le) > RAM_SIZE_BYTES:
|
||||
abort("Error: File does not fit in RAM", -1)
|
||||
|
||||
# Zero-pad input to RAM size
|
||||
input_data_le += b"\x00" * (RAM_SIZE_BYTES - len(input_data_le))
|
||||
|
||||
# Set ram_addr_rand and ram_data_rand to the values the simulated TRNG
|
||||
# will deliver.
|
||||
ram_addr_rand = 0xDEADBEEF
|
||||
ram_data_rand = 0xBD5B7DDE
|
||||
|
||||
# Convert RAM
|
||||
cpu_addr_data_le = input_data_le[0:RAM_SIZE_BYTES]
|
||||
|
||||
for cpu_addr in range(0, int(RAM_SIZE_BYTES / 4), 4):
|
||||
|
||||
# Data is little endian
|
||||
word_data_le = cpu_addr_data_le[cpu_addr : cpu_addr + 4]
|
||||
|
||||
# Get ram address
|
||||
ram_addr = cpu_addr >> 2
|
||||
|
||||
# Convert ram_addr to little endian for calculation
|
||||
ram_addr_le = ram_addr.to_bytes(4, byteorder="little", signed=False)
|
||||
|
||||
# Convert ram_data_rand to little endian for calculation
|
||||
ram_data_rand_le = ram_data_rand.to_bytes(4, byteorder="little", signed=False)
|
||||
|
||||
# Concatenate two ram_addr and convert to little endian for calculation
|
||||
ram_addr_double = ((ram_addr << 16) & 0xFFFF0000) | (ram_addr & 0x0000FFFF)
|
||||
ram_addr_double_le = ram_addr_double.to_bytes(
|
||||
4, byteorder="little", signed=False
|
||||
)
|
||||
|
||||
# XOR word_data_le, ram_data_rand_le and ram_addr_le
|
||||
# Explanation:
|
||||
# 1. Zip the byte strings: zip(word_data_le, ram_data_rand_le, ram_addr_double_le) creates
|
||||
# an iterator of tuples with corresponding elements from the byte strings.
|
||||
# 2. Apply XOR: Use a generator expression (a ^ b ^ c for a, b, c in ...) to XOR the values in each tuple.
|
||||
# 3. Convert back to bytes: The bytes constructor collects the XORed values into a new byte string.
|
||||
scrambled_word_data_le = bytes(
|
||||
a ^ b ^ c
|
||||
for a, b, c in zip(word_data_le, ram_data_rand_le, ram_addr_double_le)
|
||||
)
|
||||
|
||||
# Convert ram_addr_rand to little endian for calculation
|
||||
ram_addr_rand_le = ram_addr_rand.to_bytes(4, byteorder="little", signed=False)
|
||||
|
||||
# XOR ram_addr_le and ram_addr_rand_le
|
||||
scrambled_ram_addr_le = bytes(
|
||||
a ^ b for a, b in zip(ram_addr_le, ram_addr_rand_le)
|
||||
)
|
||||
|
||||
# Get scrambled_ram_addr as int
|
||||
scrambled_ram_addr = int.from_bytes(
|
||||
scrambled_ram_addr_le, byteorder="little", signed=False
|
||||
)
|
||||
|
||||
# In hardware the highest bits are discarded since the memory is only 128K bytes
|
||||
scrambled_ram_addr = scrambled_ram_addr & 0x7FFF
|
||||
|
||||
# Check bit 14 for which pair of ram blocks the data should be stored in
|
||||
if not (scrambled_ram_addr & 0x4000):
|
||||
ram0[scrambled_ram_addr] = (
|
||||
scrambled_word_data_le[0],
|
||||
scrambled_word_data_le[1],
|
||||
)
|
||||
ram1[scrambled_ram_addr] = (
|
||||
scrambled_word_data_le[2],
|
||||
scrambled_word_data_le[3],
|
||||
)
|
||||
else:
|
||||
ram2[scrambled_ram_addr] = (
|
||||
scrambled_word_data_le[0],
|
||||
scrambled_word_data_le[1],
|
||||
)
|
||||
ram3[scrambled_ram_addr] = (
|
||||
scrambled_word_data_le[2],
|
||||
scrambled_word_data_le[3],
|
||||
)
|
||||
|
||||
for line in range(0, rows, 1):
|
||||
spram0.write(f"{ram0[line][1]:02x}")
|
||||
spram0.write(f"{ram0[line][0]:02x}\n")
|
||||
spram1.write(f"{ram1[line][1]:02x}")
|
||||
spram1.write(f"{ram1[line][0]:02x}\n")
|
||||
spram2.write(f"{ram2[line][1]:02x}")
|
||||
spram2.write(f"{ram2[line][0]:02x}\n")
|
||||
spram3.write(f"{ram3[line][1]:02x}")
|
||||
spram3.write(f"{ram3[line][0]:02x}\n")
|
Loading…
Reference in New Issue
Block a user