mirror of https://gitlab.freedesktop.org/mesa/mesa
675 lines
23 KiB
Python
675 lines
23 KiB
Python
#
|
|
# Copyright © 2020 Google, Inc.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice (including the next
|
|
# paragraph) shall be included in all copies or substantial portions of the
|
|
# Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
# IN THE SOFTWARE.
|
|
|
|
from xml.etree import ElementTree
|
|
import os
|
|
import re
|
|
|
|
def dbg(str):
|
|
if False:
|
|
print(str)
|
|
|
|
class BitSetPattern(object):
|
|
"""Class that encapsulated the pattern matching, ie.
|
|
the match/dontcare/mask bitmasks. The following
|
|
rules should hold
|
|
|
|
(match ^ dontcare) == 0
|
|
(match || dontcare) == mask
|
|
|
|
For a leaf node, the mask should be (1 << size) - 1
|
|
(ie. all bits set)
|
|
"""
|
|
def __init__(self, bitset):
|
|
self.match = bitset.match
|
|
self.dontcare = bitset.dontcare
|
|
self.mask = bitset.mask
|
|
self.field_mask = bitset.field_mask
|
|
|
|
def merge(self, pattern):
|
|
p = BitSetPattern(pattern)
|
|
p.match = p.match | self.match
|
|
p.dontcare = p.dontcare | self.dontcare
|
|
p.mask = p.mask | self.mask
|
|
p.field_mask = p.field_mask | self.field_mask
|
|
return p
|
|
|
|
def defined_bits(self):
|
|
return self.match | self.dontcare | self.mask | self.field_mask
|
|
|
|
def get_bitrange(field):
|
|
if 'pos' in field.attrib:
|
|
assert('low' not in field.attrib)
|
|
assert('high' not in field.attrib)
|
|
low = int(field.attrib['pos'])
|
|
high = low
|
|
else:
|
|
low = int(field.attrib['low'])
|
|
high = int(field.attrib['high'])
|
|
assert low <= high
|
|
return low, high
|
|
|
|
def extract_pattern(xml, name, is_defined_bits=None):
|
|
low, high = get_bitrange(xml)
|
|
mask = ((1 << (1 + high - low)) - 1) << low
|
|
|
|
patstr = xml.text.strip()
|
|
|
|
assert (len(patstr) == (1 + high - low)), "Invalid {} length in {}: {}..{}".format(xml.tag, name, low, high)
|
|
if is_defined_bits is not None:
|
|
assert not is_defined_bits(mask), "Redefined bits in {} {}: {}..{}".format(xml.tag, name, low, high)
|
|
|
|
match = 0
|
|
dontcare = 0
|
|
|
|
for n in range(0, len(patstr)):
|
|
match = match << 1
|
|
dontcare = dontcare << 1
|
|
if patstr[n] == '1':
|
|
match |= 1
|
|
elif patstr[n] == 'x':
|
|
dontcare |= 1
|
|
elif patstr[n] != '0':
|
|
assert 0, "Invalid {} character in {}: {}".format(xml.tag, name, patstr[n])
|
|
|
|
dbg("{}: {}.{} => {:016x} / {:016x} / {:016x}".format(xml.tag, name, patstr, match << low, dontcare << low, mask))
|
|
|
|
return match << low, dontcare << low, mask
|
|
|
|
def get_c_name(name):
|
|
return name.lower().replace('#', '__').replace('-', '_').replace('.', '_')
|
|
|
|
class BitSetField(object):
|
|
"""Class that encapsulates a field defined in a bitset
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.low, self.high = get_bitrange(xml)
|
|
self.name = xml.attrib['name']
|
|
self.type = xml.attrib['type']
|
|
self.params = []
|
|
for param in xml.findall('param'):
|
|
aas = name = param.attrib['name']
|
|
if 'as' in param.attrib:
|
|
aas = param.attrib['as']
|
|
self.params.append([name, aas])
|
|
self.expr = None
|
|
self.display = None
|
|
self.call = 'call' in xml.attrib and xml.attrib['call'] == 'true'
|
|
if 'display' in xml.attrib:
|
|
self.display = xml.attrib['display'].strip()
|
|
|
|
def get_c_name(self):
|
|
return get_c_name(self.name)
|
|
|
|
def get_c_typename(self):
|
|
if self.type in self.isa.enums:
|
|
return 'TYPE_ENUM'
|
|
if self.type in self.isa.bitsets:
|
|
return 'TYPE_BITSET'
|
|
return 'TYPE_' + self.type.upper()
|
|
|
|
def mask(self):
|
|
return ((1 << self.get_size()) - 1) << self.low
|
|
|
|
def get_size(self):
|
|
return 1 + self.high - self.low
|
|
|
|
class BitSetAssertField(BitSetField):
|
|
"""Similar to BitSetField, but for <assert/>s, which can be
|
|
used to specify that a certain bitpattern is expected in
|
|
place of (for example) unused bitfields
|
|
"""
|
|
def __init__(self, case, xml):
|
|
self.isa = case.bitset.isa
|
|
self.low, self.high = get_bitrange(xml)
|
|
self.name = case.bitset.name + '#assert' + str(len(case.fields))
|
|
self.type = 'uint'
|
|
self.expr = None
|
|
self.display = None
|
|
|
|
match, dontcare, mask = extract_pattern(xml, case.bitset.name)
|
|
self.val = match >> self.low
|
|
|
|
assert dontcare == 0, "'x' (dontcare) is not valid in an assert"
|
|
|
|
def get_c_typename(self):
|
|
return 'TYPE_ASSERT'
|
|
|
|
class BitSetDerivedField(BitSetField):
|
|
"""Similar to BitSetField, but for derived fields
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.low = 0
|
|
self.high = 0
|
|
# NOTE: a width should be provided for 'int' derived fields, ie.
|
|
# where sign extension is needed. We just repurpose the 'high'
|
|
# field for that to make '1 + high - low' work out
|
|
if 'width' in xml.attrib:
|
|
self.high = int(xml.attrib['width']) - 1
|
|
self.name = xml.attrib['name']
|
|
self.type = xml.attrib['type']
|
|
if 'expr' in xml.attrib:
|
|
self.expr = xml.attrib['expr']
|
|
else:
|
|
e = isa.parse_one_expression(xml, self.name)
|
|
self.expr = e.name
|
|
self.display = None
|
|
if 'display' in xml.attrib:
|
|
self.display = xml.attrib['display'].strip()
|
|
self.call = 'call' in xml.attrib and xml.attrib['call'] == 'true'
|
|
|
|
class BitSetCase(object):
|
|
"""Class that encapsulates a single bitset case
|
|
"""
|
|
def __init__(self, bitset, xml, update_field_mask, expr=None):
|
|
self.bitset = bitset
|
|
if expr is not None:
|
|
self.name = bitset.name + '#case' + str(len(bitset.cases))
|
|
else:
|
|
self.name = bitset.name + "#default"
|
|
self.expr = expr
|
|
self.fields = {}
|
|
|
|
for derived in xml.findall('derived'):
|
|
f = BitSetDerivedField(bitset.isa, derived)
|
|
self.fields[f.name] = f
|
|
|
|
for assrt in xml.findall('assert'):
|
|
f = BitSetAssertField(self, assrt)
|
|
update_field_mask(self, f)
|
|
self.fields[f.name] = f
|
|
|
|
for field in xml.findall('field'):
|
|
dbg("{}.{}".format(self.name, field.attrib['name']))
|
|
f = BitSetField(bitset.isa, field)
|
|
update_field_mask(self, f)
|
|
self.fields[f.name] = f
|
|
|
|
self.display = None
|
|
for d in xml.findall('display'):
|
|
# Allow <display/> for empty display string:
|
|
if d.text is not None:
|
|
self.display = d.text.strip()
|
|
else:
|
|
self.display = ''
|
|
dbg("found display: '{}'".format(self.display))
|
|
|
|
def get_c_name(self):
|
|
return get_c_name(self.name)
|
|
|
|
class BitSetEncode(object):
|
|
"""Additional data that may be associated with a root bitset node
|
|
to provide additional information needed to generate helpers
|
|
to encode the bitset, such as source data type and "opcode"
|
|
case prefix (ie. how to choose/enumerate which leaf node bitset
|
|
to use to encode the source data
|
|
"""
|
|
def __init__(self, xml):
|
|
self.type = None
|
|
if 'type' in xml.attrib:
|
|
self.type = xml.attrib['type']
|
|
self.case_prefix = None
|
|
if 'case-prefix' in xml.attrib:
|
|
self.case_prefix = xml.attrib['case-prefix']
|
|
# The encode element may also contain mappings from encode src
|
|
# to individual field names:
|
|
self.maps = {}
|
|
self.forced = {}
|
|
for map in xml.findall('map'):
|
|
name = map.attrib['name']
|
|
self.maps[name] = map.text.strip()
|
|
if 'force' in map.attrib and map.attrib['force'] == 'true':
|
|
self.forced[name] = 'true'
|
|
|
|
class BitSetDecode(object):
|
|
"""Additional data that may be associated with a root bitset node
|
|
to provide additional information needed to generate helpers
|
|
to decode the bitset.
|
|
"""
|
|
def __init__(self, xml):
|
|
pass
|
|
|
|
class BitSet(object):
|
|
"""Class that encapsulates a single bitset rule
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.xml = xml
|
|
self.name = xml.attrib['name']
|
|
self.display_name = xml.attrib['displayname'] if 'displayname' in xml.attrib else self.name
|
|
self.meta = {}
|
|
|
|
# Used for generated encoder, to de-duplicate encoding for
|
|
# similar instructions:
|
|
self.snippets = {}
|
|
|
|
if 'size' in xml.attrib:
|
|
assert('extends' not in xml.attrib)
|
|
self.size = int(xml.attrib['size'])
|
|
self.extends = None
|
|
else:
|
|
self.size = None
|
|
self.extends = xml.attrib['extends']
|
|
|
|
self.encode = None
|
|
if xml.find('encode') is not None:
|
|
self.encode = BitSetEncode(xml.find('encode'))
|
|
self.decode = None
|
|
if xml.find('decode') is not None:
|
|
self.decode = BitSetDecode(xml.find('encode'))
|
|
|
|
self.gen_min = 0
|
|
self.gen_max = (1 << 32) - 1
|
|
|
|
for gen in xml.findall('gen'):
|
|
if 'min' in gen.attrib:
|
|
self.gen_min = int(gen.attrib['min'])
|
|
if 'max' in gen.attrib:
|
|
self.gen_max = int(gen.attrib['max'])
|
|
|
|
for meta in xml.findall('meta'):
|
|
self.meta.update(meta.attrib)
|
|
|
|
# Collect up the match/dontcare/mask bitmasks for
|
|
# this bitset case:
|
|
self.match = 0
|
|
self.dontcare = 0
|
|
self.mask = 0
|
|
self.field_mask = 0
|
|
|
|
self.cases = []
|
|
|
|
# Helper to check for redefined bits:
|
|
def is_defined_bits(m):
|
|
return ((self.field_mask | self.mask | self.dontcare | self.match) & m) != 0
|
|
|
|
def update_default_bitmask_field(bs, field):
|
|
m = field.mask()
|
|
dbg("field: {}.{} => {:016x}".format(self.name, field.name, m))
|
|
# For default case, we don't expect any bits to be doubly defined:
|
|
assert not is_defined_bits(m), "Redefined bits in field {}.{}: {}..{}".format(
|
|
self.name, field.name, field.low, field.high)
|
|
self.field_mask |= m
|
|
|
|
def update_override_bitmask_field(bs, field):
|
|
m = field.mask()
|
|
dbg("field: {}.{} => {:016x}".format(self.name, field.name, m))
|
|
assert self.field_mask ^ ~m
|
|
|
|
dflt = BitSetCase(self, xml, update_default_bitmask_field)
|
|
|
|
for override in xml.findall('override'):
|
|
if 'expr' in override.attrib:
|
|
expr = override.attrib['expr']
|
|
else:
|
|
e = isa.parse_one_expression(override, self.name)
|
|
expr = e.name
|
|
c = BitSetCase(self, override, update_override_bitmask_field, expr)
|
|
self.cases.append(c)
|
|
|
|
# Default case is expected to be the last one:
|
|
self.cases.append(dflt)
|
|
|
|
for pattern in xml.findall('pattern'):
|
|
match, dontcare, mask = extract_pattern(pattern, self.name, is_defined_bits)
|
|
|
|
self.match |= match
|
|
self.dontcare |= dontcare
|
|
self.mask |= mask
|
|
|
|
def get_pattern(self):
|
|
if self.extends is not None:
|
|
parent = self.isa.bitsets[self.extends]
|
|
ppat = parent.get_pattern()
|
|
pat = BitSetPattern(self)
|
|
|
|
assert ((ppat.defined_bits() & pat.defined_bits()) == 0), "bitset conflict in {}: {:x}".format(self.name, (ppat.defined_bits() & pat.defined_bits()))
|
|
|
|
return pat.merge(ppat)
|
|
|
|
return BitSetPattern(self)
|
|
|
|
def get_size(self):
|
|
if self.extends is not None:
|
|
parent = self.isa.bitsets[self.extends]
|
|
return parent.get_size()
|
|
return self.size
|
|
|
|
def get_gen_min(self):
|
|
if self.extends is not None:
|
|
parent = self.isa.bitsets[self.extends]
|
|
|
|
assert (self.gen_min == 0) or (self.gen_min >= parent.get_gen_min()), "bitset {} should not have min gen lower than the parent's one".format(self.name)
|
|
|
|
return max(self.gen_min, parent.get_gen_min())
|
|
return self.gen_min
|
|
|
|
def get_gen_max(self):
|
|
if self.extends is not None:
|
|
parent = self.isa.bitsets[self.extends]
|
|
|
|
assert (self.gen_max == (1 << 32) - 1) or (self.gen_max <= parent.get_gen_max()), "bitset {} should not have max gen higher than the parent's one".format(self.name)
|
|
|
|
return min(self.gen_max, parent.get_gen_max())
|
|
return self.gen_max
|
|
|
|
def has_gen_restriction(self):
|
|
return self.gen_min != 0 or self.gen_max != (1 << 32) - 1
|
|
|
|
def get_c_name(self):
|
|
return get_c_name(self.name)
|
|
|
|
def get_root(self):
|
|
if self.extends is not None:
|
|
return self.isa.bitsets[self.extends].get_root()
|
|
return self
|
|
|
|
def get_meta(self):
|
|
meta = {}
|
|
|
|
if self.extends is not None:
|
|
meta = self.isa.bitsets[self.extends].get_meta()
|
|
|
|
if self.meta:
|
|
meta.update(self.meta)
|
|
|
|
return meta
|
|
|
|
class BitSetTemplate(object):
|
|
"""Class that encapsulates a template declaration
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.name = xml.attrib['name']
|
|
self.display = xml.text.strip()
|
|
dbg("found template '{}: {}'".format(self.name, self.display))
|
|
|
|
class BitSetEnumValue(object):
|
|
"""Class that encapsulates an enum value
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.displayname = xml.attrib['display']
|
|
self.value = xml.attrib['val']
|
|
self.name = xml.attrib.get('name')
|
|
|
|
def __str__(self):
|
|
return self.displayname
|
|
|
|
def get_name(self):
|
|
return self.name or self.displayname
|
|
|
|
def get_displayname(self):
|
|
return self.displayname or self.name
|
|
|
|
def get_value(self):
|
|
return self.value
|
|
|
|
class BitSetEnum(object):
|
|
"""Class that encapsulates an enum declaration
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
self.name = xml.attrib['name']
|
|
|
|
# Table mapping value to name
|
|
self.values = {}
|
|
for value in xml.findall('value'):
|
|
v = BitSetEnumValue(self, value)
|
|
self.values[v.get_value()] = v
|
|
|
|
def get_c_name(self):
|
|
return 'enum_' + get_c_name(self.name)
|
|
|
|
class BitSetExpression(object):
|
|
"""Class that encapsulates an <expr> declaration
|
|
"""
|
|
def __init__(self, isa, xml):
|
|
self.isa = isa
|
|
if 'name' in xml.attrib:
|
|
self.name = xml.attrib['name']
|
|
else:
|
|
self.name = 'anon_' + str(isa.anon_expression_count)
|
|
isa.anon_expression_count = isa.anon_expression_count + 1
|
|
expr = xml.text.strip()
|
|
self.fieldnames = list(set(re.findall(r"{([a-zA-Z0-9_]+)}", expr)))
|
|
self.expr = re.sub(r"{([a-zA-Z0-9_]+)}", r"\1", expr)
|
|
dbg("'{}' -> '{}'".format(expr, self.expr))
|
|
|
|
def get_c_name(self):
|
|
return 'expr_' + get_c_name(self.name)
|
|
|
|
class ISA(object):
|
|
"""Class that encapsulates all the parsed bitset rules
|
|
"""
|
|
def __init__(self, xmlpath):
|
|
self.base_path = os.path.dirname(xmlpath)
|
|
|
|
# Counter used to name inline (anonymous) expressions:
|
|
self.anon_expression_count = 0
|
|
|
|
# Table of (globally defined) expressions:
|
|
self.expressions = {}
|
|
|
|
# Table of templates:
|
|
self.templates = {}
|
|
|
|
# Table of enums:
|
|
self.enums = {}
|
|
|
|
# Table of toplevel bitset hierarchies:
|
|
self.roots = {}
|
|
|
|
# Table of leaf nodes of bitset hierarchies:
|
|
# Note that there may be multiple leaves for a particular name
|
|
# (distinguished by gen), so the values here are lists.
|
|
self.leafs = {}
|
|
|
|
# Table of all non-ambiguous bitsets (i.e. no per-gen ambiguity):
|
|
self.bitsets = {}
|
|
|
|
# Max needed bitsize for one instruction
|
|
self.bitsize = 0
|
|
|
|
root = ElementTree.parse(xmlpath).getroot()
|
|
self.parse_file(root)
|
|
self.validate_isa()
|
|
|
|
def parse_expressions(self, root):
|
|
e = None
|
|
for expr in root.findall('expr'):
|
|
e = BitSetExpression(self, expr)
|
|
self.expressions[e.name] = e
|
|
return e
|
|
|
|
def parse_one_expression(self, root, name):
|
|
assert len(root.findall('expr')) == 1, "expected a single expression in: {}".format(name)
|
|
return self.parse_expressions(root)
|
|
|
|
def parse_file(self, root):
|
|
# Handle imports up-front:
|
|
for imprt in root.findall('import'):
|
|
p = os.path.join(self.base_path, imprt.attrib['file'])
|
|
self.parse_file(ElementTree.parse(p))
|
|
|
|
# Extract expressions:
|
|
self.parse_expressions(root)
|
|
|
|
# Extract templates:
|
|
for template in root.findall('template'):
|
|
t = BitSetTemplate(self, template)
|
|
self.templates[t.name] = t
|
|
|
|
# Extract enums:
|
|
for enum in root.findall('enum'):
|
|
e = BitSetEnum(self, enum)
|
|
self.enums[e.name] = e
|
|
|
|
# Extract bitsets:
|
|
for bitset in root.findall('bitset'):
|
|
b = BitSet(self, bitset)
|
|
if b.size is not None:
|
|
dbg("toplevel: " + b.name)
|
|
self.roots[b.name] = b
|
|
self.bitsize = max(self.bitsize, b.size)
|
|
else:
|
|
dbg("derived: " + b.name)
|
|
self.bitsets[b.name] = b
|
|
self.leafs.setdefault(b.name, []).append(b)
|
|
|
|
# Resolve all templates:
|
|
for _, bitset in self.bitsets.items():
|
|
for case in bitset.cases:
|
|
if case.display:
|
|
case.display = self.resolve_templates(case.display)
|
|
|
|
def validate_isa(self):
|
|
# We only support multiples of 32 bits for now
|
|
assert self.bitsize % 32 == 0
|
|
|
|
# Do one-time fixups
|
|
# Remove non-leaf nodes from the leafs table:
|
|
for name, bitsets in list(self.leafs.items()):
|
|
for bitset in bitsets:
|
|
if bitset.extends in self.leafs:
|
|
del self.leafs[bitset.extends]
|
|
|
|
# Fix multi-gen leaves in bitsets
|
|
for name, bitsets in self.leafs.items():
|
|
if len(bitsets) == 1:
|
|
continue
|
|
|
|
del self.bitsets[name]
|
|
|
|
# Validate that all bitset fields have valid types, and in
|
|
# the case of bitset type, the sizes match:
|
|
builtin_types = ['branch', 'absbranch', 'int', 'uint', 'hex', 'offset', 'uoffset', 'float', 'bool', 'bool_inv', 'enum', 'custom']
|
|
for bitset_name, bitset in self.bitsets.items():
|
|
if bitset.extends is not None:
|
|
assert bitset.extends in self.bitsets, "{} extends invalid type: {}".format(
|
|
bitset_name, bitset.extends)
|
|
for case in bitset.cases:
|
|
for field_name, field in case.fields.items():
|
|
if field.type == 'float':
|
|
assert field.get_size() == 32 or field.get_size() == 16
|
|
|
|
if not isinstance(field, BitSetDerivedField):
|
|
assert field.high < bitset.get_size(), \
|
|
"{}.{}: invalid bit range: [{}, {}] is not in [{}, {}]".format(
|
|
bitset_name, field_name, field.low, field.high, 0, bitset.get_size() - 1)
|
|
|
|
if field.type in builtin_types:
|
|
continue
|
|
if field.type in self.enums:
|
|
continue
|
|
assert field.type in self.bitsets, "{}.{}: invalid type: {}".format(
|
|
bitset_name, field_name, field.type)
|
|
bs = self.bitsets[field.type]
|
|
assert field.get_size() == bs.get_size(), "{}.{}: invalid size: {} vs {}".format(
|
|
bitset_name, field_name, field.get_size(), bs.get_size())
|
|
|
|
# Validate that all the leaf node bitsets have no remaining
|
|
# undefined bits
|
|
for name, bitsets in self.leafs.items():
|
|
for bitset in bitsets:
|
|
pat = bitset.get_pattern()
|
|
sz = bitset.get_size()
|
|
assert ((pat.mask | pat.field_mask) == (1 << sz) - 1), "leaf bitset {} has undefined bits: {:x}".format(
|
|
bitset.name, ~(pat.mask | pat.field_mask) & ((1 << sz) - 1))
|
|
|
|
# TODO somehow validating that only one bitset in a hierarchy
|
|
# matches any given bit pattern would be useful.
|
|
|
|
# TODO we should probably be able to look at the contexts where
|
|
# an expression is evaluated and verify that it doesn't have any
|
|
# {VARNAME} references that would be unresolved at evaluation time
|
|
|
|
def format(self):
|
|
''' Generate format string used by printf(..) and friends '''
|
|
parts = []
|
|
words = self.bitsize / 32
|
|
|
|
for i in range(int(words)):
|
|
parts.append('%08x')
|
|
|
|
fmt = ''.join(parts)
|
|
|
|
return f"\"{fmt[1:]}\""
|
|
|
|
def value(self):
|
|
''' Generate format values used by printf(..) and friends '''
|
|
parts = []
|
|
words = self.bitsize / 32
|
|
|
|
for i in range(int(words) - 1, -1, -1):
|
|
parts.append('v[' + str(i) + ']')
|
|
|
|
return ', '.join(parts)
|
|
|
|
def split_bits(self, value, bitsize):
|
|
''' Split `value` into a list of bitsize-bit integers '''
|
|
mask, parts = (1 << bitsize) - 1, []
|
|
words = self.bitsize / bitsize
|
|
|
|
while value:
|
|
parts.append(hex(value & mask))
|
|
value >>= bitsize
|
|
|
|
# Add 'missing' words
|
|
while len(parts) < words:
|
|
parts.append('0x0')
|
|
|
|
return parts
|
|
|
|
# Returns all bitsets in the ISA, including all per-gen variants, in
|
|
# (name, bitset) pairs.
|
|
def all_bitsets(self):
|
|
for name, bitset in self.bitsets.items():
|
|
yield name, bitset
|
|
for name, bitsets in self.leafs.items():
|
|
if len(bitsets) == 1:
|
|
continue
|
|
for bitset in bitsets:
|
|
yield name, bitset
|
|
|
|
def resolve_templates(self, display_string):
|
|
matches = re.findall(r'\{([^\}]+)\}', display_string)
|
|
for m in matches:
|
|
if m in self.templates:
|
|
display_string = display_string.replace("{" + m + "}", self.templates[m].display)
|
|
|
|
return display_string
|
|
|
|
def instructions(self):
|
|
instr = []
|
|
|
|
for _, root in self.roots.items():
|
|
for _, leafs in self.leafs.items():
|
|
for leaf in leafs:
|
|
if leaf.get_root() == root:
|
|
if not leaf.get_c_name().startswith('__'):
|
|
instr.append(leaf)
|
|
|
|
return instr
|