diff --git a/debug/PyCortexMDebug/scripts/gdb.py b/debug/PyCortexMDebug/PyCortexMDebug.py
similarity index 83%
rename from debug/PyCortexMDebug/scripts/gdb.py
rename to debug/PyCortexMDebug/PyCortexMDebug.py
index ca38822a..6533535c 100644
--- a/debug/PyCortexMDebug/scripts/gdb.py
+++ b/debug/PyCortexMDebug/PyCortexMDebug.py
@@ -18,6 +18,14 @@ You should have received a copy of the GNU General Public License
along with PyCortexMDebug. If not, see .
"""
+from os import path
+import sys
+
+directory, file = path.split(__file__)
+directory = path.expanduser(directory)
+directory = path.abspath(directory)
+
+sys.path.append(directory)
from cmdebug.svd_gdb import LoadSVD
from cmdebug.dwt_gdb import DWT
diff --git a/debug/PyCortexMDebug/cmdebug/__init__.py b/debug/PyCortexMDebug/cmdebug/__init__.py
old mode 100644
new mode 100755
diff --git a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py b/debug/PyCortexMDebug/cmdebug/dwt_gdb.py
old mode 100644
new mode 100755
index 9afa21e3..dd7ccd20
--- a/debug/PyCortexMDebug/cmdebug/dwt_gdb.py
+++ b/debug/PyCortexMDebug/cmdebug/dwt_gdb.py
@@ -38,12 +38,14 @@ class DWT(gdb.Command):
def __init__(self):
gdb.Command.__init__(self, "dwt", gdb.COMMAND_DATA)
- def read(self, address, bits=32):
+ @staticmethod
+ def read(address, bits=32):
"""Read from memory (using print) and return an integer"""
value = gdb.selected_inferior().read_memory(address, bits / 8)
return struct.unpack_from(".
"""
-
import lxml.objectify as objectify
import sys
-from copy import deepcopy
from collections import OrderedDict
import os
+import pickle
import traceback
+import re
+import warnings
+
+
+class SmartDict:
+ """
+ Dictionary for search by case-insensitive lookup and/or prefix lookup
+ """
+
+ def __init__(self):
+ self.od = OrderedDict()
+ self.casemap = {}
+
+ def __getitem__(self, key):
+ if key in self.od:
+ return self.od[key]
+
+ if key.lower() in self.casemap:
+ return self.od[self.casemap[key.lower()]]
+
+ return self.od[self.prefix_match(key)]
+
+ def is_ambiguous(self, key):
+ return (
+ key not in self.od
+ and key not in self.casemap
+ and len(list(self.prefix_match_iter(key))) > 1
+ )
+
+ def prefix_match_iter(self, key):
+ name, number = re.match(r"^(.*?)([0-9]*)$", key.lower()).groups()
+ for entry, od_key in self.casemap.items():
+ if entry.startswith(name) and entry.endswith(number):
+ yield od_key
+
+ def prefix_match(self, key):
+ for od_key in self.prefix_match_iter(key):
+ return od_key
+ return None
+
+ def __setitem__(self, key, value):
+ if key in self.od:
+ warnings.warn("Duplicate entry %s", key)
+ elif key.lower() in self.casemap:
+ warnings.warn(
+ "Entry %s differs from duplicate %s only in cAsE",
+ key,
+ self.casemap[key.lower()],
+ )
+
+ self.casemap[key.lower()] = key
+ self.od[key] = value
+
+ def __delitem__(self, key):
+ if (
+ self.casemap[key.lower()] == key
+ ): # Check that we did not overwrite this entry
+ del self.casemap[key.lower()]
+ del self.od[key]
+
+ def __contains__(self, key):
+ return key in self.od or key.lower() in self.casemap or self.prefix_match(key)
+
+ def __iter__(self):
+ return iter(self.od)
+
+ def __len__(self):
+ return len(self.od)
+
+ def items(self):
+ return self.od.items()
+
+ def keys(self):
+ return self.od.keys()
+
+ def values(self):
+ return self.od.values()
+
+ def __str__(self):
+ return str(self.od)
class SVDNonFatalError(Exception):
@@ -40,29 +120,52 @@ class SVDNonFatalError(Exception):
class SVDFile:
+ """
+ A parsed SVD file
+ """
+
def __init__(self, fname):
+ """
+
+ Args:
+ fname: Filename for the SVD file
+ """
f = objectify.parse(os.path.expanduser(fname))
root = f.getroot()
periph = root.peripherals.getchildren()
- self.peripherals = OrderedDict()
+ self.peripherals = SmartDict()
+ self.base_address = 0
+
# XML elements
for p in periph:
try:
- self.peripherals[str(p.name)] = SVDPeripheral(p, self)
+ if p.tag == "peripheral":
+ self.peripherals[str(p.name)] = SVDPeripheral(p, self)
+ else:
+ # This is some other tag
+ pass
except SVDNonFatalError as e:
print(e)
def add_register(parent, node):
+ """
+ Add a register node to a peripheral
+
+ Args:
+ parent: Parent SVDPeripheral object
+ node: XML file node fot of the register
+ """
+
if hasattr(node, "dim"):
dim = int(str(node.dim), 0)
# dimension is not used, number of split indexes should be same
incr = int(str(node.dimIncrement), 0)
default_dim_index = ",".join((str(i) for i in range(dim)))
dim_index = str(getattr(node, "dimIndex", default_dim_index))
- indexes = dim_index.split(",")
+ indices = dim_index.split(",")
offset = 0
- for i in indexes:
+ for i in indices:
name = str(node.name) % i
reg = SVDPeripheralRegister(node, parent)
reg.name = name
@@ -71,21 +174,30 @@ def add_register(parent, node):
offset += incr
else:
try:
- parent.registers[str(node.name)] = SVDPeripheralRegister(node, parent)
- except:
- pass
+ reg = SVDPeripheralRegister(node, parent)
+ name = str(node.name)
+ if name not in parent.registers:
+ parent.registers[name] = reg
+ else:
+ if hasattr(node, "alternateGroup"):
+ print("Register %s has an alternate group", name)
+ except SVDNonFatalError as e:
+ print(e)
def add_cluster(parent, node):
+ """
+ Add a register cluster to a peripheral
+ """
if hasattr(node, "dim"):
dim = int(str(node.dim), 0)
- # dimension is not used, number of split indexes should be same
+ # dimension is not used, number of split indices should be same
incr = int(str(node.dimIncrement), 0)
default_dim_index = ",".join((str(i) for i in range(dim)))
dim_index = str(getattr(node, "dimIndex", default_dim_index))
- indexes = dim_index.split(",")
+ indices = dim_index.split(",")
offset = 0
- for i in indexes:
+ for i in indices:
name = str(node.name) % i
cluster = SVDRegisterCluster(node, parent)
cluster.name = name
@@ -101,37 +213,58 @@ def add_cluster(parent, node):
class SVDRegisterCluster:
+ """
+ Register cluster
+ """
+
def __init__(self, svd_elem, parent):
- self.parent = parent
+ """
+
+ Args:
+ svd_elem: XML element for the register cluster
+ parent: Parent SVDPeripheral object
+ """
+ self.parent_base_address = parent.base_address
+ self.parent_name = parent.name
self.address_offset = int(str(svd_elem.addressOffset), 0)
- self.base_address = self.address_offset + parent.base_address
+ self.base_address = self.address_offset + self.parent_base_address
# This doesn't inherit registers from anything
children = svd_elem.getchildren()
self.description = str(svd_elem.description)
self.name = str(svd_elem.name)
- self.registers = OrderedDict()
- self.clusters = OrderedDict()
+ self.registers = SmartDict()
+ self.clusters = SmartDict()
for r in children:
if r.tag == "register":
add_register(self, r)
def refactor_parent(self, parent):
- self.parent = parent
- self.base_address = parent.base_address + self.address_offset
- try:
- values = self.registers.itervalues()
- except AttributeError:
- values = self.registers.values()
+ self.parent_base_address = parent.base_address
+ self.parent_name = parent.name
+ self.base_address = self.parent_base_address + self.address_offset
+ values = self.registers.values()
for r in values:
r.refactor_parent(self)
- def __unicode__(self):
+ def __str__(self):
return str(self.name)
class SVDPeripheral:
+ """
+ This is a peripheral as defined in the SVD file
+ """
+
def __init__(self, svd_elem, parent):
- self.parent = parent
+ """
+
+ Args:
+ svd_elem: XML element for the peripheral
+ parent: Parent SVDFile object
+ """
+ self.parent_base_address = parent.base_address
+
+ # Look for a base address, as it is required
if not hasattr(svd_elem, "baseAddress"):
raise SVDNonFatalError("Periph without base address")
self.base_address = int(str(svd_elem.baseAddress), 0)
@@ -139,78 +272,83 @@ class SVDPeripheral:
derived_from = svd_elem.attrib["derivedFrom"]
try:
self.name = str(svd_elem.name)
- except:
+ except AttributeError:
self.name = parent.peripherals[derived_from].name
try:
self.description = str(svd_elem.description)
- except:
+ except AttributeError:
self.description = parent.peripherals[derived_from].description
- self.registers = deepcopy(parent.peripherals[derived_from].registers)
- self.clusters = deepcopy(parent.peripherals[derived_from].clusters)
+
+ # pickle is faster than deepcopy by up to 50% on svd files with a
+ # lot of derivedFrom definitions
+ def copier(a):
+ return pickle.loads(pickle.dumps(a))
+
+ self.registers = copier(parent.peripherals[derived_from].registers)
+ self.clusters = copier(parent.peripherals[derived_from].clusters)
self.refactor_parent(parent)
else:
# This doesn't inherit registers from anything
- registers = svd_elem.registers.getchildren()
self.description = str(svd_elem.description)
self.name = str(svd_elem.name)
- self.registers = OrderedDict()
- self.clusters = OrderedDict()
- for r in registers:
- if r.tag == "cluster":
- add_cluster(self, r)
- else:
- add_register(self, r)
+ self.registers = SmartDict()
+ self.clusters = SmartDict()
+
+ if hasattr(svd_elem, "registers"):
+ registers = [
+ r
+ for r in svd_elem.registers.getchildren()
+ if r.tag in ["cluster", "register"]
+ ]
+ for r in registers:
+ if r.tag == "cluster":
+ add_cluster(self, r)
+ elif r.tag == "register":
+ add_register(self, r)
def refactor_parent(self, parent):
- self.parent = parent
- try:
- values = self.registers.itervalues()
- except AttributeError:
- values = self.registers.values()
+ self.parent_base_address = parent.base_address
+ values = self.registers.values()
for r in values:
r.refactor_parent(self)
- try:
- for c in self.clusters.itervalues():
- c.refactor_parent(self)
- except AttributeError:
- for c in self.clusters.values():
- c.refactor_parent(self)
- def __unicode__(self):
+ for c in self.clusters.values():
+ c.refactor_parent(self)
+
+ def __str__(self):
return str(self.name)
class SVDPeripheralRegister:
+ """
+ A register within a peripheral
+ """
+
def __init__(self, svd_elem, parent):
- self.parent = parent
+ self.parent_base_address = parent.base_address
self.name = str(svd_elem.name)
self.description = str(svd_elem.description)
self.offset = int(str(svd_elem.addressOffset), 0)
- try:
+ if hasattr(svd_elem, "access"):
self.access = str(svd_elem.access)
- except:
+ else:
self.access = "read-write"
- try:
+ if hasattr(svd_elem, "size"):
self.size = int(str(svd_elem.size), 0)
- except:
+ else:
self.size = 0x20
- self.fields = OrderedDict()
+ self.fields = SmartDict()
if hasattr(svd_elem, "fields"):
- fields = svd_elem.fields.getchildren()
+ # Filter fields to only consider those of tag "field"
+ fields = [f for f in svd_elem.fields.getchildren() if f.tag == "field"]
for f in fields:
self.fields[str(f.name)] = SVDPeripheralRegisterField(f, self)
def refactor_parent(self, parent):
- self.parent = parent
- try:
- fields = self.fields.itervalues()
- except AttributeError:
- fields = self.fields.values()
- for f in fields:
- f.refactor_parent(self)
+ self.parent_base_address = parent.base_address
def address(self):
- return self.parent.base_address + self.offset
+ return self.parent_base_address + self.offset
def readable(self):
return self.access in ["read-only", "read-write", "read-writeOnce"]
@@ -223,44 +361,58 @@ class SVDPeripheralRegister:
"read-writeOnce",
]
- def __unicode__(self):
+ def __str__(self):
return str(self.name)
class SVDPeripheralRegisterField:
+ """
+ Field within a register
+ """
+
def __init__(self, svd_elem, parent):
- self.parent = parent
self.name = str(svd_elem.name)
self.description = str(getattr(svd_elem, "description", ""))
- try:
+ # Try to extract a bit range (offset and width) from the available fields
+ if hasattr(svd_elem, "bitOffset") and hasattr(svd_elem, "bitWidth"):
self.offset = int(str(svd_elem.bitOffset))
self.width = int(str(svd_elem.bitWidth))
- except:
- try:
- bitrange = list(
- map(int, str(svd_elem.bitRange).strip()[1:-1].split(":"))
- )
- self.offset = bitrange[1]
- self.width = 1 + bitrange[0] - bitrange[1]
- except:
- lsb = int(str(svd_elem.lsb))
- msb = int(str(svd_elem.msb))
- self.offset = lsb
- self.width = 1 + msb - lsb
+ elif hasattr(svd_elem, "bitRange"):
+ bitrange = list(map(int, str(svd_elem.bitRange).strip()[1:-1].split(":")))
+ self.offset = bitrange[1]
+ self.width = 1 + bitrange[0] - bitrange[1]
+ else:
+ assert hasattr(svd_elem, "lsb") and hasattr(
+ svd_elem, "msb"
+ ), "Range not found for field {} in register {}".format(self.name, parent)
+ lsb = int(str(svd_elem.lsb))
+ msb = int(str(svd_elem.msb))
+ self.offset = lsb
+ self.width = 1 + msb - lsb
+
self.access = str(getattr(svd_elem, "access", parent.access))
self.enum = {}
if hasattr(svd_elem, "enumeratedValues"):
- for v in svd_elem.enumeratedValues.getchildren():
- if v.tag == "name":
+ values = [
+ v
+ for v in svd_elem.enumeratedValues.getchildren()
+ if v.tag == "enumeratedValue"
+ ]
+ for v in values:
+ # Skip the "name" tag and any entries that don't have a value
+ if v.tag == "name" or not hasattr(v, "value"):
continue
# Some Kinetis parts have values with # instead of 0x...
value = str(v.value).replace("#", "0x")
- self.enum[int(value, 0)] = (str(v.name), str(v.description))
-
- def refactor_parent(self, parent):
- self.parent = parent
+ description = str(v.description) if hasattr(v, "description") else ""
+ try:
+ index = int(value, 0)
+ self.enum[int(value, 0)] = (str(v.name), description)
+ except ValueError:
+ # If the value couldn't be converted as a single integer, skip it
+ pass
def readable(self):
return self.access in ["read-only", "read-write", "read-writeOnce"]
@@ -273,11 +425,15 @@ class SVDPeripheralRegisterField:
"read-writeOnce",
]
- def __unicode__(self):
+ def __str__(self):
return str(self.name)
-if __name__ == "__main__":
+def _main():
+ """
+ Basic test to parse a file and do some things
+ """
+
for f in sys.argv[1:]:
print("Testing file: {}".format(f))
svd = SVDFile(f)
@@ -286,3 +442,7 @@ if __name__ == "__main__":
print("Registers in peripheral '{}':".format(key))
print(svd.peripherals[key].registers)
print("Done testing file: {}".format(f))
+
+
+if __name__ == "__main__":
+ _main()
diff --git a/debug/PyCortexMDebug/cmdebug/svd_gdb.py b/debug/PyCortexMDebug/cmdebug/svd_gdb.py
old mode 100644
new mode 100755
index 7153f1c9..3acd014f
--- a/debug/PyCortexMDebug/cmdebug/svd_gdb.py
+++ b/debug/PyCortexMDebug/cmdebug/svd_gdb.py
@@ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License
along with PyCortexMDebug. If not, see .
"""
-import binascii
import gdb
import re
import math
@@ -24,10 +23,7 @@ import sys
import struct
import pkg_resources
-sys.path.append(".")
-from cmdebug.svd import SVDFile
-
-# from svd_test import *
+from .svd import SVDFile
BITS_TO_UNPACK_FORMAT = {
8: "B",
@@ -83,7 +79,8 @@ class LoadSVD(gdb.Command):
return [fname for fname in filenames if fname.lower().startswith(prefix)]
return gdb.COMPLETE_NONE
- def invoke(self, args, from_tty):
+ @staticmethod
+ def invoke(args, from_tty):
args = gdb.string_to_argv(args)
argc = len(args)
if argc == 1:
@@ -130,36 +127,39 @@ class SVD(gdb.Command):
except AttributeError:
regs_iter = registers.values()
gdb.write("Registers in %s:\n" % container_name)
- regList = []
+ reg_list = []
for r in regs_iter:
if r.readable():
- data = self.read(r.address(), r.size)
- data = self.format(data, form, r.size)
- if form == "a":
- data += (
- " <"
- + re.sub(
- r"\s+",
- " ",
- gdb.execute(
- "info symbol {}".format(data), True, True
- ).strip(),
+ try:
+ data = self.read(r.address(), r.size)
+ data = self.format(data, form, r.size)
+ if form == "a":
+ data += (
+ " <"
+ + re.sub(
+ r"\s+",
+ " ",
+ gdb.execute(
+ "info symbol {}".format(data), True, True
+ ).strip(),
+ )
+ + ">"
)
- + ">"
- )
+ except gdb.MemoryError:
+ data = "(error reading)"
else:
data = "(not readable)"
desc = re.sub(r"\s+", " ", r.description)
- regList.append((r.name, data, desc))
+ reg_list.append((r.name, data, desc))
- column1Width = max(len(reg[0]) for reg in regList) + 2 # padding
- column2Width = max(len(reg[1]) for reg in regList)
- for reg in regList:
+ column1_width = max(len(reg[0]) for reg in reg_list) + 2 # padding
+ column2_width = max(len(reg[1]) for reg in reg_list)
+ for reg in reg_list:
gdb.write(
"\t{}:{}{}".format(
reg[0],
- "".ljust(column1Width - len(reg[0])),
- reg[1].rjust(column2Width),
+ "".ljust(column1_width - len(reg[0])),
+ reg[1].rjust(column2_width),
)
)
if reg[2] != reg[0]:
@@ -173,7 +173,7 @@ class SVD(gdb.Command):
data = 0
else:
data = self.read(register.address(), register.size)
- fieldList = []
+ field_list = []
try:
fields_iter = fields.itervalues()
except AttributeError:
@@ -193,16 +193,16 @@ class SVD(gdb.Command):
val = self.format(val, form, f.width)
else:
val = "(not readable)"
- fieldList.append((f.name, val, desc))
+ field_list.append((f.name, val, desc))
- column1Width = max(len(field[0]) for field in fieldList) + 2 # padding
- column2Width = max(len(field[1]) for field in fieldList) # padding
- for field in fieldList:
+ column1_width = max(len(field[0]) for field in field_list) + 2 # padding
+ column2_width = max(len(field[1]) for field in field_list) # padding
+ for field in field_list:
gdb.write(
"\t{}:{}{}".format(
field[0],
- "".ljust(column1Width - len(field[0])),
- field[1].rjust(column2Width),
+ "".ljust(column1_width - len(field[0])),
+ field[1].rjust(column2_width),
)
)
if field[2] != field[0]:
@@ -234,6 +234,10 @@ class SVD(gdb.Command):
gdb.write("svd/[format_character] ...\n")
gdb.write("\tFormat values using that character\n")
gdb.write("\td(default):decimal, x: hex, o: octal, b: binary\n")
+ gdb.write("\n")
+ gdb.write(
+ "Both prefix matching and case-insensitive matching is supported for peripherals, registers, clusters and fields.\n"
+ )
return
if not len(s[0]):
@@ -242,7 +246,7 @@ class SVD(gdb.Command):
peripherals = self.svd_file.peripherals.itervalues()
except AttributeError:
peripherals = self.svd_file.peripherals.values()
- columnWidth = max(len(p.name) for p in peripherals) + 2 # padding
+ column_width = max(len(p.name) for p in peripherals) + 2 # padding
try:
peripherals = self.svd_file.peripherals.itervalues()
except AttributeError:
@@ -251,11 +255,19 @@ class SVD(gdb.Command):
desc = re.sub(r"\s+", " ", p.description)
gdb.write(
"\t{}:{}{}\n".format(
- p.name, "".ljust(columnWidth - len(p.name)), desc
+ p.name, "".ljust(column_width - len(p.name)), desc
)
)
return
+ def warn_if_ambiguous(smart_dict, key):
+ if smart_dict.is_ambiguous(key):
+ gdb.write(
+ "Warning: {} could prefix match any of: {}\n".format(
+ key, ", ".join(smart_dict.prefix_match_iter(key))
+ )
+ )
+
registers = None
if len(s) >= 1:
peripheral_name = s[0]
@@ -263,29 +275,31 @@ class SVD(gdb.Command):
gdb.write("Peripheral {} does not exist!\n".format(s[0]))
return
+ warn_if_ambiguous(self.svd_file.peripherals, peripheral_name)
+
peripheral = self.svd_file.peripherals[peripheral_name]
if len(s) == 1:
- self._print_registers(s[0], form, peripheral.registers)
+ self._print_registers(peripheral.name, form, peripheral.registers)
if len(peripheral.clusters) > 0:
try:
clusters_iter = peripheral.clusters.itervalues()
except AttributeError:
clusters_iter = peripheral.clusters.values()
- gdb.write("Clusters in %s:\n" % peripheral_name)
- regList = []
+ gdb.write("Clusters in %s:\n" % peripheral.name)
+ reg_list = []
for r in clusters_iter:
desc = re.sub(r"\s+", " ", r.description)
- regList.append((r.name, "", desc))
+ reg_list.append((r.name, "", desc))
- column1Width = max(len(reg[0]) for reg in regList) + 2 # padding
- column2Width = max(len(reg[1]) for reg in regList)
- for reg in regList:
+ column1_width = max(len(reg[0]) for reg in reg_list) + 2 # padding
+ column2_width = max(len(reg[1]) for reg in reg_list)
+ for reg in reg_list:
gdb.write(
"\t{}:{}{}".format(
reg[0],
- "".ljust(column1Width - len(reg[0])),
- reg[1].rjust(column2Width),
+ "".ljust(column1_width - len(reg[0])),
+ reg[1].rjust(column2_width),
)
)
if reg[2] != reg[0]:
@@ -295,19 +309,23 @@ class SVD(gdb.Command):
cluster = None
if len(s) == 2:
- container = " ".join(s[:2])
if s[1] in peripheral.clusters:
- self._print_registers(
- container, form, peripheral.clusters[s[1]].registers
- )
+ warn_if_ambiguous(peripheral.clusters, s[1])
+ cluster = peripheral.clusters[s[1]]
+ container = peripheral.name + " > " + cluster.name
+ self._print_registers(container, form, cluster.registers)
+
elif s[1] in peripheral.registers:
- self._print_register_fields(
- container, form, self.svd_file.peripherals[s[0]].registers[s[1]]
- )
+ warn_if_ambiguous(peripheral.registers, s[1])
+ register = peripheral.registers[s[1]]
+ container = peripheral.name + " > " + register.name
+
+ self._print_register_fields(container, form, register)
+
else:
gdb.write(
"Register/cluster {} in peripheral {} does not exist!\n".format(
- s[1], s[0]
+ s[1], peripheral.name
)
)
return
@@ -315,42 +333,55 @@ class SVD(gdb.Command):
if len(s) == 3:
if s[1] not in peripheral.clusters:
gdb.write(
- "Cluster {} in peripheral {} does not exist!\n".format(s[1], s[0])
- )
- elif s[2] not in peripheral.clusters[s[1]].registers:
- gdb.write(
- "Register {} in cluster {} in peripheral {} does not exist!\n".format(
- s[2], s[1], s[0]
+ "Cluster {} in peripheral {} does not exist!\n".format(
+ s[1], peripheral.name
)
)
- else:
- container = " ".join(s[:3])
- cluster = peripheral.clusters[s[1]]
- self._print_register_fields(container, form, cluster.registers[s[2]])
+ return
+ warn_if_ambiguous(peripheral.clusters, s[1])
+
+ cluster = peripheral.clusters[s[1]]
+ if s[2] not in cluster.registers:
+ gdb.write(
+ "Register {} in cluster {} in peripheral {} does not exist!\n".format(
+ s[2], cluster.name, peripheral.name
+ )
+ )
+ return
+ warn_if_ambiguous(cluster.registers, s[2])
+
+ register = cluster.registers[s[2]]
+ container = " > ".join([peripheral.name, cluster.name, register.name])
+ self._print_register_fields(container, form, register)
return
if len(s) == 4:
- try:
- reg = self.svd_file.peripherals[s[0]].registers[s[1]]
- except KeyError:
+ if s[1] not in peripheral.registers:
gdb.write(
- "Register {} in peripheral {} does not exist!\n".format(s[1], s[0])
- )
- return
- try:
- field = reg.fields[s[2]]
- except KeyError:
- gdb.write(
- "Field {} in register {} in peripheral {} does not exist!\n".format(
- s[2], s[1], s[0]
+ "Register {} in peripheral {} does not exist!\n".format(
+ s[1], peripheral.name
)
)
return
+ warn_if_ambiguous(peripheral.registers, s[1])
+
+ reg = peripheral.registers[s[1]]
+
+ if s[2] not in reg.fields:
+ gdb.write(
+ "Field {} in register {} in peripheral {} does not exist!\n".format(
+ s[2], reg.name, peripheral.name
+ )
+ )
+ return
+ warn_if_ambiguous(reg.fields, s[2])
+
+ field = reg.fields[s[2]]
if not field.writable() or not reg.writable():
gdb.write(
"Field {} in register {} in peripheral {} is read-only!\n".format(
- s[2], s[1], s[0]
+ field.name, reg.name, peripheral.name
)
)
return
@@ -359,9 +390,8 @@ class SVD(gdb.Command):
val = int(s[3], 0)
except ValueError:
gdb.write(
- "{} is not a valid number! You can prefix numbers with 0x for hex, 0b for binary, or any python int literal\n".format(
- s[3]
- )
+ "{} is not a valid number! You can prefix numbers with 0x for hex, 0b for binary, or any python "
+ "int literal\n".format(s[3])
)
return
@@ -378,7 +408,7 @@ class SVD(gdb.Command):
else:
data = self.read(reg.address(), reg.size)
data &= ~(((1 << field.width) - 1) << field.offset)
- data |= (val) << field.offset
+ data |= val << field.offset
self.write(reg.address(), data, reg.size)
return
@@ -394,22 +424,26 @@ class SVD(gdb.Command):
if len(s) > 1:
s = s[1:]
else:
- return
+ return [] # completion after e.g. "svd/x" but before trailing space
if len(s) == 1:
- return filter(
- lambda x: x.lower().startswith(s[0].lower()),
- self.peripheral_list() + ["help"],
- )
+ return list(self.svd_file.peripherals.prefix_match_iter(s[0]))
if len(s) == 2:
reg = s[1].upper()
if len(reg) and reg[0] == "&":
reg = reg[1:]
- filt = filter(lambda x: x.startswith(reg), self.register_list(s[0].upper()))
- return filt
- def read(self, address, bits=32):
+ if s[0] not in self.svd_file.peripherals:
+ return []
+
+ per = self.svd_file.peripherals[s[0]]
+ return list(per.registers.prefix_match_iter(s[1]))
+
+ return []
+
+ @staticmethod
+ def read(address, bits=32):
"""Read from memory and return an integer"""
value = gdb.selected_inferior().read_memory(address, bits / 8)
unpack_format = "I"
@@ -418,15 +452,17 @@ class SVD(gdb.Command):
# gdb.write("{:x} {}\n".format(address, binascii.hexlify(value)))
return struct.unpack_from("<" + unpack_format, value)[0]
- def write(self, address, data, bits=32):
+ @staticmethod
+ def write(address, data, bits=32):
"""Write data to memory"""
gdb.selected_inferior().write_memory(address, bytes(data), bits / 8)
- def format(self, value, form, length=32):
+ @staticmethod
+ def format(value, form, length=32):
"""Format a number based on a format character and length"""
# get current gdb radix setting
radix = int(
- re.search("\d+", gdb.execute("show output-radix", True, True)).group(0)
+ re.search(r"\d+", gdb.execute("show output-radix", True, True)).group(0)
)
# override it if asked to
@@ -454,7 +490,7 @@ class SVD(gdb.Command):
try:
keys = self.svd_file.peripherals.iterkeys()
except AttributeError:
- keys = elf.svd_file.peripherals.keys()
+ keys = self.svd_file.peripherals.keys()
return list(keys)
def register_list(self, peripheral):
@@ -470,7 +506,7 @@ class SVD(gdb.Command):
def field_list(self, peripheral, register):
try:
- periph = svd_file.peripherals[peripheral]
+ periph = self.svd_file.peripherals[peripheral]
reg = periph.registers[register]
try:
regs = reg.fields.iterkeys()
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 9c4f96f9..406d806e 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -20,7 +20,9 @@ RUN apt-get update && \
unzip \
build-essential \
python \
+ python-dev \
python-pip \
+ python-setuptools \
python3 \
imagemagick \
srecord \
@@ -29,6 +31,9 @@ RUN apt-get update && \
dfu-util \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+RUN pip install lxml
+
+
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]
RUN wget --progress=dot:giga -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | apt-key add - && add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main"
@@ -48,7 +53,7 @@ RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/
cd gcc-arm-none-eabi-10-2020-q4-major/bin/ && \
for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \
cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v
-
+
# install hex2dfu
# hadolint ignore=DL3003
diff --git a/make/rules.mk b/make/rules.mk
index 6edc9152..627f14c6 100644
--- a/make/rules.mk
+++ b/make/rules.mk
@@ -72,11 +72,11 @@ flash: $(OBJ_DIR)/flash
upload: $(OBJ_DIR)/upload
debug: flash
- arm-none-eabi-gdb \
+ arm-none-eabi-gdb-py \
-ex 'target extended-remote | openocd -c "gdb_port pipe" $(OPENOCD_OPTS)' \
-ex "set confirm off" \
-ex "source ../debug/FreeRTOS/FreeRTOS.py" \
- -ex "source ../debug/PyCortexMDebug/scripts/gdb.py" \
+ -ex "source ../debug/PyCortexMDebug/PyCortexMDebug.py" \
-ex "svd_load $(SVD_FILE)" \
-ex "compare-sections" \
$(OBJ_DIR)/$(PROJECT).elf; \
@@ -86,7 +86,7 @@ openocd:
bm_debug: flash
set -m; blackmagic & echo $$! > $(OBJ_DIR)/agent.PID
- arm-none-eabi-gdb \
+ arm-none-eabi-gdb-py \
-ex "target extended-remote 127.0.0.1:2000" \
-ex "set confirm off" \
-ex "monitor debug_bmp enable"\