253 lines
8.2 KiB
Python
Executable File
253 lines
8.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2020 Nuvoton Technology Corporation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# This file contains general functions for ECST application
|
|
|
|
import sys
|
|
import argparse
|
|
import colorama
|
|
from colorama import Fore
|
|
|
|
INVALID_INPUT = -1
|
|
EXIT_FAILURE_STATUS = 1
|
|
|
|
# Header common fields
|
|
FW_HDR_CRC_DISABLE = 0x00
|
|
FW_HDR_CRC_ENABLE = 0x02
|
|
FW_CRC_DISABLE = 0x00
|
|
FW_CRC_ENABLE = 0x02
|
|
|
|
SPI_CLOCK_RATIO_1 = 0x00
|
|
SPI_CLOCK_RATIO_2 = 0x08
|
|
|
|
SPI_UNLIMITED_BURST_DISABLE = 0x00
|
|
SPI_UNLIMITED_BURST_ENABLE = 0x08
|
|
|
|
# Verbose related values
|
|
NO_VERBOSE = 0
|
|
REG_VERBOSE = 1
|
|
SUPER_VERBOSE = 1
|
|
|
|
# argument default values.
|
|
DEFAULT_MODE = "bt"
|
|
SPI_MAX_CLOCK_DEFAULT = "20"
|
|
FLASH_SIZE_DEFAULT = "16"
|
|
SPI_CLOCK_RATIO_DEFAULT = 1
|
|
PASTE_FIRMWARE_HEADER_DEFAULT = 0x00000000
|
|
DEFAULT_VERBOSE = NO_VERBOSE
|
|
SPI_MODE_VAL_DEFAULT = 'normal'
|
|
SPI_UNLIMITED_BURST_DEFAULT = SPI_UNLIMITED_BURST_DISABLE
|
|
FW_HDR_CRC_DEFAULT = FW_HDR_CRC_ENABLE
|
|
FW_CRC_DEFAULT = FW_CRC_ENABLE
|
|
FW_CRC_START_OFFSET_DEFAULT = 0x0
|
|
POINTER_OFFSET_DEFAULT = 0x0
|
|
|
|
# Chips: convert from name to index.
|
|
CHIPS_INFO = {
|
|
'npcx7m5': {'ram_address': 0x100a8000, 'ram_size': 0x20000},
|
|
'npcx7m6': {'ram_address': 0x10090000, 'ram_size': 0x40000},
|
|
'npcx7m7': {'ram_address': 0x10070000, 'ram_size': 0x60000},
|
|
'npcx9m3': {'ram_address': 0x10080000, 'ram_size': 0x50000},
|
|
'npcx9m6': {'ram_address': 0x10090000, 'ram_size': 0x40000},
|
|
'npcx9m7': {'ram_address': 0x10070000, 'ram_size': 0x60000},
|
|
'npcx9mfp': {'ram_address': 0x10058000, 'ram_size': 0x80000},
|
|
'npcx4m3': {'ram_address': 0x10088000, 'ram_size': 0x50000},
|
|
'npcx4m8': {'ram_address': 0x10060000, 'ram_size': 0x7c800},
|
|
}
|
|
DEFAULT_CHIP = 'npcx7m6'
|
|
|
|
# RAM related values
|
|
RAM_ADDR = 0x00
|
|
RAM_SIZE = 0x01
|
|
|
|
class EcstArgs:
|
|
"""creates an arguments object for the ECST,
|
|
the arguments are taken from the command line and/or
|
|
argument file
|
|
"""
|
|
error_args = None
|
|
|
|
mode = DEFAULT_MODE
|
|
help = False
|
|
verbose = DEFAULT_VERBOSE
|
|
super_verbose = False
|
|
input = None
|
|
output = None
|
|
args_file = None
|
|
chip_name = DEFAULT_CHIP
|
|
chip_ram_address = CHIPS_INFO[DEFAULT_CHIP]['ram_address']
|
|
chip_ram_size = CHIPS_INFO[DEFAULT_CHIP]['ram_address']
|
|
firmware_header_crc = FW_HDR_CRC_DEFAULT
|
|
firmware_crc = FW_CRC_DEFAULT
|
|
spi_flash_maximum_clock = SPI_MAX_CLOCK_DEFAULT
|
|
spi_flash_clock_ratio = SPI_CLOCK_RATIO_DEFAULT
|
|
unlimited_burst_mode = SPI_UNLIMITED_BURST_DEFAULT
|
|
spi_flash_read_mode = SPI_MODE_VAL_DEFAULT
|
|
firmware_load_address = None
|
|
firmware_entry_point = None
|
|
use_arm_reset = True
|
|
firmware_crc_start = FW_CRC_START_OFFSET_DEFAULT
|
|
firmware_crc_size = None
|
|
firmware_length = None
|
|
flash_size = FLASH_SIZE_DEFAULT
|
|
paste_firmware_header = PASTE_FIRMWARE_HEADER_DEFAULT
|
|
pointer = POINTER_OFFSET_DEFAULT
|
|
bh_offset = None
|
|
|
|
def __init__(self):
|
|
|
|
arguments = _create_parser("")
|
|
valid_arguments = arguments[0]
|
|
invalid_arguments = arguments[1]
|
|
self.error_args = invalid_arguments
|
|
|
|
_populate_args(self, valid_arguments)
|
|
_populate_chip_fields(self)
|
|
|
|
def _populate_chip_fields(self):
|
|
"""populate the chip related fields for the ecst"""
|
|
self.chip_name = self.chip_name
|
|
chip = str(self.chip_name).lower()
|
|
|
|
if chip not in CHIPS_INFO:
|
|
self.chip_name = INVALID_INPUT
|
|
return
|
|
|
|
self.chip_ram_address = CHIPS_INFO[chip]['ram_address']
|
|
self.chip_ram_size = CHIPS_INFO[chip]['ram_size']
|
|
if self.firmware_load_address is None:
|
|
self.firmware_load_address = self.chip_ram_address
|
|
|
|
def _populate_args(self, argument_list):
|
|
"""populate the ecst arguments according to the command line/ args file"""
|
|
for arg in vars(argument_list):
|
|
if (arg == "input") & (argument_list.input is not None):
|
|
self.input = argument_list.input
|
|
|
|
elif (arg == "output") & (argument_list.output is not None):
|
|
self.output = argument_list.output
|
|
|
|
elif (arg == "chip") & (argument_list.chip is not None):
|
|
self.chip_name = argument_list.chip
|
|
_populate_chip_fields(self)
|
|
|
|
elif (arg == "verbose") & argument_list.verbose:
|
|
self.verbose = REG_VERBOSE
|
|
|
|
elif (arg == "super_verbose") & argument_list.super_verbose:
|
|
self.verbose = SUPER_VERBOSE
|
|
|
|
elif (arg == "spi_flash_maximum_clock") & \
|
|
(argument_list.spi_flash_maximum_clock is not None):
|
|
self.spi_flash_maximum_clock =\
|
|
argument_list.spi_flash_maximum_clock
|
|
|
|
elif (arg == "spi_flash_clock_ratio") & \
|
|
(argument_list.spi_flash_clock_ratio is not None):
|
|
if argument_list.spi_flash_clock_ratio.isdigit():
|
|
self.spi_flash_clock_ratio =\
|
|
int(argument_list.spi_flash_clock_ratio)
|
|
else:
|
|
self.spi_flash_clock_ratio = INVALID_INPUT
|
|
|
|
elif (arg == "firmware_header_crc") &\
|
|
argument_list.firmware_header_crc:
|
|
self.firmware_header_crc = FW_HDR_CRC_DISABLE
|
|
|
|
elif (arg == "firmware_crc") & argument_list.firmware_crc:
|
|
self.firmware_crc = FW_CRC_DISABLE
|
|
|
|
elif (arg == "spi_read_mode") &\
|
|
(argument_list.spi_read_mode is not None):
|
|
|
|
self.spi_flash_read_mode = argument_list.spi_read_mode
|
|
|
|
elif (arg == "flash_size") & (argument_list.flash_size is not None):
|
|
self.flash_size = argument_list.flash_size
|
|
|
|
elif (arg == "paste_firmware_header") & \
|
|
(argument_list.paste_firmware_header is not None):
|
|
if _is_hex(argument_list.paste_firmware_header):
|
|
self.paste_firmware_header =\
|
|
int(argument_list.paste_firmware_header, 16)
|
|
else:
|
|
self.paste_firmware_header = INVALID_INPUT
|
|
|
|
def _create_parser(arg_list):
|
|
"""create argument parser according to pre-defined arguments
|
|
|
|
:param arg_list: when empty, parses command line arguments,
|
|
else parses the given string
|
|
"""
|
|
|
|
parser = argparse.ArgumentParser(conflict_handler='resolve', allow_abbrev=False)
|
|
parser.add_argument("-i", nargs='?', dest="input")
|
|
parser.add_argument("-o", nargs='?', dest="output")
|
|
parser.add_argument("-chip", dest="chip")
|
|
parser.add_argument("-v", action="store_true", dest="verbose")
|
|
parser.add_argument("-vv", action="store_true", dest="super_verbose")
|
|
parser.add_argument("-nohcrc", action="store_true",
|
|
dest="firmware_header_crc")
|
|
parser.add_argument("-nofcrc", action="store_true", dest="firmware_crc")
|
|
parser.add_argument("-spimaxclk", nargs='?',
|
|
dest="spi_flash_maximum_clock")
|
|
parser.add_argument("-spiclkratio", nargs='?',
|
|
dest="spi_flash_clock_ratio")
|
|
parser.add_argument("-spireadmode", nargs='?', dest="spi_read_mode")
|
|
parser.add_argument("-flashsize", nargs='?', dest="flash_size")
|
|
parser.add_argument("-ph", nargs='?', dest="paste_firmware_header")
|
|
|
|
args = parser.parse_known_args(arg_list.split())
|
|
|
|
if arg_list == "":
|
|
args = parser.parse_known_args()
|
|
|
|
return args
|
|
|
|
def _file_to_line(arg_file):
|
|
"""helper to convert a text file to one line string
|
|
used to parse the arguments in a given argfile
|
|
|
|
:param arg_file: the file to manipulate
|
|
"""
|
|
with open(arg_file, "r") as arg_file_to_read:
|
|
data = arg_file_to_read.read().strip()
|
|
arg_file_to_read.close()
|
|
|
|
return data
|
|
|
|
def _is_hex(val):
|
|
"""helper to determine whether an input is a hex
|
|
formatted number
|
|
|
|
:param val: input to be checked
|
|
"""
|
|
if val.startswith("0x") or val.startswith("0X"):
|
|
val = val[2:]
|
|
hex_digits = set("0123456789abcdefABCDEF")
|
|
for char in val:
|
|
if char not in hex_digits:
|
|
return False
|
|
return True
|
|
|
|
def exit_with_failure(message):
|
|
"""formatted failure message printer, prints the
|
|
relevant error message and exits the application.
|
|
|
|
:param message: the error message to be printed
|
|
"""
|
|
|
|
message = '\n' + message
|
|
message += '\n'
|
|
message += '******************************\n'
|
|
message += '*** FAILED ***\n'
|
|
message += '******************************\n'
|
|
print(Fore.RED + message)
|
|
|
|
sys.exit(EXIT_FAILURE_STATUS)
|
|
|
|
colorama.init()
|