# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Steve Reinhardt
-# Korey Sewell
import os
import sys
# of 'build' in the current tree.
sys.path[0:0] = [os.environ['M5_PLY']]
-import lex
-import yacc
+from ply import lex
+from ply import yacc
#####################################################################
#
t_DOT = r'\.'
t_COLON = r':'
t_DBLCOLON = r'::'
-t_ASTERISK = r'\*'
+t_ASTERISK = r'\*'
# Identifiers and reserved words
reserved_map = { }
try:
t.value = int(t.value,0)
except ValueError:
- error(t.lineno, 'Integer value "%s" too large' % t.value)
+ error(t.lexer.lineno, 'Integer value "%s" too large' % t.value)
t.value = 0
return t
r"(?m)'([^'])+'"
# strip off quotes
t.value = t.value[1:-1]
- t.lineno += t.value.count('\n')
+ t.lexer.lineno += t.value.count('\n')
return t
r"(?m)\{\{([^\}]|}(?!\}))+\}\}"
# strip off {{ & }}
t.value = t.value[2:-2]
- t.lineno += t.value.count('\n')
+ t.lexer.lineno += t.value.count('\n')
return t
def t_CPPDIRECTIVE(t):
r'^\#[^\#].*\n'
- t.lineno += t.value.count('\n')
+ t.lexer.lineno += t.value.count('\n')
return t
def t_NEWFILE(t):
r'^\#\#newfile\s+"[\w/.-]*"'
- fileNameStack.push((t.value[11:-1], t.lineno))
- t.lineno = 0
+ fileNameStack.push((t.value[11:-1], t.lexer.lineno))
+ t.lexer.lineno = 0
def t_ENDFILE(t):
r'^\#\#endfile'
- (old_filename, t.lineno) = fileNameStack.pop()
+ (old_filename, t.lexer.lineno) = fileNameStack.pop()
#
# The functions t_NEWLINE, t_ignore, and t_error are
# Newlines
def t_NEWLINE(t):
r'\n+'
- t.lineno += t.value.count('\n')
+ t.lexer.lineno += t.value.count('\n')
# Comments
def t_comment(t):
# Error handler
def t_error(t):
- error(t.lineno, "illegal character '%s'" % t.value[0])
+ error(t.lexer.lineno, "illegal character '%s'" % t.value[0])
t.skip(1)
# Build the lexer
-lex.lex()
+lexer = lex.lex()
#####################################################################
#
try:
exec fixPythonIndentation(t[2]) in exportContext
except Exception, exc:
- error(t.lineno(1),
+ error(t.lexer.lineno,
'error: %s in global let block "%s".' % (exc, t[2]))
t[0] = GenCode(header_output = exportContext["header_output"],
decoder_output = exportContext["decoder_output"],
try:
userDict = eval('{' + t[3] + '}')
except Exception, exc:
- error(t.lineno(1),
+ error(t.lexer.lineno,
'error: %s in def operand_types block "%s".' % (exc, t[3]))
- buildOperandTypeMap(userDict, t.lineno(1))
+ buildOperandTypeMap(userDict, t.lexer.lineno)
t[0] = GenCode() # contributes nothing to the output C++ file
# Define the mapping from operand names to operand classes and other
def p_def_operands(t):
'def_operands : DEF OPERANDS CODELIT SEMI'
if not globals().has_key('operandTypeMap'):
- error(t.lineno(1),
+ error(t.lexer.lineno,
'error: operand types must be defined before operands')
try:
- userDict = eval('{' + t[3] + '}')
+ userDict = eval('{' + t[3] + '}', exportContext)
except Exception, exc:
- error(t.lineno(1),
+ error(t.lexer.lineno,
'error: %s in def operands block "%s".' % (exc, t[3]))
- buildOperandNameMap(userDict, t.lineno(1))
+ buildOperandNameMap(userDict, t.lexer.lineno)
t[0] = GenCode() # contributes nothing to the output C++ file
# A bitfield definition looks like:
def p_def_bitfield_struct(t):
'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
if (t[2] != ''):
- error(t.lineno(1), 'error: structure bitfields are always unsigned.')
+ error(t.lexer.lineno, 'error: structure bitfields are always unsigned.')
expr = 'machInst.%s' % t[5]
hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
t[0] = GenCode(header_output = hash_define)
def p_def_format(t):
'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
(id, params, code) = (t[3], t[5], t[7])
- defFormat(id, params, code, t.lineno(1))
+ defFormat(id, params, code, t.lexer.lineno)
t[0] = GenCode()
# The formal parameter list for an instruction format is a possibly
#
# A decode block looks like:
-# decode <field1> [, <field2>]* [default <inst>] { ... }
+# decode <field1> [, <field2>]* [default <inst>] { ... }
#
def p_decode_block(t):
'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
def p_decode_stmt_list_1(t):
'decode_stmt_list : decode_stmt decode_stmt_list'
if (t[1].has_decode_default and t[2].has_decode_default):
- error(t.lineno(1), 'Two default cases in decode block')
+ error(t.lexer.lineno, 'Two default cases in decode block')
t[0] = t[1] + t[2]
#
formatStack.push(formatMap[t[1]])
t[0] = ('', '// format %s' % t[1])
except KeyError:
- error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
+ error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])
# Nested decode block: if the value of the current field matches the
# specified constant, do a nested decode on some other field.
'inst : ID LPAREN arg_list RPAREN'
# Pass the ID and arg list to the current format class to deal with.
currentFormat = formatStack.top()
- codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
+ codeObj = currentFormat.defineInst(t[1], t[3], t.lexer.lineno)
args = ','.join(map(str, t[3]))
args = re.sub('(?m)^', '//', args)
args = re.sub('^//', '', args)
try:
format = formatMap[t[1]]
except KeyError:
- error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
- codeObj = format.defineInst(t[3], t[5], t.lineno(1))
+ error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])
+ codeObj = format.defineInst(t[3], t[5], t.lexer.lineno)
comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
codeObj.prepend_all(comment)
t[0] = codeObj
# *token*, not a grammar symbol (hence the need to use t.value)
def p_error(t):
if t:
- error(t.lineno, "syntax error at '%s'" % t.value)
+ error(t.lexer.lineno, "syntax error at '%s'" % t.value)
else:
error(0, "unknown syntax error", True)
# END OF GRAMMAR RULES
#
# Now build the parser.
-yacc.yacc()
+parser = yacc.yacc()
#####################################################################
context = {}
updateExportContext()
context.update(exportContext)
- context.update({ 'name': name, 'Name': string.capitalize(name) })
+ if len(name):
+ Name = name[0].upper()
+ if len(name) > 1:
+ Name += name[1:]
+ context.update({ 'name': name, 'Name': Name })
try:
vars = self.func(self.user_code, context, *args[0], **args[1])
except Exception, exc:
# Template objects are format strings that allow substitution from
# the attribute spaces of other objects (e.g. InstObjParams instances).
-labelRE = re.compile(r'[^%]%\(([^\)]+)\)[sd]')
+labelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]')
class Template:
def __init__(self, t):
ctype = 'uint%d_t' % size
is_signed = 0
elif desc == 'float':
- is_signed = 1 # shouldn't really matter
+ is_signed = 1 # shouldn't really matter
if size == 32:
ctype = 'float'
elif size == 64:
# (e.g., "32-bit integer register").
#
class Operand(object):
+ def buildReadCode(self, func = None):
+ code = self.read_code % {"name": self.base_name,
+ "func": func,
+ "op_idx": self.src_reg_idx,
+ "reg_idx": self.reg_spec,
+ "size": self.size,
+ "ctype": self.ctype}
+ if self.size != self.dflt_size:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (self.base_name, code, self.size-1)
+ else:
+ return '%s = %s;\n' % \
+ (self.base_name, code)
+
+ def buildWriteCode(self, func = None):
+ if (self.size != self.dflt_size and self.is_signed):
+ final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
+ else:
+ final_val = self.base_name
+ code = self.write_code % {"name": self.base_name,
+ "func": func,
+ "op_idx": self.dest_reg_idx,
+ "reg_idx": self.reg_spec,
+ "size": self.size,
+ "ctype": self.ctype,
+ "final_val": final_val}
+ return '''
+ {
+ %s final_val = %s;
+ %s;
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (self.dflt_ctype, final_val, code)
+
def __init__(self, full_name, ext, is_src, is_dest):
self.full_name = full_name
self.ext = ext
def makeRead(self):
if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to read integer register as FP')
+ if self.read_code != None:
+ return self.buildReadCode('readIntRegOperand')
if (self.size == self.dflt_size):
return '%s = xc->readIntRegOperand(this, %d);\n' % \
(self.base_name, self.src_reg_idx)
def makeWrite(self):
if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to write integer register as FP')
+ if self.write_code != None:
+ return self.buildWriteCode('setIntRegOperand')
if (self.size != self.dflt_size and self.is_signed):
final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
else:
def makeRead(self):
bit_select = 0
- width = 0;
- if (self.ctype == 'float'):
- func = 'readFloatRegOperand'
- width = 32;
- elif (self.ctype == 'double'):
+ if (self.ctype == 'float' or self.ctype == 'double'):
func = 'readFloatRegOperand'
- width = 64;
else:
func = 'readFloatRegOperandBits'
- if (self.ctype == 'uint32_t'):
- width = 32;
- elif (self.ctype == 'uint64_t'):
- width = 64;
if (self.size != self.dflt_size):
bit_select = 1
- if width:
- base = 'xc->%s(this, %d, %d)' % \
- (func, self.src_reg_idx, width)
- else:
- base = 'xc->%s(this, %d)' % \
- (func, self.src_reg_idx)
+ base = 'xc->%s(this, %d)' % (func, self.src_reg_idx)
+ if self.read_code != None:
+ return self.buildReadCode(func)
if bit_select:
return '%s = bits(%s, %d, 0);\n' % \
(self.base_name, base, self.size-1)
def makeWrite(self):
final_val = self.base_name
final_ctype = self.ctype
- widthSpecifier = ''
- width = 0
- if (self.ctype == 'float'):
- width = 32
- func = 'setFloatRegOperand'
- elif (self.ctype == 'double'):
- width = 64
+ if (self.ctype == 'float' or self.ctype == 'double'):
func = 'setFloatRegOperand'
- elif (self.ctype == 'uint32_t'):
- func = 'setFloatRegOperandBits'
- width = 32
- elif (self.ctype == 'uint64_t'):
+ elif (self.ctype == 'uint32_t' or self.ctype == 'uint64_t'):
func = 'setFloatRegOperandBits'
- width = 64
else:
func = 'setFloatRegOperandBits'
final_ctype = 'uint%d_t' % self.dflt_size
if (self.size != self.dflt_size and self.is_signed):
final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
- if width:
- widthSpecifier = ', %d' % width
+ if self.write_code != None:
+ return self.buildWriteCode(func)
wb = '''
{
%s final_val = %s;
- xc->%s(this, %d, final_val%s);\n
+ xc->%s(this, %d, final_val);\n
if (traceData) { traceData->setData(final_val); }
- }''' % (final_ctype, final_val, func, self.dest_reg_idx,
- widthSpecifier)
+ }''' % (final_ctype, final_val, func, self.dest_reg_idx)
return wb
class ControlRegOperand(Operand):
bit_select = 0
if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to read control register as FP')
+ if self.read_code != None:
+ return self.buildReadCode('readMiscRegOperand')
base = 'xc->readMiscRegOperand(this, %s)' % self.src_reg_idx
if self.size == self.dflt_size:
return '%s = %s;\n' % (self.base_name, base)
def makeWrite(self):
if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to write control register as FP')
+ if self.write_code != None:
+ return self.buildWriteCode('setMiscRegOperand')
wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \
(self.dest_reg_idx, self.base_name)
wb += 'if (traceData) { traceData->setData(%s); }' % \
return c
def makeRead(self):
+ if self.read_code != None:
+ return self.buildReadCode()
return ''
def makeWrite(self):
+ if self.write_code != None:
+ return self.buildWriteCode()
return ''
# Return the memory access size *in bits*, suitable for
def makeAccSize(self):
return self.size
+class UPCOperand(Operand):
+ def makeConstructor(self):
+ return ''
+
+ def makeRead(self):
+ if self.read_code != None:
+ return self.buildReadCode('readMicroPC')
+ return '%s = xc->readMicroPC();\n' % self.base_name
+
+ def makeWrite(self):
+ if self.write_code != None:
+ return self.buildWriteCode('setMicroPC')
+ return 'xc->setMicroPC(%s);\n' % self.base_name
+
+class NUPCOperand(Operand):
+ def makeConstructor(self):
+ return ''
+
+ def makeRead(self):
+ if self.read_code != None:
+ return self.buildReadCode('readNextMicroPC')
+ return '%s = xc->readNextMicroPC();\n' % self.base_name
+
+ def makeWrite(self):
+ if self.write_code != None:
+ return self.buildWriteCode('setNextMicroPC')
+ return 'xc->setNextMicroPC(%s);\n' % self.base_name
class NPCOperand(Operand):
def makeConstructor(self):
return ''
def makeRead(self):
+ if self.read_code != None:
+ return self.buildReadCode('readNextPC')
return '%s = xc->readNextPC();\n' % self.base_name
def makeWrite(self):
+ if self.write_code != None:
+ return self.buildWriteCode('setNextPC')
return 'xc->setNextPC(%s);\n' % self.base_name
class NNPCOperand(Operand):
return ''
def makeRead(self):
+ if self.read_code != None:
+ return self.buildReadCode('readNextNPC')
return '%s = xc->readNextNPC();\n' % self.base_name
def makeWrite(self):
+ if self.write_code != None:
+ return self.buildWriteCode('setNextNPC')
return 'xc->setNextNPC(%s);\n' % self.base_name
def buildOperandNameMap(userDict, lineno):
global operandNameMap
operandNameMap = {}
for (op_name, val) in userDict.iteritems():
- (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val
+ (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
# 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'):
+ '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"
operands = userDict.keys()
operandsREString = (r'''
- (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
+ (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
- (?![\w\.]) # neg. lookahead assertion: prevent partial matches
+ (?![\w\.]) # neg. lookahead assertion: prevent partial matches
'''
% string.join(operands, '|'))
global operandsWithExtRE
operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
+maxInstSrcRegs = 0
+maxInstDestRegs = 0
class OperandList:
if self.memOperand:
error(0, "Code block has more than one memory operand.")
self.memOperand = op_desc
+ global maxInstSrcRegs
+ global maxInstDestRegs
+ if maxInstSrcRegs < self.numSrcRegs:
+ maxInstSrcRegs = self.numSrcRegs
+ if maxInstDestRegs < self.numDestRegs:
+ maxInstDestRegs = self.numDestRegs
# now make a final pass to finalize op_desc fields that may depend
# on the register enumeration
for op_desc in self.items:
%(decode_function)s
'''
+max_inst_regs_template = '''
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from the ISA description in %(filename)s
+ */
+
+namespace %(namespace)s {
+
+ const int MaxInstSrcRegs = %(MaxInstSrcRegs)d;
+ const int MaxInstDestRegs = %(MaxInstDestRegs)d;
+
+} // namespace %(namespace)s
+
+'''
+
# Update the output file only if the new contents are different from
# the current contents. Minimizes the files that need to be rebuilt
fileNameStack.push((isa_desc_file, 0))
# Parse it.
- (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
+ (isa_name, namespace, global_code, namespace_code) = \
+ parser.parse(isa_desc, lexer=lexer)
# grab the last three path components of isa_desc_file to put in
# the output
update_if_needed(output_dir + '/' + cpu.filename,
file_template % vars())
+ # The variable names here are hacky, but this will creat local variables
+ # which will be referenced in vars() which have the value of the globals.
+ global maxInstSrcRegs
+ MaxInstSrcRegs = maxInstSrcRegs
+ global maxInstDestRegs
+ MaxInstDestRegs = maxInstDestRegs
+ # max_inst_regs.hh
+ update_if_needed(output_dir + '/max_inst_regs.hh', \
+ max_inst_regs_template % vars())
+
# global list of CpuModel objects (see cpu_models.py)
cpu_models = []