247 lines
6.7 KiB
Python
247 lines
6.7 KiB
Python
import binascii
|
|
import struct
|
|
|
|
|
|
def str_to_time(t):
|
|
"""
|
|
Converts a given time to seconds.
|
|
Supported textual representations:
|
|
- u -> microseconds
|
|
- m -> milliseconds
|
|
- s -> seconds
|
|
- M -> minutes
|
|
- H -> hours
|
|
Example: 10M is converted to 600 seconds.
|
|
:param t: time in seconds or in textual representation
|
|
"""
|
|
conversions = {'u': 0.000001, 'm': 0.001, 's': 1, 'M': 60, 'H': 3600, 'D': 86400}
|
|
|
|
if isinstance(t, str):
|
|
try:
|
|
if t[-1] not in conversions.keys():
|
|
return float(t)
|
|
|
|
# extract multiplier
|
|
mult = conversions[t[-1]]
|
|
|
|
if mult == 's':
|
|
return str_to_time(t[0:-1])
|
|
|
|
return float(t[0:-1]) * mult
|
|
|
|
except BaseException:
|
|
raise Exception(f"[PhysicalMemoryArray] Invalid value for '{t[-1]}' for t {t}")
|
|
|
|
return float(t)
|
|
|
|
|
|
def check_data(data, bits):
|
|
"""
|
|
Checks if data converted to binary corresponds to the given bits
|
|
:returns: is_match, data_value, bits_value
|
|
Note: data_value and bits_value are None if is_match is True
|
|
"""
|
|
n_bits = len(bits)
|
|
val = to_binary(data, n_bits)
|
|
|
|
# Match
|
|
if val == bits:
|
|
return True, None, None
|
|
|
|
else:
|
|
data_val = data
|
|
bits_val = None
|
|
|
|
if data is None or type(data) is int:
|
|
bits_val = from_binary(bits, int)
|
|
|
|
elif type(data) is float:
|
|
bits_val = from_binary(bits, float)
|
|
|
|
elif type(data) is str:
|
|
if len(data) == 1:
|
|
bits_val = from_binary(bits, float)
|
|
|
|
# Memory pointer
|
|
elif '-0x' in data:
|
|
addr_prefix = f"{data.split('-0x')[0]}-"
|
|
addr_bits = from_binary(bits, int)
|
|
bits_val = f"{addr_prefix}{addr_bits}"
|
|
|
|
# CRC - pointer (function pointer, saved PC)
|
|
else:
|
|
data_val = calc_crc(data, n_bits)
|
|
bits_val = from_binary(bits, int)
|
|
|
|
elif type(data) is dict:
|
|
# saved PC (address)
|
|
if 'function_name' in data and 'instruction_number' in data:
|
|
pc = f"{data['function_name']}-{data['instruction_number']}"
|
|
data_val = calc_crc(pc, n_bits)
|
|
bits_val = from_binary(bits, int)
|
|
|
|
if bits_val is None:
|
|
raise Exception(f"Unsupported data check vs {type(data)}")
|
|
|
|
return False, data_val, bits_val
|
|
|
|
|
|
def from_binary(data, conv_type):
|
|
"""
|
|
Converts data from binary to conv_type
|
|
:param data: data to convert
|
|
:param conv_type: target type of the conversion
|
|
:return: converted data
|
|
"""
|
|
# signed integer
|
|
if conv_type is int:
|
|
# positive
|
|
if data[0] == '0' or len(data) == 1:
|
|
return int(data, 2)
|
|
|
|
# negative
|
|
return int(data[1:], 2) - (2 ** (len(data) - 1))
|
|
|
|
# char
|
|
elif conv_type is str:
|
|
return chr(int(data, 2))
|
|
|
|
# float / double
|
|
elif conv_type is float:
|
|
n_bits = len(data)
|
|
if n_bits != 32 and n_bits != 64:
|
|
raise Exception(f"Binary to floating point conversion of {n_bits} not supported!")
|
|
|
|
# convert to bytes
|
|
data = int(data, 2).to_bytes(n_bits//8, byteorder='big')
|
|
|
|
pack_type = '>f' if n_bits == 32 else '>d'
|
|
return struct.unpack(pack_type, data)[0]
|
|
|
|
# bool
|
|
elif conv_type is bool:
|
|
return data[-1] == '1'
|
|
|
|
|
|
def to_binary(data, n_bits):
|
|
"""
|
|
Converts data to its binary notation, using n_bits
|
|
:param data: data to convert
|
|
:param n_bits: number of bits to use in the representation
|
|
:return: binary data
|
|
"""
|
|
if data is None:
|
|
return ''.zfill(n_bits)
|
|
|
|
elif type(data) is int:
|
|
format_str = '{:0' + str(n_bits) + 'b}'
|
|
# bit mask (used for negative integers)
|
|
mask = int('1' * n_bits, 2)
|
|
val = format_str.format(data & mask)
|
|
# fix bit size
|
|
return val[-n_bits:]
|
|
|
|
elif type(data) is float:
|
|
if n_bits != 32 and n_bits != 64:
|
|
raise Exception(f"Floating point conversion of {n_bits} not supported!")
|
|
|
|
pack_type = '>f' if n_bits == 32 else '>d'
|
|
return ''.join(f"{b:08b}" for b in struct.pack(pack_type, data))
|
|
|
|
elif type(data) is str:
|
|
# char
|
|
if len(data) == 1:
|
|
val = bin(ord(data))[2:].zfill(n_bits)
|
|
# fix bit size for unicode vals
|
|
return val[-n_bits:]
|
|
|
|
# memory pointer (get address)
|
|
elif '-0x' in data:
|
|
addr = f"0x{data.split('-0x')[1]}"
|
|
data = int(addr, 16)
|
|
return to_binary(data, n_bits)
|
|
|
|
# other pointer (function pointer, saved PC)
|
|
else:
|
|
val = calc_crc(data, n_bits)
|
|
# use int implementation
|
|
return to_binary(val, n_bits)
|
|
|
|
elif type(data) is dict:
|
|
# saved PC (address)
|
|
if 'function_name' in data and 'instruction_number' in data:
|
|
pc = f"{data['function_name']}-{data['instruction_number']}"
|
|
# use address implementation
|
|
return to_binary(pc, n_bits)
|
|
|
|
elif type(data) is bool:
|
|
val = '1' if data else '0'
|
|
return val.zfill(n_bits)
|
|
|
|
raise Exception(f"Data type {type(data)} not supported!")
|
|
|
|
|
|
def calc_crc(data, n_bits):
|
|
"""
|
|
Computes the CRC of the data
|
|
:param data: data to convert
|
|
:param n_bits: number of bits for CRC (supported CRC16, CRC32, and CRC64)
|
|
:return: CRC in integer representation
|
|
"""
|
|
crc_version = {8: crc8, 16: crc16, 32: binascii.crc32, 64: crc64}
|
|
|
|
if n_bits in crc_version.keys():
|
|
return crc_version[n_bits](bytes(data, 'utf-8'))
|
|
|
|
raise Exception(f"CRC size of {n_bits} not supported! (input={data})")
|
|
|
|
|
|
def crc8(data, poly=0x07, init=0x00):
|
|
"""
|
|
Compute the CRC-8-ATM checksum.
|
|
"""
|
|
crc = init
|
|
|
|
for byte in data:
|
|
crc ^= byte
|
|
|
|
for _ in range(8):
|
|
if crc & 0x80:
|
|
crc = (crc << 1) ^ poly
|
|
else:
|
|
crc <<= 1
|
|
|
|
crc &= 0xFF # Ensure 8-bit value
|
|
|
|
return crc
|
|
|
|
|
|
def crc16(data, poly=0x1021, init=0x0000):
|
|
"""
|
|
Computes CRC-16-CCITT (XModem) checksum
|
|
"""
|
|
crc = init
|
|
|
|
for byte in data:
|
|
crc ^= (byte << 8)
|
|
|
|
for _ in range(8):
|
|
crc = (crc << 1) ^ poly if (crc & 0x8000) else (crc << 1)
|
|
crc &= 0xFFFF # Keep it 16-bit
|
|
|
|
return crc
|
|
|
|
|
|
def crc64(data, poly=0x000000000000001B, init=0xFFFFFFFFFFFFFFFF):
|
|
"""
|
|
Computes CRC-64-ISO without a lookup table (bitwise).
|
|
"""
|
|
crc = init
|
|
|
|
for byte in data:
|
|
crc ^= byte << 56 # Align byte with the leftmost 8 bits of CRC
|
|
for _ in range(8): # Process each bit
|
|
crc = (crc << 1) ^ poly if (crc & (1 << 63)) else (crc << 1)
|
|
crc &= 0xFFFFFFFFFFFFFFFF # Keep it 64-bit
|
|
|
|
return crc |