mirror of
https://github.com/saymrwulf/pulp-runtime.git
synced 2026-05-14 20:48:09 +00:00
554 lines
18 KiB
Python
Executable file
554 lines
18 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
#
|
|
# Copyright (C) 2018 ETH Zurich, University of Bologna
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
from elftools.elf.elffile import ELFFile
|
|
import os
|
|
import os.path
|
|
import struct
|
|
import argparse
|
|
|
|
|
|
|
|
class stim(object):
|
|
|
|
|
|
def __init__(self, verbose=False):
|
|
self.binaries = []
|
|
self.mem = {}
|
|
self.verbose = verbose
|
|
self.areas = []
|
|
|
|
self.dump('Created stimuli generator')
|
|
|
|
def get_entry(self):
|
|
with open(self.binaries[0], 'rb') as file:
|
|
elffile = ELFFile(file)
|
|
return elffile.header['e_entry']
|
|
|
|
def dump(self, str):
|
|
if self.verbose:
|
|
print (str)
|
|
|
|
def add_binary(self, binary):
|
|
self.dump(' Added binary: %s' % binary)
|
|
self.binaries.append(binary)
|
|
|
|
def add_area(self, start, size):
|
|
self.dump(' Added target area: [0x%x -> 0x%x]' % (start, start + size))
|
|
self.areas.append([start, start+size])
|
|
|
|
|
|
def __add_mem_word(self, base, size, data, width):
|
|
|
|
aligned_base = base & ~(width - 1)
|
|
|
|
shift = base - aligned_base
|
|
iter_size = width - shift
|
|
if iter_size > size:
|
|
iter_size = size
|
|
|
|
value = self.mem.get(str(aligned_base))
|
|
if value is None:
|
|
value = 0
|
|
|
|
value &= ~(((1<<width) - 1) << (shift*8))
|
|
value |= int.from_bytes(data[0:iter_size], byteorder='little') << (shift*8)
|
|
|
|
self.mem[str(aligned_base)] = value
|
|
|
|
return iter_size
|
|
|
|
|
|
|
|
|
|
|
|
def __add_mem(self, base, size, data, width):
|
|
|
|
while size > 0:
|
|
|
|
iter_size = self.__add_mem_word(base, size, data, width)
|
|
|
|
size -= iter_size
|
|
base += iter_size
|
|
data = data[iter_size:]
|
|
|
|
|
|
def __gen_stim_slm(self, filename, width):
|
|
|
|
self.dump(' Generating to file: ' + filename)
|
|
|
|
try:
|
|
os.makedirs(os.path.dirname(filename))
|
|
except:
|
|
pass
|
|
|
|
with open(filename, 'w') as file:
|
|
for key in sorted(self.mem.keys()):
|
|
file.write('%X_%0*X\n' % (int(key), width*2, self.mem.get(key)))
|
|
|
|
def __parse_binaries(self, width):
|
|
|
|
self.mem = {}
|
|
|
|
for binary in self.binaries:
|
|
|
|
with open(binary, 'rb') as file:
|
|
elffile = ELFFile(file)
|
|
|
|
for segment in elffile.iter_segments():
|
|
|
|
if segment['p_type'] == 'PT_LOAD':
|
|
|
|
data = segment.data()
|
|
addr = segment['p_paddr']
|
|
size = len(data)
|
|
|
|
load = True
|
|
if len(self.areas) != 0:
|
|
load = False
|
|
for area in self.areas:
|
|
if addr >= area[0] and addr + size <= area[1]:
|
|
load = True
|
|
break
|
|
|
|
if load:
|
|
|
|
self.dump(' Handling section (base: 0x%x, size: 0x%x)' % (addr, size))
|
|
|
|
self.__add_mem(addr, size, data, width)
|
|
|
|
if segment['p_filesz'] < segment['p_memsz']:
|
|
addr = segment['p_paddr'] + segment['p_filesz']
|
|
size = segment['p_memsz'] - segment['p_filesz']
|
|
self.dump(' Init section to 0 (base: 0x%x, size: 0x%x)' % (addr, size))
|
|
self.__add_mem(addr, size, [0] * size, width)
|
|
|
|
else:
|
|
|
|
self.dump(' Bypassing section (base: 0x%x, size: 0x%x)' % (addr, size))
|
|
|
|
|
|
|
|
|
|
def gen_stim_slm_64(self, stim_file):
|
|
|
|
self.__parse_binaries(8)
|
|
|
|
self.__gen_stim_slm(stim_file, 8)
|
|
|
|
|
|
def gen_stim_bin(self, stim_file):
|
|
|
|
self.__parse_binaries(1)
|
|
|
|
try:
|
|
os.makedirs(os.path.dirname(stim_file))
|
|
except:
|
|
pass
|
|
|
|
with open(stim_file, 'wb') as file:
|
|
prev_addr = None
|
|
for key in sorted(self.mem.keys()):
|
|
addr = int(key)
|
|
if prev_addr is not None:
|
|
while prev_addr != addr - 1:
|
|
file.write(struct.pack('B', 0))
|
|
prev_addr += 1
|
|
|
|
prev_addr = addr
|
|
file.write(struct.pack('B', int(self.mem.get(key))))
|
|
|
|
|
|
|
|
class Efuse(object):
|
|
|
|
def __init__(self, config, verbose=False):
|
|
self.config = config
|
|
self.verbose = verbose
|
|
|
|
self.dump('Created efuse stimuli generator')
|
|
|
|
|
|
def dump(self, str):
|
|
if self.verbose:
|
|
print (str)
|
|
|
|
def gen_stim_txt(self, filename):
|
|
|
|
|
|
user_efuses = {}
|
|
|
|
efuses = self.config.get('**/efuse/values')
|
|
if efuses is None:
|
|
efuses = []
|
|
else:
|
|
efuses = efuses.get_dict()
|
|
for efuse in efuses:
|
|
efuse_id, val = efuse.split(':')
|
|
efuse_id = int(efuse_id, 0)
|
|
val = int(val, 0)
|
|
user_efuses[efuse_id] = val
|
|
|
|
nb_regs = self.config.get_child_int('**/efuse/nb_regs')
|
|
|
|
pulp_chip = self.config.get_child_str('**/chip/name')
|
|
|
|
pulp_chip_family = self.config.get_child_str('**/chip/pulp_chip_family')
|
|
|
|
if pulp_chip_family == 'gap' or pulp_chip == 'vega' or pulp_chip == 'gap9':
|
|
|
|
load_mode = self.config.get_child_str('**/runner/boot-mode')
|
|
encrypted = self.config.get_child_str('**/efuse/encrypted')
|
|
aes_key = self.config.get_child_str('**/efuse/aes_key')
|
|
aes_iv = self.config.get_child_str('**/efuse/aes_iv')
|
|
xtal_check = self.config.get_child_bool('**/efuse/xtal_check')
|
|
xtal_check_delta = self.config.get_child_bool('**/efuse/xtal_check_delta')
|
|
xtal_check_min = self.config.get_child_bool('**/efuse/xtal_check_min')
|
|
xtal_check_max = self.config.get_child_bool('**/efuse/xtal_check_max')
|
|
no_preload = self.config.get_child_str('**/efuse/no-preload')
|
|
|
|
# In case we boot with the classic rom mode, don't init any efuse, the boot loader will boot with the default mode
|
|
load_mode_hex = None
|
|
|
|
if pulp_chip == 'gap':
|
|
|
|
if load_mode == 'rom':
|
|
load_mode_hex = 0x3A
|
|
elif load_mode == 'spi':
|
|
load_mode_hex = 0x0A
|
|
elif load_mode == 'jtag':
|
|
load_mode_hex = 0x12
|
|
elif load_mode == 'rom_hyper':
|
|
load_mode_hex = 0x2A
|
|
elif load_mode == 'rom_spim_single':
|
|
load_mode_hex = 0x32
|
|
elif load_mode == 'rom_spim':
|
|
load_mode_hex = 0x3A
|
|
elif load_mode == 'jtag_dev' or load_mode == 'spi_dev':
|
|
load_mode_hex = None
|
|
|
|
if xtal_check:
|
|
if load_mode_hex == None: load_mode_hex = 0
|
|
load_mode_hex |= 1<<7
|
|
delta = int(xtal_check_delta*((1 << 15)-1))
|
|
efuses.append('26:0x%x' % (delta & 0xff))
|
|
efuses.append('27:0x%x' % ((delta >> 8) & 0xff))
|
|
efuses.append('28:0x%x' % (xtal_check_min))
|
|
efuses.append('29:0x%x' % (xtal_check_max))
|
|
|
|
if load_mode_hex != None:
|
|
if encrypted:
|
|
load_mode_hex |= 0x40
|
|
for i in range(0, 16):
|
|
efuses.append('%d:0x%s' % (2+i, aes_key[30-i*2:32-i*2]))
|
|
for i in range(0, 8):
|
|
efuses.append('%d:0x%s' % (18+i, aes_iv[14-i*2:16-i*2]))
|
|
|
|
efuses.append('0:%s' % load_mode_hex)
|
|
|
|
elif pulp_chip == 'vega' or pulp_chip == 'gap9':
|
|
efuses = [0] * 128
|
|
info2 = 0
|
|
info3 = 0
|
|
info4 = 0
|
|
info5 = 0
|
|
info6 = 0
|
|
|
|
clk_div = self.config.get_child_int('**/efuse/clkdiv')
|
|
fll_freq = self.config.get_child_int('**/efuse/fll/freq')
|
|
fll_assert_cycles = self.config.get_child_int('**/efuse/fll/assert_cycles')
|
|
fll_lock_tolerance = self.config.get_child_int('**/efuse/fll/lock_tolerance')
|
|
hyper_delay = self.config.get_child_int('**/efuse/hyper/delay')
|
|
hyper_latency = self.config.get_child_int('**/efuse/hyper/latency')
|
|
|
|
if load_mode == 'rom':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
elif load_mode == 'rom_hyper':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# Hyperflash type
|
|
info3 = (1 << 0)
|
|
elif load_mode == 'rom_spim':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# SPI flash type
|
|
info3 = (0 << 0)
|
|
elif load_mode == 'rom_mram':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# MRAM type
|
|
info3 = (2 << 0)
|
|
# Activate MRAM TRIM CFG and fill it with dummy numbers until we get the real one. Also activate clock divider
|
|
info6 |= (1 << 6) | (1<<7)
|
|
info2 |= (2 << 3)
|
|
efuses[56] = 32*4
|
|
for i in range(0, 32):
|
|
efuses [57+i] = i | ((i*4+1)<<8) | ((i*4+2)<<16) | ((i*4+3)<<24)
|
|
|
|
if clk_div is not None:
|
|
info6 |= 1 << 7
|
|
info2 = (info2 & ~(3<<3)) | (clk_div << 3)
|
|
|
|
|
|
if fll_freq is not None:
|
|
info2 |= (1 << 0) | (1 << 2)
|
|
efuses[31] = fll_freq
|
|
|
|
if fll_lock_tolerance is not None or fll_assert_cycles is not None:
|
|
info2 |= (1<< 1)
|
|
efuses[32] = fll_lock_tolerance
|
|
efuses[33] = fll_assert_cycles
|
|
|
|
if hyper_delay is not None:
|
|
info5 |= (1<<6)
|
|
efuses[30] = hyper_delay
|
|
|
|
if hyper_latency is not None:
|
|
info5 |= (1<<7)
|
|
efuses[51] = hyper_latency
|
|
|
|
|
|
|
|
if load_mode_hex != None:
|
|
if encrypted:
|
|
load_mode_hex |= 0x40
|
|
info6 |= 1<<4
|
|
for i in range(0, 16):
|
|
efuses[2+i] = aes_key[30-i*2:32-i*2]
|
|
for i in range(0, 8):
|
|
efuses[18+i] = aes_iv[14-i*2:16-i*2]
|
|
|
|
efuses[0] = load_mode_hex
|
|
|
|
efuses[1] = info2
|
|
efuses[37] = info3
|
|
efuses[38] = info4
|
|
efuses[39] = info5
|
|
efuses[40] = info6
|
|
elif pulp_chip == 'gap_rev1':
|
|
info3 = 0
|
|
info6 = 0
|
|
if load_mode == 'rom':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
elif load_mode == 'rom_hyper':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# Hyperflash type
|
|
info3 = (1 << 0)
|
|
elif load_mode == 'rom_spim':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# SPI flash type
|
|
info3 = (0 << 0)
|
|
|
|
if xtal_check:
|
|
if load_mode_hex == None: load_mode_hex = 0
|
|
load_mode_hex |= 1<<7
|
|
delta = int(xtal_check_delta*((1 << 15)-1))
|
|
efuses.append('26:0x%x' % (delta & 0xff))
|
|
efuses.append('27:0x%x' % ((delta >> 8) & 0xff))
|
|
efuses.append('28:0x%x' % (xtal_check_min))
|
|
efuses.append('29:0x%x' % (xtal_check_max))
|
|
|
|
if load_mode_hex != None:
|
|
if encrypted:
|
|
load_mode_hex |= 0x40
|
|
info6 |= 1<<4
|
|
for i in range(0, 16):
|
|
efuses.append('%d:0x%s' % (2+i, aes_key[30-i*2:32-i*2]))
|
|
for i in range(0, 8):
|
|
efuses.append('%d:0x%s' % (18+i, aes_iv[14-i*2:16-i*2]))
|
|
|
|
efuses.append('0:%s' % load_mode_hex)
|
|
|
|
efuses.append('1:%s' % 0)
|
|
efuses.append('37:%s' % (info3))
|
|
efuses.append('38:%s' % 0)
|
|
efuses.append('39:%s' % 0)
|
|
efuses.append('40:%s' % (info6))
|
|
|
|
elif pulp_chip == 'gap8_revc':
|
|
|
|
fll_freq = self.config.get_child_int('**/efuse/fll/freq')
|
|
ref_clk_wait = self.config.get_child_int('**/efuse/ref_clk_wait')
|
|
burst_size = self.config.get_child_int('**/efuse/burst_size')
|
|
flash_id = self.config.get_child_bool('**/efuse/flash_id')
|
|
fll_assert_cycles = self.config.get_child_int('**/efuse/fll/assert_cycles')
|
|
fll_lock_tolerance = self.config.get_child_int('**/efuse/fll/lock_tolerance')
|
|
hyper_delay = self.config.get_child_int('**/efuse/hyper/delay')
|
|
hyper_latency = self.config.get_child_int('**/efuse/hyper/latency')
|
|
|
|
if hyper_delay is None:
|
|
hyper_delay = 3
|
|
|
|
efuses = [0] * 128
|
|
info3 = 0
|
|
info2 = 0
|
|
info6 = 0
|
|
info5 = 0
|
|
|
|
if self.config.get_child_str('**/vsim/model') == 'rtl':
|
|
info7 = 1 # Don't use UDMA MEMCPY as it makes RTL platform crash
|
|
else:
|
|
info7 = 0
|
|
if load_mode == 'rom':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
elif load_mode == 'rom_hyper':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# Hyperflash type
|
|
info3 = (1 << 0)
|
|
info7 |= (1 << 2) # Partially reconfigure pads to overcome HW issue with rwds cg latch
|
|
elif load_mode == 'rom_spim':
|
|
# RTL platform | flash boot | no encryption | no wait xtal
|
|
load_mode_hex = 2 | (2 << 3) | (0 << 4) | (0 << 5) | (0 << 6) | (0 << 7)
|
|
# SPI flash type
|
|
info3 = (0 << 0)
|
|
|
|
if burst_size is not None:
|
|
info6 |= (1 << 7)
|
|
efuses[61] = burst_size & 0xff
|
|
efuses[62] = (burst_size >> 8) & 0xff
|
|
|
|
if flash_id:
|
|
info6 |= (1 << 5)
|
|
|
|
if fll_freq is not None:
|
|
info2 |= (1 << 0)
|
|
efuses[57] = fll_freq
|
|
|
|
if ref_clk_wait is not None:
|
|
info2 |= (1 << 6)
|
|
efuses[35] = ref_clk_wait & 0xff
|
|
efuses[36] = (ref_clk_wait >> 8) & 0xff
|
|
else:
|
|
info2 |= (1 << 6)
|
|
efuses[35] = 0
|
|
efuses[36] = 0
|
|
|
|
if hyper_delay is not None:
|
|
info5 |= (1<<6)
|
|
efuses[32] |= hyper_delay
|
|
|
|
if hyper_latency is not None:
|
|
info5 |= (1<<7)
|
|
efuses[51] |= hyper_latency
|
|
|
|
|
|
if fll_lock_tolerance is not None or fll_assert_cycles is not None:
|
|
info2 |= (1<< 1)
|
|
efuses[58] = fll_lock_tolerance
|
|
efuses[59] = fll_assert_cycles
|
|
|
|
if xtal_check:
|
|
if load_mode_hex == None: load_mode_hex = 0
|
|
load_mode_hex |= 1<<7
|
|
delta = int(xtal_check_delta*((1 << 15)-1))
|
|
efuses[26] = delta & 0xff
|
|
efuses[27] = (delta >> 8) & 0xff
|
|
efuses[28] = xtal_check_min & 0xff
|
|
efuses[29] = (xtal_check_min >> 8) & 0xff
|
|
efuses[30] |= xtal_check_max & 0xff
|
|
efuses[31] = (xtal_check_max >> 8) & 0xff
|
|
|
|
if load_mode_hex != None:
|
|
if encrypted:
|
|
load_mode_hex |= 0x40
|
|
info6 |= 1<<4
|
|
for i in range(0, 16):
|
|
efuses[2+i] = int('0x%s' % aes_key[30-i*2:32-i*2], 0)
|
|
for i in range(0, 8):
|
|
efuses[18+i] = int('0x%s' % aes_iv[14-i*2:16-i*2], 0)
|
|
|
|
efuses[0] = load_mode_hex
|
|
|
|
efuses[1] = info2
|
|
efuses[37] = info3
|
|
efuses[38] = 0
|
|
efuses[39] = info5
|
|
efuses[40] = info6
|
|
efuses[60] = info7
|
|
|
|
|
|
# Efuse preloading file generation
|
|
if pulp_chip == 'vega' or pulp_chip == 'gap9':
|
|
|
|
self.dump(' Generating to file: ' + filename)
|
|
|
|
with open(filename, 'w') as file:
|
|
if no_preload is None or no_preload == False:
|
|
for efuseId in range (0, 128):
|
|
value = efuses[efuseId]
|
|
self.dump(' Writing register (index: %d, value: 0x%x)' % (efuseId, value))
|
|
file.write('{0:032b}\n'.format(value))
|
|
|
|
elif pulp_chip == 'gap8_revc':
|
|
|
|
values = [0] * nb_regs * 8
|
|
for efuseId in range (0, nb_regs):
|
|
value = user_efuses.get(efuseId)
|
|
if value is None:
|
|
value = efuses[efuseId]
|
|
self.dump(' Writing register (index: %d, value: 0x%x)' % (efuseId, value))
|
|
for index in range(0, 8):
|
|
if (value >> index) & 1 == 1: values[efuseId + index*128] = 1
|
|
|
|
self.dump(' Generating to file: ' + filename)
|
|
|
|
with open(filename, 'w') as file:
|
|
for value in values:
|
|
file.write('%d ' % (value))
|
|
|
|
else:
|
|
|
|
values = [0] * nb_regs * 8
|
|
for efuse in efuses:
|
|
efuseId, value = efuse.split(':')
|
|
self.dump(' Writing register (index: %d, value: 0x%x)' % (int(efuseId, 0), int(value, 0)))
|
|
efuseId = int(efuseId, 0)
|
|
value = int(value, 0)
|
|
for index in range(0, 8):
|
|
if (value >> index) & 1 == 1: values[efuseId + index*128] = 1
|
|
|
|
self.dump(' Generating to file: ' + filename)
|
|
|
|
with open(filename, 'w') as file:
|
|
for value in values:
|
|
file.write('%d ' % (value))
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description='Generate stimuli')
|
|
|
|
parser.add_argument("--binary", dest="binary", default=None, help="Specify input binary")
|
|
parser.add_argument("--vectors", dest="vectors", default=None, help="Specify output vectors file")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.binary is None:
|
|
raise Exception('Specify the input binary with --binary=<path>')
|
|
|
|
if args.vectors is not None:
|
|
|
|
stim_gen = stim(verbose=True)
|
|
|
|
stim_gen.add_binary(args.binary)
|
|
|
|
stim_gen.gen_stim_slm_64(args.vectors)
|