isa_parser: move the operand map stuff into the ISAParser class.
This commit is contained in:
parent
4db57edade
commit
629e8df196
1 changed files with 152 additions and 151 deletions
|
@ -157,7 +157,7 @@ class Template(object):
|
|||
snippetLabels = [l for l in labelRE.findall(template)
|
||||
if d.snippets.has_key(l)]
|
||||
|
||||
snippets = dict([(s, mungeSnippet(d.snippets[s]))
|
||||
snippets = dict([(s, self.parser.mungeSnippet(d.snippets[s]))
|
||||
for s in snippetLabels])
|
||||
|
||||
myDict.update(snippets)
|
||||
|
@ -168,7 +168,7 @@ class Template(object):
|
|||
# operands explicitly (like Mem)
|
||||
compositeCode += ' ' + template
|
||||
|
||||
operands = SubOperandList(compositeCode, d.operands)
|
||||
operands = SubOperandList(self.parser, compositeCode, d.operands)
|
||||
|
||||
myDict['op_decl'] = operands.concatAttrStrings('op_decl')
|
||||
|
||||
|
@ -380,34 +380,6 @@ def makeList(arg):
|
|||
else:
|
||||
return [ arg ]
|
||||
|
||||
# Generate operandTypeMap from the user's 'def operand_types'
|
||||
# statement.
|
||||
def buildOperandTypeMap(user_dict, lineno):
|
||||
global operandTypeMap
|
||||
operandTypeMap = {}
|
||||
for (ext, (desc, size)) in user_dict.iteritems():
|
||||
if desc == 'signed int':
|
||||
ctype = 'int%d_t' % size
|
||||
is_signed = 1
|
||||
elif desc == 'unsigned int':
|
||||
ctype = 'uint%d_t' % size
|
||||
is_signed = 0
|
||||
elif desc == 'float':
|
||||
is_signed = 1 # shouldn't really matter
|
||||
if size == 32:
|
||||
ctype = 'float'
|
||||
elif size == 64:
|
||||
ctype = 'double'
|
||||
elif desc == 'twin64 int':
|
||||
is_signed = 0
|
||||
ctype = 'Twin64_t'
|
||||
elif desc == 'twin32 int':
|
||||
is_signed = 0
|
||||
ctype = 'Twin32_t'
|
||||
if ctype == '':
|
||||
error(lineno, 'Unrecognized type description "%s" in user_dict')
|
||||
operandTypeMap[ext] = (size, ctype, is_signed)
|
||||
|
||||
class Operand(object):
|
||||
'''Base class for operand descriptors. An instance of this class
|
||||
(or actually a class derived from this one) represents a specific
|
||||
|
@ -448,7 +420,7 @@ class Operand(object):
|
|||
if (traceData) { traceData->setData(final_val); }
|
||||
}''' % (self.dflt_ctype, final_val, code)
|
||||
|
||||
def __init__(self, full_name, ext, is_src, is_dest):
|
||||
def __init__(self, parser, full_name, ext, is_src, is_dest):
|
||||
self.full_name = full_name
|
||||
self.ext = ext
|
||||
self.is_src = is_src
|
||||
|
@ -460,7 +432,8 @@ class Operand(object):
|
|||
else:
|
||||
self.eff_ext = self.dflt_ext
|
||||
|
||||
(self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext]
|
||||
self.size, self.ctype, self.is_signed = \
|
||||
parser.operandTypeMap[self.eff_ext]
|
||||
|
||||
# note that mem_acc_size is undefined for non-mem operands...
|
||||
# template must be careful not to use it if it doesn't apply.
|
||||
|
@ -770,91 +743,6 @@ class NNPCOperand(Operand):
|
|||
return self.buildWriteCode('setNextNPC')
|
||||
return 'xc->setNextNPC(%s);\n' % self.base_name
|
||||
|
||||
def buildOperandNameMap(user_dict, lineno):
|
||||
global operandNameMap
|
||||
operandNameMap = {}
|
||||
for (op_name, val) in user_dict.iteritems():
|
||||
(base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val[:5]
|
||||
if len(val) > 5:
|
||||
read_code = val[5]
|
||||
else:
|
||||
read_code = None
|
||||
if len(val) > 6:
|
||||
write_code = val[6]
|
||||
else:
|
||||
write_code = None
|
||||
if len(val) > 7:
|
||||
error(lineno,
|
||||
'error: too many attributes for operand "%s"' %
|
||||
base_cls_name)
|
||||
|
||||
(dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext]
|
||||
# Canonical flag structure is a triple of lists, where each list
|
||||
# indicates the set of flags implied by this operand always, when
|
||||
# used as a source, and when used as a dest, respectively.
|
||||
# For simplicity this can be initialized using a variety of fairly
|
||||
# obvious shortcuts; we convert these to canonical form here.
|
||||
if not flags:
|
||||
# no flags specified (e.g., 'None')
|
||||
flags = ( [], [], [] )
|
||||
elif isinstance(flags, str):
|
||||
# a single flag: assumed to be unconditional
|
||||
flags = ( [ flags ], [], [] )
|
||||
elif isinstance(flags, list):
|
||||
# a list of flags: also assumed to be unconditional
|
||||
flags = ( flags, [], [] )
|
||||
elif isinstance(flags, tuple):
|
||||
# it's a tuple: it should be a triple,
|
||||
# but each item could be a single string or a list
|
||||
(uncond_flags, src_flags, dest_flags) = flags
|
||||
flags = (makeList(uncond_flags),
|
||||
makeList(src_flags), makeList(dest_flags))
|
||||
# Accumulate attributes of new operand class in tmp_dict
|
||||
tmp_dict = {}
|
||||
for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri',
|
||||
'dflt_size', 'dflt_ctype', 'dflt_is_signed',
|
||||
'read_code', 'write_code'):
|
||||
tmp_dict[attr] = eval(attr)
|
||||
tmp_dict['base_name'] = op_name
|
||||
# New class name will be e.g. "IntReg_Ra"
|
||||
cls_name = base_cls_name + '_' + op_name
|
||||
# Evaluate string arg to get class object. Note that the
|
||||
# actual base class for "IntReg" is "IntRegOperand", i.e. we
|
||||
# have to append "Operand".
|
||||
try:
|
||||
base_cls = eval(base_cls_name + 'Operand')
|
||||
except NameError:
|
||||
if debug:
|
||||
raise
|
||||
error(lineno,
|
||||
'error: unknown operand base class "%s"' % base_cls_name)
|
||||
# The following statement creates a new class called
|
||||
# <cls_name> as a subclass of <base_cls> with the attributes
|
||||
# in tmp_dict, just as if we evaluated a class declaration.
|
||||
operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict)
|
||||
|
||||
# Define operand variables.
|
||||
operands = user_dict.keys()
|
||||
|
||||
operandsREString = (r'''
|
||||
(?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
|
||||
((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
|
||||
(?![\w\.]) # neg. lookahead assertion: prevent partial matches
|
||||
'''
|
||||
% string.join(operands, '|'))
|
||||
|
||||
global operandsRE
|
||||
operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
|
||||
|
||||
# Same as operandsREString, but extension is mandatory, and only two
|
||||
# groups are returned (base and ext, not full name as above).
|
||||
# Used for subtituting '_' for '.' to make C++ identifiers.
|
||||
operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])'
|
||||
% string.join(operands, '|'))
|
||||
|
||||
global operandsWithExtRE
|
||||
operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
|
||||
|
||||
class OperandList(object):
|
||||
'''Find all the operands in the given code block. Returns an operand
|
||||
descriptor list (instance of class OperandList).'''
|
||||
|
@ -866,7 +754,7 @@ class OperandList(object):
|
|||
# search for operands
|
||||
next_pos = 0
|
||||
while 1:
|
||||
match = operandsRE.search(code, next_pos)
|
||||
match = parser.operandsRE.search(code, next_pos)
|
||||
if not match:
|
||||
# no more matches: we're done
|
||||
break
|
||||
|
@ -887,8 +775,8 @@ class OperandList(object):
|
|||
op_desc.is_dest = op_desc.is_dest or is_dest
|
||||
else:
|
||||
# new operand: create new descriptor
|
||||
op_desc = operandNameMap[op_base](op_full, op_ext,
|
||||
is_src, is_dest)
|
||||
op_desc = parser.operandNameMap[op_base](parser,
|
||||
op_full, op_ext, is_src, is_dest)
|
||||
self.append(op_desc)
|
||||
# start next search after end of current match
|
||||
next_pos = match.end()
|
||||
|
@ -973,7 +861,7 @@ class OperandList(object):
|
|||
class SubOperandList(OperandList):
|
||||
'''Find all the operands in the given code block. Returns an operand
|
||||
descriptor list (instance of class OperandList).'''
|
||||
def __init__(self, code, master_list):
|
||||
def __init__(self, parser, code, master_list):
|
||||
self.items = []
|
||||
self.bases = {}
|
||||
# delete comments so we don't match on reg specifiers inside
|
||||
|
@ -981,7 +869,7 @@ class SubOperandList(OperandList):
|
|||
# search for operands
|
||||
next_pos = 0
|
||||
while 1:
|
||||
match = operandsRE.search(code, next_pos)
|
||||
match = parser.operandsRE.search(code, next_pos)
|
||||
if not match:
|
||||
# no more matches: we're done
|
||||
break
|
||||
|
@ -1018,19 +906,6 @@ commentRE = re.compile(r'//.*\n')
|
|||
# (used in findOperands())
|
||||
assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
|
||||
|
||||
# Munge operand names in code string to make legal C++ variable names.
|
||||
# This means getting rid of the type extension if any.
|
||||
# (Will match base_name attribute of Operand object.)
|
||||
def substMungedOpNames(code):
|
||||
return operandsWithExtRE.sub(r'\1', code)
|
||||
|
||||
# Fix up code snippets for final substitution in templates.
|
||||
def mungeSnippet(s):
|
||||
if isinstance(s, str):
|
||||
return substMungedOpNames(substBitOps(s))
|
||||
else:
|
||||
return s
|
||||
|
||||
def makeFlagConstructor(flag_list):
|
||||
if len(flag_list) == 0:
|
||||
return ''
|
||||
|
@ -1128,13 +1003,6 @@ class Stack(list):
|
|||
def top(self):
|
||||
return self[-1]
|
||||
|
||||
# Global stack that tracks current file and line number.
|
||||
# Each element is a tuple (filename, lineno) that records the
|
||||
# *current* filename and the line number in the *previous* file where
|
||||
# it was included.
|
||||
fileNameStack = Stack()
|
||||
|
||||
|
||||
#######################
|
||||
#
|
||||
# Output file template
|
||||
|
@ -1195,6 +1063,12 @@ class ISAParser(Grammar):
|
|||
# The default case stack.
|
||||
self.defaultStack = Stack(None)
|
||||
|
||||
# Stack that tracks current file and line number. Each
|
||||
# element is a tuple (filename, lineno) that records the
|
||||
# *current* filename and the line number in the *previous*
|
||||
# file where it was included.
|
||||
self.fileNameStack = Stack()
|
||||
|
||||
symbols = ('makeList', 're', 'string')
|
||||
self.exportContext = dict([(s, eval(s)) for s in symbols])
|
||||
|
||||
|
@ -1322,12 +1196,12 @@ class ISAParser(Grammar):
|
|||
|
||||
def t_NEWFILE(self, t):
|
||||
r'^\#\#newfile\s+"[\w/.-]*"'
|
||||
fileNameStack.push((t.value[11:-1], t.lexer.lineno))
|
||||
self.fileNameStack.push((t.value[11:-1], t.lexer.lineno))
|
||||
t.lexer.lineno = 0
|
||||
|
||||
def t_ENDFILE(self, t):
|
||||
r'^\#\#endfile'
|
||||
(old_filename, t.lexer.lineno) = fileNameStack.pop()
|
||||
(old_filename, t.lexer.lineno) = self.fileNameStack.pop()
|
||||
|
||||
#
|
||||
# The functions t_NEWLINE, t_ignore, and t_error are
|
||||
|
@ -1489,14 +1363,14 @@ StaticInstPtr
|
|||
raise
|
||||
error(t,
|
||||
'error: %s in def operand_types block "%s".' % (exc, t[3]))
|
||||
buildOperandTypeMap(user_dict, t.lexer.lineno)
|
||||
self.buildOperandTypeMap(user_dict, t.lexer.lineno)
|
||||
t[0] = GenCode(self) # contributes nothing to the output C++ file
|
||||
|
||||
# Define the mapping from operand names to operand classes and
|
||||
# other traits. Stored in operandNameMap.
|
||||
def p_def_operands(self, t):
|
||||
'def_operands : DEF OPERANDS CODELIT SEMI'
|
||||
if not globals().has_key('operandTypeMap'):
|
||||
if not hasattr(self, 'operandTypeMap'):
|
||||
error(t, 'error: operand types must be defined before operands')
|
||||
try:
|
||||
user_dict = eval('{' + t[3] + '}', self.exportContext)
|
||||
|
@ -1504,7 +1378,7 @@ StaticInstPtr
|
|||
if debug:
|
||||
raise
|
||||
error(t, 'error: %s in def operands block "%s".' % (exc, t[3]))
|
||||
buildOperandNameMap(user_dict, t.lexer.lineno)
|
||||
self.buildOperandNameMap(user_dict, t.lexer.lineno)
|
||||
t[0] = GenCode(self) # contributes nothing to the output C++ file
|
||||
|
||||
# A bitfield definition looks like:
|
||||
|
@ -1950,6 +1824,133 @@ StaticInstPtr
|
|||
|
||||
return re.sub(r'%(?!\()', '%%', s)
|
||||
|
||||
def buildOperandTypeMap(self, user_dict, lineno):
|
||||
"""Generate operandTypeMap from the user's 'def operand_types'
|
||||
statement."""
|
||||
operand_type = {}
|
||||
for (ext, (desc, size)) in user_dict.iteritems():
|
||||
if desc == 'signed int':
|
||||
ctype = 'int%d_t' % size
|
||||
is_signed = 1
|
||||
elif desc == 'unsigned int':
|
||||
ctype = 'uint%d_t' % size
|
||||
is_signed = 0
|
||||
elif desc == 'float':
|
||||
is_signed = 1 # shouldn't really matter
|
||||
if size == 32:
|
||||
ctype = 'float'
|
||||
elif size == 64:
|
||||
ctype = 'double'
|
||||
elif desc == 'twin64 int':
|
||||
is_signed = 0
|
||||
ctype = 'Twin64_t'
|
||||
elif desc == 'twin32 int':
|
||||
is_signed = 0
|
||||
ctype = 'Twin32_t'
|
||||
if ctype == '':
|
||||
error(parser, lineno,
|
||||
'Unrecognized type description "%s" in user_dict')
|
||||
operand_type[ext] = (size, ctype, is_signed)
|
||||
|
||||
self.operandTypeMap = operand_type
|
||||
|
||||
def buildOperandNameMap(self, user_dict, lineno):
|
||||
operand_name = {}
|
||||
for op_name, val in user_dict.iteritems():
|
||||
base_cls_name, dflt_ext, reg_spec, flags, sort_pri = val[:5]
|
||||
if len(val) > 5:
|
||||
read_code = val[5]
|
||||
else:
|
||||
read_code = None
|
||||
if len(val) > 6:
|
||||
write_code = val[6]
|
||||
else:
|
||||
write_code = None
|
||||
if len(val) > 7:
|
||||
error(lineno,
|
||||
'error: too many attributes for operand "%s"' %
|
||||
base_cls_name)
|
||||
|
||||
(dflt_size, dflt_ctype, dflt_is_signed) = \
|
||||
self.operandTypeMap[dflt_ext]
|
||||
# Canonical flag structure is a triple of lists, where each list
|
||||
# indicates the set of flags implied by this operand always, when
|
||||
# used as a source, and when used as a dest, respectively.
|
||||
# For simplicity this can be initialized using a variety of fairly
|
||||
# obvious shortcuts; we convert these to canonical form here.
|
||||
if not flags:
|
||||
# no flags specified (e.g., 'None')
|
||||
flags = ( [], [], [] )
|
||||
elif isinstance(flags, str):
|
||||
# a single flag: assumed to be unconditional
|
||||
flags = ( [ flags ], [], [] )
|
||||
elif isinstance(flags, list):
|
||||
# a list of flags: also assumed to be unconditional
|
||||
flags = ( flags, [], [] )
|
||||
elif isinstance(flags, tuple):
|
||||
# it's a tuple: it should be a triple,
|
||||
# but each item could be a single string or a list
|
||||
(uncond_flags, src_flags, dest_flags) = flags
|
||||
flags = (makeList(uncond_flags),
|
||||
makeList(src_flags), makeList(dest_flags))
|
||||
# Accumulate attributes of new operand class in tmp_dict
|
||||
tmp_dict = {}
|
||||
for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri',
|
||||
'dflt_size', 'dflt_ctype', 'dflt_is_signed',
|
||||
'read_code', 'write_code'):
|
||||
tmp_dict[attr] = eval(attr)
|
||||
tmp_dict['base_name'] = op_name
|
||||
# New class name will be e.g. "IntReg_Ra"
|
||||
cls_name = base_cls_name + '_' + op_name
|
||||
# Evaluate string arg to get class object. Note that the
|
||||
# actual base class for "IntReg" is "IntRegOperand", i.e. we
|
||||
# have to append "Operand".
|
||||
try:
|
||||
base_cls = eval(base_cls_name + 'Operand')
|
||||
except NameError:
|
||||
error(lineno,
|
||||
'error: unknown operand base class "%s"' % base_cls_name)
|
||||
# The following statement creates a new class called
|
||||
# <cls_name> as a subclass of <base_cls> with the attributes
|
||||
# in tmp_dict, just as if we evaluated a class declaration.
|
||||
operand_name[op_name] = type(cls_name, (base_cls,), tmp_dict)
|
||||
|
||||
self.operandNameMap = operand_name
|
||||
|
||||
# Define operand variables.
|
||||
operands = user_dict.keys()
|
||||
|
||||
operandsREString = (r'''
|
||||
(?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
|
||||
((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
|
||||
(?![\w\.]) # neg. lookahead assertion: prevent partial matches
|
||||
'''
|
||||
% string.join(operands, '|'))
|
||||
|
||||
self.operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
|
||||
|
||||
# Same as operandsREString, but extension is mandatory, and only two
|
||||
# groups are returned (base and ext, not full name as above).
|
||||
# Used for subtituting '_' for '.' to make C++ identifiers.
|
||||
operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])'
|
||||
% string.join(operands, '|'))
|
||||
|
||||
self.operandsWithExtRE = \
|
||||
re.compile(operandsWithExtREString, re.MULTILINE)
|
||||
|
||||
def substMungedOpNames(self, code):
|
||||
'''Munge operand names in code string to make legal C++
|
||||
variable names. This means getting rid of the type extension
|
||||
if any. Will match base_name attribute of Operand object.)'''
|
||||
return self.operandsWithExtRE.sub(r'\1', code)
|
||||
|
||||
def mungeSnippet(self, s):
|
||||
'''Fix up code snippets for final substitution in templates.'''
|
||||
if isinstance(s, str):
|
||||
return self.substMungedOpNames(substBitOps(s))
|
||||
else:
|
||||
return s
|
||||
|
||||
def update_if_needed(self, file, contents):
|
||||
'''Update the output file only if the new contents are
|
||||
different from the current contents. Minimizes the files that
|
||||
|
@ -2001,14 +2002,14 @@ StaticInstPtr
|
|||
except IOError:
|
||||
error('Error including file "%s"' % filename)
|
||||
|
||||
fileNameStack.push((filename, 0))
|
||||
self.fileNameStack.push((filename, 0))
|
||||
|
||||
# Find any includes and include them
|
||||
def replace(matchobj):
|
||||
return self.replace_include(matchobj, current_dir)
|
||||
contents = self.includeRE.sub(replace, contents)
|
||||
|
||||
fileNameStack.pop()
|
||||
self.fileNameStack.pop()
|
||||
return contents
|
||||
|
||||
def _parse_isa_desc(self, isa_desc_file):
|
||||
|
@ -2020,7 +2021,7 @@ StaticInstPtr
|
|||
isa_desc = self.read_and_flatten(isa_desc_file)
|
||||
|
||||
# Initialize filename stack with outer file.
|
||||
fileNameStack.push((isa_desc_file, 0))
|
||||
self.fileNameStack.push((isa_desc_file, 0))
|
||||
|
||||
# Parse it.
|
||||
(isa_name, namespace, global_code, namespace_code) = \
|
||||
|
@ -2067,7 +2068,7 @@ StaticInstPtr
|
|||
try:
|
||||
self._parse_isa_desc(*args, **kwargs)
|
||||
except ISAParserError, e:
|
||||
e.exit(fileNameStack)
|
||||
e.exit(self.fileNameStack)
|
||||
|
||||
# Called as script: get args from command line.
|
||||
# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models>
|
||||
|
|
Loading…
Reference in a new issue