diff options
Diffstat (limited to 'arch/isa_parser.py')
-rwxr-xr-x | arch/isa_parser.py | 256 |
1 files changed, 124 insertions, 132 deletions
diff --git a/arch/isa_parser.py b/arch/isa_parser.py index 6a8935963..fffcc33e5 100755 --- a/arch/isa_parser.py +++ b/arch/isa_parser.py @@ -162,7 +162,7 @@ def t_CPPDIRECTIVE(t): return t def t_NEWFILE(t): - r'^\#\#newfile[ /t]*\"[A-Za-z0-9\\/-_.]*\"' + r'^\#\#newfile\s+"[\w/.-]*"' global fileNameStack fileNameStack.append((t.value[11:-1], t.lineno)) t.lineno = 0 @@ -841,7 +841,7 @@ defaultStack = Stack( None ) # Used to make nested code blocks look pretty. # def indent(s): - return re.sub(r'(?m)^(?!\#)', ' ', s) + return re.sub(r'(?m)^(?!#)', ' ', s) # # Munge a somewhat arbitrarily formatted piece of Python code @@ -868,17 +868,21 @@ def fixPythonIndentation(s): return s # Error handler. Just call exit. Output formatted to work under -# Emacs compile-mode. +# Emacs compile-mode. This function should be called when errors due +# to user input are detected (as opposed to parser bugs). def error(lineno, string): - global fileNameStack spaces = "" for (filename, line) in fileNameStack[0:-1]: print spaces + "In file included from " + filename spaces += " " + # Uncomment the following line to get a Python stack backtrace for + # these errors too. Can be handy when trying to debug the parser. + # traceback.print_exc() sys.exit(spaces + "%s:%d: %s" % (fileNameStack[-1][0], lineno, string)) # Like error(), but include a Python stack backtrace (for processing -# Python exceptions). +# Python exceptions). This function should be called for errors that +# appear to be bugs in the parser itself. def error_bt(lineno, string): traceback.print_exc() print >> sys.stderr, "%s:%d: %s" % (input_filename, lineno, string) @@ -1068,7 +1072,7 @@ class OperandTraits: (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] # Note that initializations in the declarations are solely # to avoid 'uninitialized variable' errors from the compiler. - return type + ' ' + op_desc.munged_name + ' = 0;\n'; + return type + ' ' + op_desc.base_name + ' = 0;\n'; class IntRegOperandTraits(OperandTraits): def isReg(self): @@ -1093,19 +1097,19 @@ class IntRegOperandTraits(OperandTraits): error(0, 'Attempt to read integer register as FP') if (size == self.dflt_size): return '%s = xc->readIntReg(this, %d);\n' % \ - (op_desc.munged_name, op_desc.src_reg_idx) + (op_desc.base_name, op_desc.src_reg_idx) else: return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \ - (op_desc.munged_name, op_desc.src_reg_idx, size-1) + (op_desc.base_name, op_desc.src_reg_idx, size-1) def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] if (type == 'float' or type == 'double'): error(0, 'Attempt to write integer register as FP') if (size != self.dflt_size and is_signed): - final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name) + final_val = 'sext<%d>(%s)' % (size, op_desc.base_name) else: - final_val = op_desc.munged_name + final_val = op_desc.base_name wb = ''' { %s final_val = %s; @@ -1146,13 +1150,13 @@ class FloatRegOperandTraits(OperandTraits): (func, op_desc.src_reg_idx) if bit_select: return '%s = bits(%s, %d, 0);\n' % \ - (op_desc.munged_name, base, size-1) + (op_desc.base_name, base, size-1) else: - return '%s = %s;\n' % (op_desc.munged_name, base) + return '%s = %s;\n' % (op_desc.base_name, base) def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] - final_val = op_desc.munged_name + final_val = op_desc.base_name if (type == 'float'): func = 'setFloatRegSingle' elif (type == 'double'): @@ -1161,7 +1165,7 @@ class FloatRegOperandTraits(OperandTraits): func = 'setFloatRegInt' type = 'uint%d_t' % self.dflt_size if (size != self.dflt_size and is_signed): - final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name) + final_val = 'sext<%d>(%s)' % (size, op_desc.base_name) wb = ''' { %s final_val = %s; @@ -1194,18 +1198,18 @@ class ControlRegOperandTraits(OperandTraits): error(0, 'Attempt to read control register as FP') base = 'xc->read%s()' % self.reg_spec if size == self.dflt_size: - return '%s = %s;\n' % (op_desc.munged_name, base) + return '%s = %s;\n' % (op_desc.base_name, base) else: return '%s = bits(%s, %d, 0);\n' % \ - (op_desc.munged_name, base, size-1) + (op_desc.base_name, base, size-1) def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] if (type == 'float' or type == 'double'): error(0, 'Attempt to write control register as FP') - wb = 'xc->set%s(%s);\n' % (self.reg_spec, op_desc.munged_name) + wb = 'xc->set%s(%s);\n' % (self.reg_spec, op_desc.base_name) wb += 'if (traceData) { traceData->setData(%s); }' % \ - op_desc.munged_name + op_desc.base_name return wb class MemOperandTraits(OperandTraits): @@ -1220,41 +1224,30 @@ class MemOperandTraits(OperandTraits): # Note that initializations in the declarations are solely # to avoid 'uninitialized variable' errors from the compiler. # Declare memory data variable. - c = '%s %s = 0;\n' % (type, op_desc.munged_name) - # Declare var to hold memory access flags. - c += 'unsigned %s_flags = memAccessFlags;\n' % op_desc.base_name - # If this operand is a dest (i.e., it's a store operation), - # then we need to declare a variable for the write result code - # as well. - if op_desc.is_dest: - c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name + c = '%s %s = 0;\n' % (type, op_desc.base_name) return c def makeRead(self, op_desc): - (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] - eff_type = 'uint%d_t' % size - return 'fault = xc->read(EA, (%s&)%s, %s_flags);\n' \ - % (eff_type, op_desc.munged_name, op_desc.base_name) + return '' def makeWrite(self, op_desc): + return '' + + # Return the memory access size *in bits*, suitable for + # forming a type via "uint%d_t". Divide by 8 if you want bytes. + def makeAccSize(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] - eff_type = 'uint%d_t' % size - wb = 'fault = xc->write((%s&)%s, EA, %s_flags, &%s_write_result);\n' \ - % (eff_type, op_desc.munged_name, op_desc.base_name, - op_desc.base_name) - wb += 'if (traceData) { traceData->setData(%s); }' % \ - op_desc.munged_name - return wb + return size class NPCOperandTraits(OperandTraits): def makeConstructor(self, op_desc): return '' def makeRead(self, op_desc): - return '%s = xc->readPC() + 4;\n' % op_desc.munged_name + return '%s = xc->readPC() + 4;\n' % op_desc.base_name def makeWrite(self, op_desc): - return 'xc->setNextPC(%s);\n' % op_desc.munged_name + return 'xc->setNextPC(%s);\n' % op_desc.base_name exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits', @@ -1317,14 +1310,15 @@ class OperandDescriptor: self.traits = operandTraitsMap[base_name] # The 'effective extension' (eff_ext) is either the actual # extension, if one was explicitly provided, or the default. - # The 'munged name' replaces the '.' between the base and - # extension (if any) with a '_' to make a legal C++ variable name. if ext: self.eff_ext = ext - self.munged_name = base_name + '_' + ext else: self.eff_ext = self.traits.dflt_ext - self.munged_name = base_name + + # note that mem_acc_size is undefined for non-mem operands... + # template must be careful not to use it if it doesn't apply. + if self.traits.isMem(): + self.mem_acc_size = self.traits.makeAccSize(self) # Finalize additional fields (primarily code fields). This step # is done separately since some of these fields may depend on the @@ -1345,10 +1339,73 @@ class OperandDescriptor: else: self.op_wb = '' + class OperandDescriptorList: - def __init__(self): + + # Find all the operands in the given code block. Returns an operand + # descriptor list (instance of class OperandDescriptorList). + def __init__(self, code): self.items = [] self.bases = {} + # delete comments so we don't match on reg specifiers inside + code = commentRE.sub('', code) + # search for operands + next_pos = 0 + while 1: + match = operandsRE.search(code, next_pos) + if not match: + # no more matches: we're done + break + op = match.groups() + # regexp groups are operand full name, base, and extension + (op_full, op_base, op_ext) = op + # if the token following the operand is an assignment, this is + # a destination (LHS), else it's a source (RHS) + is_dest = (assignRE.match(code, match.end()) != None) + is_src = not is_dest + # see if we've already seen this one + op_desc = self.find_base(op_base) + if op_desc: + if op_desc.ext != op_ext: + error(0, 'Inconsistent extensions for operand %s' % \ + op_base) + op_desc.is_src = op_desc.is_src or is_src + op_desc.is_dest = op_desc.is_dest or is_dest + else: + # new operand: create new descriptor + op_desc = OperandDescriptor(op_full, op_base, op_ext, + is_src, is_dest) + self.append(op_desc) + # start next search after end of current match + next_pos = match.end() + self.sort() + # enumerate source & dest register operands... used in building + # constructor later + self.numSrcRegs = 0 + self.numDestRegs = 0 + self.numFPDestRegs = 0 + self.numIntDestRegs = 0 + self.memOperand = None + for op_desc in self.items: + if op_desc.traits.isReg(): + if op_desc.is_src: + op_desc.src_reg_idx = self.numSrcRegs + self.numSrcRegs += 1 + if op_desc.is_dest: + op_desc.dest_reg_idx = self.numDestRegs + self.numDestRegs += 1 + if op_desc.traits.isFloatReg(): + self.numFPDestRegs += 1 + elif op_desc.traits.isIntReg(): + self.numIntDestRegs += 1 + elif op_desc.traits.isMem(): + if self.memOperand: + error(0, "Code block has more than one memory operand.") + self.memOperand = op_desc + # now make a final pass to finalize op_desc fields that may depend + # on the register enumeration + for op_desc in self.items: + op_desc.finalize() def __len__(self): return len(self.items) @@ -1403,73 +1460,11 @@ commentRE = re.compile(r'//.*\n') # (used in findOperands()) assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) -# -# Find all the operands in the given code block. Returns an operand -# descriptor list (instance of class OperandDescriptorList). -# -def findOperands(code): - operands = OperandDescriptorList() - # delete comments so we don't accidentally match on reg specifiers inside - code = commentRE.sub('', code) - # search for operands - next_pos = 0 - while 1: - match = operandsRE.search(code, next_pos) - if not match: - # no more matches: we're done - break - op = match.groups() - # regexp groups are operand full name, base, and extension - (op_full, op_base, op_ext) = op - # if the token following the operand is an assignment, this is - # a destination (LHS), else it's a source (RHS) - is_dest = (assignRE.match(code, match.end()) != None) - is_src = not is_dest - # see if we've already seen this one - op_desc = operands.find_base(op_base) - if op_desc: - if op_desc.ext != op_ext: - error(0, 'Inconsistent extensions for operand %s' % op_base) - op_desc.is_src = op_desc.is_src or is_src - op_desc.is_dest = op_desc.is_dest or is_dest - else: - # new operand: create new descriptor - op_desc = OperandDescriptor(op_full, op_base, op_ext, - is_src, is_dest) - operands.append(op_desc) - # start next search after end of current match - next_pos = match.end() - operands.sort() - # enumerate source & dest register operands... used in building - # constructor later - srcRegs = 0 - destRegs = 0 - operands.numFPDestRegs = 0 - operands.numIntDestRegs = 0 - for op_desc in operands: - if op_desc.traits.isReg(): - if op_desc.is_src: - op_desc.src_reg_idx = srcRegs - srcRegs += 1 - if op_desc.is_dest: - op_desc.dest_reg_idx = destRegs - destRegs += 1 - if op_desc.traits.isFloatReg(): - operands.numFPDestRegs += 1 - elif op_desc.traits.isIntReg(): - operands.numIntDestRegs += 1 - operands.numSrcRegs = srcRegs - operands.numDestRegs = destRegs - # now make a final pass to finalize op_desc fields that may depend - # on the register enumeration - for op_desc in operands: - op_desc.finalize() - return operands - # Munge operand names in code string to make legal C++ variable names. -# (Will match munged_name attribute of OperandDescriptor object.) +# This means getting rid of the type extension if any. +# (Will match base_name attribute of OperandDescriptor object.) def substMungedOpNames(code): - return operandsWithExtRE.sub(r'\1_\2', code) + return operandsWithExtRE.sub(r'\1', code) def joinLists(t): return map(string.join, t) @@ -1493,7 +1488,7 @@ def makeFlagConstructor(flag_list): class CodeBlock: def __init__(self, code): self.orig_code = code - self.operands = findOperands(code) + self.operands = OperandDescriptorList(code) self.code = substMungedOpNames(substBitOps(code)) self.constructor = self.operands.concatAttrStrings('constructor') self.constructor += \ @@ -1507,22 +1502,14 @@ class CodeBlock: self.op_decl = self.operands.concatAttrStrings('op_decl') - is_mem = lambda op: op.traits.isMem() - not_mem = lambda op: not op.traits.isMem() - self.op_rd = self.operands.concatAttrStrings('op_rd') self.op_wb = self.operands.concatAttrStrings('op_wb') - self.op_mem_rd = \ - self.operands.concatSomeAttrStrings(is_mem, 'op_rd') - self.op_mem_wb = \ - self.operands.concatSomeAttrStrings(is_mem, 'op_wb') - self.op_nonmem_rd = \ - self.operands.concatSomeAttrStrings(not_mem, 'op_rd') - self.op_nonmem_wb = \ - self.operands.concatSomeAttrStrings(not_mem, 'op_wb') self.flags = self.operands.concatAttrLists('flags') + if self.operands.memOperand: + self.mem_acc_size = self.operands.memOperand.mem_acc_size + # Make a basic guess on the operand class (function unit type). # These are good enough for most cases, and will be overridden # later otherwise. @@ -1625,24 +1612,29 @@ def update_if_needed(file, contents): f.close() # This regular expression matches include directives -regExp = re.compile('(?P<include>^[ \t]*##include[ \t]*\"[ \t]*(?P<filename>[A-Za-z0-9\\/-_.]*)[ \t]*\"[ \t]*\n)', re.MULTILINE) +includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', + re.MULTILINE) def preprocess_isa_desc(isa_desc): # Find any includes and include them - - # Look for an include - m = re.search(regExp, isa_desc) - while m: + pos = 0 + while 1: + m = includeRE.search(isa_desc, pos) + if not m: + break filename = m.group('filename') print 'Including file "%s"' % filename - includeFile = open(filename) - includecontents = includeFile.read() - isa_desc = isa_desc[:m.start('include')] + '##newfile "' + filename + '"\n' + includecontents + '##endfile\n' + isa_desc[m.end('include'):] - # Look for the next include - m = re.search(regExp, isa_desc) + try: + isa_desc = isa_desc[:m.start()] + \ + '##newfile "' + filename + '"\n' + \ + open(filename).read() + \ + '##endfile\n' + \ + isa_desc[m.end():] + except IOError: + error(0, 'Error including file "%s"' % (filename)) + pos = m.start() return isa_desc - # # Read in and parse the ISA description. # |