blob: c596760e3405f7677998e2493f3e3bb5f8184dcc [file] [log] [blame]
#!/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},
}
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')
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()