#
# Copyright 2025 Chair of EDA, Technical University of Munich
#
# 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.
#
import re
[docs]
class Trace(MetaTraceModel_base):
def __init__(self, name_, core_):
[docs]
self.instructionGroups = []
super().__init__()
[docs]
def createAndAddTraceValue(self, name_, type_="int", size_=-1):
trVal = TraceValue(name_, type_, size_)
self.traceValues[name_] = trVal
return trVal
[docs]
def createAndAddInstructionGroup(self, name_, id_):
instrType = InstructionGroup(name_, id_, self)
self.instructionGroups.append(instrType)
return instrType
[docs]
def getAllTraceValues(self):
return self.traceValues.values()
[docs]
def getAllInstructionGroups(self):
return self.instructionGroups
[docs]
def getAllMappings(self):
mappings = []
for instrType_i in self.getAllInstructionGroups():
mappings.extend(instrType_i.getAllMappings())
return mappings
[docs]
def getAllDescriptions(self):
descriptions = []
for map_i in self.getAllMappings():
descriptions.append(map_i.description)
return descriptions
[docs]
def setSeparator(self, sep_):
self.separator = sep_
[docs]
def getSeparator(self):
return self.separator
[docs]
class InstructionGroup(MetaTraceModel_base):
def __init__(self, name_, id_, parent_):
[docs]
self.__parent = parent_
super().__init__()
[docs]
def addInstruction(self, name_):
self.instructions.append(name_)
[docs]
def addBitfield(self, name_):
self.bitfields.append(name_)
[docs]
def createAndAddMapping(self, trValName_, description_, position_):
# Look up trace-value in dict. of parent/trace-model
try:
trVal = self.__parent.traceValues[trValName_]
except KeyError:
raise TypeError("Mapping for instruction %s: Cannot create mapping for trace-value %s. Trace-value does not exist (Make sure to add all trace-values to the trace-model before creating mappings)" %(self.name, trValName_))
mapping = Mapping(self, trVal, description_, position_)
self.mappings[trValName_] = mapping
return mapping
[docs]
def getAllInstructions(self):
return self.instructions
[docs]
def getAllBitfields(self):
return self.bitfields
[docs]
def getAllMappings(self):
return self.mappings.values()
[docs]
def getMapping(self, trVal_):
try:
return self.mappings[trVal_.name]
except KeyError:
return None
[docs]
def getAllPreMappings(self):
mappings = []
for map_i in self.mappings:
map_i = self.mappings[map_i]
if map_i.positionIsPre():
mappings.append(map_i)
return mappings
[docs]
def getAllPostMappings(self):
mappings = []
for map_i in self.mappings:
map_i = self.mappings[map_i]
if map_i.positionIsPost():
mappings.append(map_i)
return mappings
[docs]
class TraceValue(MetaTraceModel_base):
def __init__(self, name_, type_, size_):
super().__init__()
[docs]
class Mapping(MetaTraceModel_base):
def __init__(self, type_, trVal_, descr_, pos_):
[docs]
self.instructionGroup = type_
[docs]
self.traceValue = trVal_
# self.description = Description(self, descr_)
[docs]
self.description = DescriptionParser().parse_description_string(descr_, self.instructionGroup)
if pos_ not in ["pre", "post"]:
raise RuntimeError("Cannot create object of type MetaTraceModel::Mapping with position \"%s\"! Currently supported positions are \"pre\" and \"post\"" %pos_)
super().__init__()
[docs]
def positionIsPre(self):
return (self.position == "pre")
[docs]
def positionIsPost(self):
return (self.position == "post")
[docs]
def getTraceValue(self):
return self.traceValue
[docs]
def getDescription(self):
return self.description
[docs]
def getInstructionGroup(self):
return self.instructionGroup
[docs]
class Description(MetaTraceModel_base):
def __init__(self, type_, value, resolved=False, nested_descriptions=None):
[docs]
self.resolved = resolved
[docs]
self.nested_descriptions = nested_descriptions or []
[docs]
def getDescriptionType(self):
return self.type
[docs]
def getDescriptionValue(self):
return self.value
[docs]
def getNestedDescriptions(self):
return self.nested_descriptions
[docs]
def __repr__(self):
if self.nested_descriptions:
nested_repr = ', '.join([repr(nd) for nd in self.nested_descriptions])
return f"Description(type={self.type}, value={self.value}, resolved={self.resolved} , nested_descriptions=[{nested_repr}])"
else:
return f"Description(type={self.type}, value={self.value}, resolved={self.resolved})"
[docs]
class DescriptionParser(MetaTraceModel_base):
[docs]
def parse_description_string(self, desc_string, instructionGroup, resolved = False):
parsed_descriptions = []
resolved = resolved
buffer = ""
i = 0
while i < len(desc_string):
if desc_string[i:i+3] == "$pc":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
parsed_descriptions.append(Description(type_="pc", value="pc", resolved=resolved))
i += 3
elif desc_string[i:i+4] == "$asm":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
parsed_descriptions.append(Description(type_="asm", value="asm", resolved=resolved))
i += 4
elif desc_string[i:i+5] == "$code":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
parsed_descriptions.append(Description(type_="code", value="code", resolved=resolved))
i += 5
elif desc_string[i:i+5] == "$reg{":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
i += 5
nested_content, i = self.extract_nested_content(desc_string, i)
parsed_descriptions.append(Description(type_="reg", value="reg", resolved=resolved, nested_descriptions=self.parse_description_string(nested_content, instructionGroup, resolved=resolved)))
elif desc_string[i:i+5] == "$csr{":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
i += 5
nested_content, i = self.extract_nested_content(desc_string, i)
parsed_descriptions.append(Description(type_="csr", value="csr", resolved=resolved, nested_descriptions=self.parse_description_string(nested_content, instructionGroup, resolved=resolved)))
elif desc_string[i:i+10] == "$bitfield{":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
i += 10
nested_content, i = self.extract_nested_content(desc_string, i, single_level=True)
if nested_content not in instructionGroup.bitfields:
instructionGroup.addBitfield(nested_content)
parsed_descriptions.append(Description(type_="bitfield", value=nested_content, resolved=resolved))
elif desc_string[i:i+10] == "$resolved{":
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
buffer = ""
i += 10
nested_content, i = self.extract_nested_content(desc_string, i)
parsed_descriptions.extend(self.parse_description_string(nested_content, instructionGroup, resolved=True))
else:
buffer += desc_string[i]
i += 1
if buffer:
parsed_descriptions.append(Description(type_="string", value=buffer, resolved=resolved))
return parsed_descriptions