summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/arch/isa_parser.py303
1 files changed, 152 insertions, 151 deletions
diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py
index 9590e2453..282010429 100755
--- a/src/arch/isa_parser.py
+++ b/src/arch/isa_parser.py
@@ -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>