isa_parser.py revision 6984:e37de92468f1
16019Shines@cs.fsu.edu# Copyright (c) 2003-2005 The Regents of The University of Michigan 27093Sgblack@eecs.umich.edu# All rights reserved. 37093Sgblack@eecs.umich.edu# 47093Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 57093Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are 67093Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright 77093Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 87093Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 97093Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 107093Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution; 117093Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its 127093Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from 137093Sgblack@eecs.umich.edu# this software without specific prior written permission. 146019Shines@cs.fsu.edu# 156019Shines@cs.fsu.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 166019Shines@cs.fsu.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 176019Shines@cs.fsu.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 186019Shines@cs.fsu.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 196019Shines@cs.fsu.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 206019Shines@cs.fsu.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 216019Shines@cs.fsu.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 226019Shines@cs.fsu.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 236019Shines@cs.fsu.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 246019Shines@cs.fsu.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 256019Shines@cs.fsu.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 266019Shines@cs.fsu.edu# 276019Shines@cs.fsu.edu# Authors: Steve Reinhardt 286019Shines@cs.fsu.edu 296019Shines@cs.fsu.eduimport os 306019Shines@cs.fsu.eduimport sys 316019Shines@cs.fsu.eduimport re 326019Shines@cs.fsu.eduimport string 336019Shines@cs.fsu.eduimport traceback 346019Shines@cs.fsu.edu# get type names 356019Shines@cs.fsu.edufrom types import * 366019Shines@cs.fsu.edu 376019Shines@cs.fsu.edufrom m5.util.grammar import Grammar 386019Shines@cs.fsu.edu 396019Shines@cs.fsu.edu################### 407399SAli.Saidi@ARM.com# Utility functions 417399SAli.Saidi@ARM.com 426019Shines@cs.fsu.edu# 436019Shines@cs.fsu.edu# Indent every line in string 's' by two spaces 446019Shines@cs.fsu.edu# (except preprocessor directives). 456019Shines@cs.fsu.edu# Used to make nested code blocks look pretty. 466019Shines@cs.fsu.edu# 476019Shines@cs.fsu.edudef indent(s): 486116Snate@binkert.org return re.sub(r'(?m)^(?!#)', ' ', s) 496019Shines@cs.fsu.edu 506019Shines@cs.fsu.edu# 516019Shines@cs.fsu.edu# Munge a somewhat arbitrarily formatted piece of Python code 526019Shines@cs.fsu.edu# (e.g. from a format 'let' block) into something whose indentation 536019Shines@cs.fsu.edu# will get by the Python parser. 546019Shines@cs.fsu.edu# 556019Shines@cs.fsu.edu# The two keys here are that Python will give a syntax error if 568232Snate@binkert.org# there's any whitespace at the beginning of the first line, and that 578232Snate@binkert.org# all lines at the same lexical nesting level must have identical 588232Snate@binkert.org# indentation. Unfortunately the way code literals work, an entire 596116Snate@binkert.org# let block tends to have some initial indentation. Rather than 606116Snate@binkert.org# trying to figure out what that is and strip it off, we prepend 'if 616019Shines@cs.fsu.edu# 1:' to make the let code the nested block inside the if (and have 626019Shines@cs.fsu.edu# the parser automatically deal with the indentation for us). 637406SAli.Saidi@ARM.com# 648527SAli.Saidi@ARM.com# We don't want to do this if (1) the code block is empty or (2) the 657406SAli.Saidi@ARM.com# first line of the block doesn't have any whitespace at the front. 667406SAli.Saidi@ARM.com 677406SAli.Saidi@ARM.comdef fixPythonIndentation(s): 686019Shines@cs.fsu.edu # get rid of blank lines first 696019Shines@cs.fsu.edu s = re.sub(r'(?m)^\s*\n', '', s); 706019Shines@cs.fsu.edu if (s != '' and re.match(r'[ \t]', s[0])): 716019Shines@cs.fsu.edu s = 'if 1:\n' + s 727697SAli.Saidi@ARM.com return s 737404SAli.Saidi@ARM.com 747404SAli.Saidi@ARM.com# Error handler. Just call exit. Output formatted to work under 757404SAli.Saidi@ARM.com# Emacs compile-mode. Optional 'print_traceback' arg, if set to True, 768527SAli.Saidi@ARM.com# prints a Python stack backtrace too (can be handy when trying to 776019Shines@cs.fsu.edu# debug the parser itself). 787404SAli.Saidi@ARM.comdef error(lineno, string, print_traceback = False): 798352SChander.Sudanthi@ARM.com spaces = "" 807399SAli.Saidi@ARM.com for (filename, line) in fileNameStack[0:-1]: 817406SAli.Saidi@ARM.com print spaces + "In file included from " + filename + ":" 827404SAli.Saidi@ARM.com spaces += " " 837406SAli.Saidi@ARM.com # Print a Python stack backtrace if requested. 846019Shines@cs.fsu.edu if (print_traceback): 856019Shines@cs.fsu.edu traceback.print_exc() 866019Shines@cs.fsu.edu if lineno != 0: 876019Shines@cs.fsu.edu line_str = "%d:" % lineno 886019Shines@cs.fsu.edu else: 896019Shines@cs.fsu.edu line_str = "" 906019Shines@cs.fsu.edu sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string)) 916019Shines@cs.fsu.edu 927694SAli.Saidi@ARM.com#################### 937694SAli.Saidi@ARM.com# Template objects. 947694SAli.Saidi@ARM.com# 957749SAli.Saidi@ARM.com# Template objects are format strings that allow substitution from 967749SAli.Saidi@ARM.com# the attribute spaces of other objects (e.g. InstObjParams instances). 977749SAli.Saidi@ARM.com 987694SAli.Saidi@ARM.comlabelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]') 997694SAli.Saidi@ARM.com 1007694SAli.Saidi@ARM.comclass Template(object): 1017694SAli.Saidi@ARM.com def __init__(self, t): 1027694SAli.Saidi@ARM.com self.template = t 1037694SAli.Saidi@ARM.com 1047404SAli.Saidi@ARM.com def subst(self, d): 1057694SAli.Saidi@ARM.com myDict = None 1066019Shines@cs.fsu.edu 1077404SAli.Saidi@ARM.com # Protect non-Python-dict substitutions (e.g. if there's a printf 1087404SAli.Saidi@ARM.com # in the templated C++ code) 1097404SAli.Saidi@ARM.com template = protect_non_subst_percents(self.template) 1107697SAli.Saidi@ARM.com # CPU-model-specific substitutions are handled later (in GenCode). 1117404SAli.Saidi@ARM.com template = protect_cpu_symbols(template) 1127404SAli.Saidi@ARM.com 1137404SAli.Saidi@ARM.com # Build a dict ('myDict') to use for the template substitution. 1147404SAli.Saidi@ARM.com # Start with the template namespace. Make a copy since we're 1157404SAli.Saidi@ARM.com # going to modify it. 1167697SAli.Saidi@ARM.com myDict = parser.templateMap.copy() 1177697SAli.Saidi@ARM.com 1187697SAli.Saidi@ARM.com if isinstance(d, InstObjParams): 1197697SAli.Saidi@ARM.com # If we're dealing with an InstObjParams object, we need 1207697SAli.Saidi@ARM.com # to be a little more sophisticated. The instruction-wide 1217697SAli.Saidi@ARM.com # parameters are already formed, but the parameters which 1227697SAli.Saidi@ARM.com # are only function wide still need to be generated. 1237697SAli.Saidi@ARM.com compositeCode = '' 1247697SAli.Saidi@ARM.com 1257697SAli.Saidi@ARM.com myDict.update(d.__dict__) 1267404SAli.Saidi@ARM.com # The "operands" and "snippets" attributes of the InstObjParams 1277404SAli.Saidi@ARM.com # objects are for internal use and not substitution. 1287404SAli.Saidi@ARM.com del myDict['operands'] 1297404SAli.Saidi@ARM.com del myDict['snippets'] 1307404SAli.Saidi@ARM.com 1317404SAli.Saidi@ARM.com snippetLabels = [l for l in labelRE.findall(template) 1327404SAli.Saidi@ARM.com if d.snippets.has_key(l)] 1337404SAli.Saidi@ARM.com 1347404SAli.Saidi@ARM.com snippets = dict([(s, mungeSnippet(d.snippets[s])) 1357404SAli.Saidi@ARM.com for s in snippetLabels]) 1367404SAli.Saidi@ARM.com 1376019Shines@cs.fsu.edu myDict.update(snippets) 1386019Shines@cs.fsu.edu 1396019Shines@cs.fsu.edu compositeCode = ' '.join(map(str, snippets.values())) 1406019Shines@cs.fsu.edu 1417404SAli.Saidi@ARM.com # Add in template itself in case it references any 1426019Shines@cs.fsu.edu # operands explicitly (like Mem) 1437404SAli.Saidi@ARM.com compositeCode += ' ' + template 1447404SAli.Saidi@ARM.com 1457404SAli.Saidi@ARM.com operands = SubOperandList(compositeCode, d.operands) 1467404SAli.Saidi@ARM.com 1477404SAli.Saidi@ARM.com myDict['op_decl'] = operands.concatAttrStrings('op_decl') 1487404SAli.Saidi@ARM.com 1497697SAli.Saidi@ARM.com is_src = lambda op: op.is_src 1507404SAli.Saidi@ARM.com is_dest = lambda op: op.is_dest 1517697SAli.Saidi@ARM.com 1527697SAli.Saidi@ARM.com myDict['op_src_decl'] = \ 1537697SAli.Saidi@ARM.com operands.concatSomeAttrStrings(is_src, 'op_src_decl') 1547404SAli.Saidi@ARM.com myDict['op_dest_decl'] = \ 1557697SAli.Saidi@ARM.com operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') 1567404SAli.Saidi@ARM.com 1577697SAli.Saidi@ARM.com myDict['op_rd'] = operands.concatAttrStrings('op_rd') 1587697SAli.Saidi@ARM.com myDict['op_wb'] = operands.concatAttrStrings('op_wb') 1597697SAli.Saidi@ARM.com 1607734SAli.Saidi@ARM.com if d.operands.memOperand: 1617734SAli.Saidi@ARM.com myDict['mem_acc_size'] = d.operands.memOperand.mem_acc_size 1626019Shines@cs.fsu.edu myDict['mem_acc_type'] = d.operands.memOperand.mem_acc_type 1636019Shines@cs.fsu.edu 1646019Shines@cs.fsu.edu elif isinstance(d, dict): 1657404SAli.Saidi@ARM.com # if the argument is a dictionary, we just use it. 1667404SAli.Saidi@ARM.com myDict.update(d) 1677404SAli.Saidi@ARM.com elif hasattr(d, '__dict__'): 1687404SAli.Saidi@ARM.com # if the argument is an object, we use its attribute map. 1697404SAli.Saidi@ARM.com myDict.update(d.__dict__) 1707404SAli.Saidi@ARM.com else: 1717404SAli.Saidi@ARM.com raise TypeError, "Template.subst() arg must be or have dictionary" 1727404SAli.Saidi@ARM.com return template % myDict 1737404SAli.Saidi@ARM.com 1747404SAli.Saidi@ARM.com # Convert to string. This handles the case when a template with a 1757404SAli.Saidi@ARM.com # CPU-specific term gets interpolated into another template or into 1767404SAli.Saidi@ARM.com # an output block. 1777404SAli.Saidi@ARM.com def __str__(self): 1787404SAli.Saidi@ARM.com return expand_cpu_symbols_to_string(self.template) 1797404SAli.Saidi@ARM.com 1807404SAli.Saidi@ARM.com################ 1816019Shines@cs.fsu.edu# Format object. 1826019Shines@cs.fsu.edu# 1837404SAli.Saidi@ARM.com# A format object encapsulates an instruction format. It must provide 1847404SAli.Saidi@ARM.com# a defineInst() method that generates the code for an instruction 1857404SAli.Saidi@ARM.com# definition. 1867404SAli.Saidi@ARM.com 1877404SAli.Saidi@ARM.comexportContextSymbols = ('InstObjParams', 'makeList', 're', 'string') 1887734SAli.Saidi@ARM.com 1897404SAli.Saidi@ARM.comexportContext = {} 1907404SAli.Saidi@ARM.com 1917734SAli.Saidi@ARM.comdef updateExportContext(): 1927734SAli.Saidi@ARM.com exportContext.update(exportDict(*exportContextSymbols)) 1937404SAli.Saidi@ARM.com exportContext.update(parser.templateMap) 1947404SAli.Saidi@ARM.com 1957404SAli.Saidi@ARM.comdef exportDict(*symNames): 1968352SChander.Sudanthi@ARM.com return dict([(s, eval(s)) for s in symNames]) 1977734SAli.Saidi@ARM.com 1987734SAli.Saidi@ARM.com 1996019Shines@cs.fsu.educlass Format(object): 2006019Shines@cs.fsu.edu def __init__(self, id, params, code): 2017404SAli.Saidi@ARM.com # constructor: just save away arguments 2027404SAli.Saidi@ARM.com self.id = id 2037404SAli.Saidi@ARM.com self.params = params 2047404SAli.Saidi@ARM.com label = 'def format ' + id 2057404SAli.Saidi@ARM.com self.user_code = compile(fixPythonIndentation(code), label, 'exec') 2067404SAli.Saidi@ARM.com param_list = string.join(params, ", ") 2077404SAli.Saidi@ARM.com f = '''def defInst(_code, _context, %s): 2087404SAli.Saidi@ARM.com my_locals = vars().copy() 2097404SAli.Saidi@ARM.com exec _code in _context, my_locals 2107404SAli.Saidi@ARM.com return my_locals\n''' % param_list 2117404SAli.Saidi@ARM.com c = compile(f, label + ' wrapper', 'exec') 2127404SAli.Saidi@ARM.com exec c 2137734SAli.Saidi@ARM.com self.func = defInst 2147404SAli.Saidi@ARM.com 2157404SAli.Saidi@ARM.com def defineInst(self, name, args, lineno): 2167734SAli.Saidi@ARM.com context = {} 2177404SAli.Saidi@ARM.com updateExportContext() 2187404SAli.Saidi@ARM.com context.update(exportContext) 2197404SAli.Saidi@ARM.com if len(name): 2207404SAli.Saidi@ARM.com Name = name[0].upper() 2217404SAli.Saidi@ARM.com if len(name) > 1: 2227404SAli.Saidi@ARM.com Name += name[1:] 2237404SAli.Saidi@ARM.com context.update({ 'name': name, 'Name': Name }) 2247404SAli.Saidi@ARM.com try: 2257404SAli.Saidi@ARM.com vars = self.func(self.user_code, context, *args[0], **args[1]) 2267404SAli.Saidi@ARM.com except Exception, exc: 2277404SAli.Saidi@ARM.com error(lineno, 'error defining "%s": %s.' % (name, exc)) 2287404SAli.Saidi@ARM.com for k in vars.keys(): 2297404SAli.Saidi@ARM.com if k not in ('header_output', 'decoder_output', 2307404SAli.Saidi@ARM.com 'exec_output', 'decode_block'): 2317404SAli.Saidi@ARM.com del vars[k] 2327404SAli.Saidi@ARM.com return GenCode(**vars) 2337734SAli.Saidi@ARM.com 2347404SAli.Saidi@ARM.com# Special null format to catch an implicit-format instruction 2357404SAli.Saidi@ARM.com# definition outside of any format block. 2367404SAli.Saidi@ARM.comclass NoFormat(object): 2377734SAli.Saidi@ARM.com def __init__(self): 2387404SAli.Saidi@ARM.com self.defaultInst = '' 2397404SAli.Saidi@ARM.com 2407404SAli.Saidi@ARM.com def defineInst(self, name, args, lineno): 2417404SAli.Saidi@ARM.com error(lineno, 2427404SAli.Saidi@ARM.com 'instruction definition "%s" with no active format!' % name) 2437404SAli.Saidi@ARM.com 2447404SAli.Saidi@ARM.com# This dictionary maps format name strings to Format objects. 2457404SAli.Saidi@ARM.comformatMap = {} 2467404SAli.Saidi@ARM.com 2477404SAli.Saidi@ARM.com# Define a new format 2487404SAli.Saidi@ARM.comdef defFormat(id, params, code, lineno): 2497404SAli.Saidi@ARM.com # make sure we haven't already defined this one 2507404SAli.Saidi@ARM.com if formatMap.get(id, None) != None: 2517404SAli.Saidi@ARM.com error(lineno, 'format %s redefined.' % id) 2527404SAli.Saidi@ARM.com # create new object and store in global map 2537404SAli.Saidi@ARM.com formatMap[id] = Format(id, params, code) 2547404SAli.Saidi@ARM.com 2557734SAli.Saidi@ARM.com##################################################################### 2567404SAli.Saidi@ARM.com# 2577404SAli.Saidi@ARM.com# Support Classes 2587404SAli.Saidi@ARM.com# 2597734SAli.Saidi@ARM.com##################################################################### 2607404SAli.Saidi@ARM.com 2617404SAli.Saidi@ARM.com# Expand template with CPU-specific references into a dictionary with 2626019Shines@cs.fsu.edu# an entry for each CPU model name. The entry key is the model name 2636019Shines@cs.fsu.edu# and the corresponding value is the template with the CPU-specific 2646019Shines@cs.fsu.edu# refs substituted for that model. 2657733SAli.Saidi@ARM.comdef expand_cpu_symbols_to_dict(template): 2667733SAli.Saidi@ARM.com # Protect '%'s that don't go with CPU-specific terms 2677733SAli.Saidi@ARM.com t = re.sub(r'%(?!\(CPU_)', '%%', template) 2688353SAli.Saidi@ARM.com result = {} 2698353SAli.Saidi@ARM.com for cpu in cpu_models: 2708353SAli.Saidi@ARM.com result[cpu.name] = t % cpu.strings 2717733SAli.Saidi@ARM.com return result 2727733SAli.Saidi@ARM.com 2737733SAli.Saidi@ARM.com# *If* the template has CPU-specific references, return a single 2747733SAli.Saidi@ARM.com# string containing a copy of the template for each CPU model with the 2756019Shines@cs.fsu.edu# corresponding values substituted in. If the template has no 2766019Shines@cs.fsu.edu# CPU-specific references, it is returned unmodified. 2776019Shines@cs.fsu.edudef expand_cpu_symbols_to_string(template): 2786019Shines@cs.fsu.edu if template.find('%(CPU_') != -1: 2796019Shines@cs.fsu.edu return reduce(lambda x,y: x+y, 2807733SAli.Saidi@ARM.com expand_cpu_symbols_to_dict(template).values()) 2816019Shines@cs.fsu.edu else: 2827733SAli.Saidi@ARM.com return template 2838353SAli.Saidi@ARM.com 2848353SAli.Saidi@ARM.com# Protect CPU-specific references by doubling the corresponding '%'s 2858353SAli.Saidi@ARM.com# (in preparation for substituting a different set of references into 2867733SAli.Saidi@ARM.com# the template). 2877733SAli.Saidi@ARM.comdef protect_cpu_symbols(template): 2887749SAli.Saidi@ARM.com return re.sub(r'%(?=\(CPU_)', '%%', template) 2896019Shines@cs.fsu.edu 2906019Shines@cs.fsu.edu# Protect any non-dict-substitution '%'s in a format string 2916019Shines@cs.fsu.edu# (i.e. those not followed by '(') 2926019Shines@cs.fsu.edudef protect_non_subst_percents(s): 2936019Shines@cs.fsu.edu return re.sub(r'%(?!\()', '%%', s) 2947734SAli.Saidi@ARM.com 2957734SAli.Saidi@ARM.com############### 2967734SAli.Saidi@ARM.com# GenCode class 2977734SAli.Saidi@ARM.com# 2987734SAli.Saidi@ARM.com# The GenCode class encapsulates generated code destined for various 2997734SAli.Saidi@ARM.com# output files. The header_output and decoder_output attributes are 3007734SAli.Saidi@ARM.com# strings containing code destined for decoder.hh and decoder.cc 3017734SAli.Saidi@ARM.com# respectively. The decode_block attribute contains code to be 3027734SAli.Saidi@ARM.com# incorporated in the decode function itself (that will also end up in 3037734SAli.Saidi@ARM.com# decoder.cc). The exec_output attribute is a dictionary with a key 3047734SAli.Saidi@ARM.com# for each CPU model name; the value associated with a particular key 3057734SAli.Saidi@ARM.com# is the string of code for that CPU model's exec.cc file. The 3067734SAli.Saidi@ARM.com# has_decode_default attribute is used in the decode block to allow 3077734SAli.Saidi@ARM.com# explicit default clauses to override default default clauses. 3087734SAli.Saidi@ARM.com 3097734SAli.Saidi@ARM.comclass GenCode(object): 3106019Shines@cs.fsu.edu # Constructor. At this point we substitute out all CPU-specific 3116019Shines@cs.fsu.edu # symbols. For the exec output, these go into the per-model 3126019Shines@cs.fsu.edu # dictionary. For all other output types they get collapsed into 3136019Shines@cs.fsu.edu # a single string. 3147734SAli.Saidi@ARM.com def __init__(self, 3156019Shines@cs.fsu.edu header_output = '', decoder_output = '', exec_output = '', 3166019Shines@cs.fsu.edu decode_block = '', has_decode_default = False): 3176019Shines@cs.fsu.edu self.header_output = expand_cpu_symbols_to_string(header_output) 3186019Shines@cs.fsu.edu self.decoder_output = expand_cpu_symbols_to_string(decoder_output) 3197734SAli.Saidi@ARM.com if isinstance(exec_output, dict): 3206019Shines@cs.fsu.edu self.exec_output = exec_output 3216019Shines@cs.fsu.edu elif isinstance(exec_output, str): 3226019Shines@cs.fsu.edu # If the exec_output arg is a single string, we replicate 3236019Shines@cs.fsu.edu # it for each of the CPU models, substituting and 3247734SAli.Saidi@ARM.com # %(CPU_foo)s params appropriately. 3256019Shines@cs.fsu.edu self.exec_output = expand_cpu_symbols_to_dict(exec_output) 3266019Shines@cs.fsu.edu self.decode_block = expand_cpu_symbols_to_string(decode_block) 3276019Shines@cs.fsu.edu self.has_decode_default = has_decode_default 3286019Shines@cs.fsu.edu 3297734SAli.Saidi@ARM.com # Override '+' operator: generate a new GenCode object that 3306019Shines@cs.fsu.edu # concatenates all the individual strings in the operands. 3316019Shines@cs.fsu.edu def __add__(self, other): 3326019Shines@cs.fsu.edu exec_output = {} 3336019Shines@cs.fsu.edu for cpu in cpu_models: 3347734SAli.Saidi@ARM.com n = cpu.name 3356019Shines@cs.fsu.edu exec_output[n] = self.exec_output[n] + other.exec_output[n] 3366019Shines@cs.fsu.edu return GenCode(self.header_output + other.header_output, 3376019Shines@cs.fsu.edu self.decoder_output + other.decoder_output, 3386019Shines@cs.fsu.edu exec_output, 3396019Shines@cs.fsu.edu self.decode_block + other.decode_block, 3406019Shines@cs.fsu.edu self.has_decode_default or other.has_decode_default) 3416019Shines@cs.fsu.edu 3426019Shines@cs.fsu.edu # Prepend a string (typically a comment) to all the strings. 3436019Shines@cs.fsu.edu def prepend_all(self, pre): 3446019Shines@cs.fsu.edu self.header_output = pre + self.header_output 3456019Shines@cs.fsu.edu self.decoder_output = pre + self.decoder_output 3466019Shines@cs.fsu.edu self.decode_block = pre + self.decode_block 3476019Shines@cs.fsu.edu for cpu in cpu_models: 3486019Shines@cs.fsu.edu self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] 3496019Shines@cs.fsu.edu 3506019Shines@cs.fsu.edu # Wrap the decode block in a pair of strings (e.g., 'case foo:' 3516019Shines@cs.fsu.edu # and 'break;'). Used to build the big nested switch statement. 3526019Shines@cs.fsu.edu def wrap_decode_block(self, pre, post = ''): 3536019Shines@cs.fsu.edu self.decode_block = pre + indent(self.decode_block) + post 3547734SAli.Saidi@ARM.com 3557734SAli.Saidi@ARM.com##################################################################### 3567734SAli.Saidi@ARM.com# 3577734SAli.Saidi@ARM.com# Bitfield Operator Support 3587734SAli.Saidi@ARM.com# 3597734SAli.Saidi@ARM.com##################################################################### 3607734SAli.Saidi@ARM.com 3617734SAli.Saidi@ARM.combitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') 3627734SAli.Saidi@ARM.com 3637734SAli.Saidi@ARM.combitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') 3647734SAli.Saidi@ARM.combitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') 3657734SAli.Saidi@ARM.com 3667734SAli.Saidi@ARM.comdef substBitOps(code): 3677734SAli.Saidi@ARM.com # first convert single-bit selectors to two-index form 3687734SAli.Saidi@ARM.com # i.e., <n> --> <n:n> 3697734SAli.Saidi@ARM.com code = bitOp1ArgRE.sub(r'<\1:\1>', code) 3707734SAli.Saidi@ARM.com # simple case: selector applied to ID (name) 3717734SAli.Saidi@ARM.com # i.e., foo<a:b> --> bits(foo, a, b) 3727734SAli.Saidi@ARM.com code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) 3737734SAli.Saidi@ARM.com # if selector is applied to expression (ending in ')'), 3747734SAli.Saidi@ARM.com # we need to search backward for matching '(' 3757734SAli.Saidi@ARM.com match = bitOpExprRE.search(code) 3767734SAli.Saidi@ARM.com while match: 3777734SAli.Saidi@ARM.com exprEnd = match.start() 3787734SAli.Saidi@ARM.com here = exprEnd - 1 3797734SAli.Saidi@ARM.com nestLevel = 1 3807734SAli.Saidi@ARM.com while nestLevel > 0: 3817734SAli.Saidi@ARM.com if code[here] == '(': 3827734SAli.Saidi@ARM.com nestLevel -= 1 3837734SAli.Saidi@ARM.com elif code[here] == ')': 3847734SAli.Saidi@ARM.com nestLevel += 1 3857734SAli.Saidi@ARM.com here -= 1 3867734SAli.Saidi@ARM.com if here < 0: 3877734SAli.Saidi@ARM.com sys.exit("Didn't find '('!") 3887734SAli.Saidi@ARM.com exprStart = here+1 3897734SAli.Saidi@ARM.com newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], 3907734SAli.Saidi@ARM.com match.group(1), match.group(2)) 3917734SAli.Saidi@ARM.com code = code[:exprStart] + newExpr + code[match.end():] 3927734SAli.Saidi@ARM.com match = bitOpExprRE.search(code) 3937734SAli.Saidi@ARM.com return code 3947734SAli.Saidi@ARM.com 3957734SAli.Saidi@ARM.com 3967734SAli.Saidi@ARM.com##################################################################### 3977734SAli.Saidi@ARM.com# 3987734SAli.Saidi@ARM.com# Code Parser 3997734SAli.Saidi@ARM.com# 4007734SAli.Saidi@ARM.com# The remaining code is the support for automatically extracting 4017734SAli.Saidi@ARM.com# instruction characteristics from pseudocode. 4027734SAli.Saidi@ARM.com# 4037734SAli.Saidi@ARM.com##################################################################### 4047734SAli.Saidi@ARM.com 4056019Shines@cs.fsu.edu# Force the argument to be a list. Useful for flags, where a caller 4066019Shines@cs.fsu.edu# can specify a singleton flag or a list of flags. Also usful for 4077404SAli.Saidi@ARM.com# converting tuples to lists so they can be modified. 4087404SAli.Saidi@ARM.comdef makeList(arg): 4097404SAli.Saidi@ARM.com if isinstance(arg, list): 4107404SAli.Saidi@ARM.com return arg 4117404SAli.Saidi@ARM.com elif isinstance(arg, tuple): 4127749SAli.Saidi@ARM.com return list(arg) 4137749SAli.Saidi@ARM.com elif not arg: 4147720Sgblack@eecs.umich.edu return [] 4157294Sgblack@eecs.umich.edu else: 4167294Sgblack@eecs.umich.edu return [ arg ] 4177404SAli.Saidi@ARM.com 4187404SAli.Saidi@ARM.com# Generate operandTypeMap from the user's 'def operand_types' 4197404SAli.Saidi@ARM.com# statement. 4207404SAli.Saidi@ARM.comdef buildOperandTypeMap(user_dict, lineno): 4217294Sgblack@eecs.umich.edu global operandTypeMap 4227404SAli.Saidi@ARM.com operandTypeMap = {} 4237404SAli.Saidi@ARM.com for (ext, (desc, size)) in user_dict.iteritems(): 4247404SAli.Saidi@ARM.com if desc == 'signed int': 4257294Sgblack@eecs.umich.edu ctype = 'int%d_t' % size 4267294Sgblack@eecs.umich.edu is_signed = 1 4277294Sgblack@eecs.umich.edu elif desc == 'unsigned int': 4286019Shines@cs.fsu.edu ctype = 'uint%d_t' % size 4297093Sgblack@eecs.umich.edu is_signed = 0 4307404SAli.Saidi@ARM.com elif desc == 'float': 4317404SAli.Saidi@ARM.com is_signed = 1 # shouldn't really matter 4327093Sgblack@eecs.umich.edu if size == 32: 4337093Sgblack@eecs.umich.edu ctype = 'float' 4347093Sgblack@eecs.umich.edu elif size == 64: 4356019Shines@cs.fsu.edu ctype = 'double' 4366019Shines@cs.fsu.edu elif desc == 'twin64 int': 4377404SAli.Saidi@ARM.com is_signed = 0 4387404SAli.Saidi@ARM.com ctype = 'Twin64_t' 4397404SAli.Saidi@ARM.com elif desc == 'twin32 int': 4407404SAli.Saidi@ARM.com is_signed = 0 4417404SAli.Saidi@ARM.com ctype = 'Twin32_t' 4427406SAli.Saidi@ARM.com if ctype == '': 4437406SAli.Saidi@ARM.com error(lineno, 'Unrecognized type description "%s" in user_dict') 4447406SAli.Saidi@ARM.com operandTypeMap[ext] = (size, ctype, is_signed) 4457406SAli.Saidi@ARM.com 4467406SAli.Saidi@ARM.comclass Operand(object): 4477406SAli.Saidi@ARM.com '''Base class for operand descriptors. An instance of this class 4487406SAli.Saidi@ARM.com (or actually a class derived from this one) represents a specific 4497406SAli.Saidi@ARM.com operand for a code block (e.g, "Rc.sq" as a dest). Intermediate 4507406SAli.Saidi@ARM.com derived classes encapsulates the traits of a particular operand 4517406SAli.Saidi@ARM.com type (e.g., "32-bit integer register").''' 4527406SAli.Saidi@ARM.com 4537406SAli.Saidi@ARM.com def buildReadCode(self, func = None): 4547406SAli.Saidi@ARM.com code = self.read_code % {"name": self.base_name, 4557404SAli.Saidi@ARM.com "func": func, 4567404SAli.Saidi@ARM.com "op_idx": self.src_reg_idx, 4577404SAli.Saidi@ARM.com "reg_idx": self.reg_spec, 4588202SAli.Saidi@ARM.com "size": self.size, 4597749SAli.Saidi@ARM.com "ctype": self.ctype} 4608202SAli.Saidi@ARM.com if self.size != self.dflt_size: 4618202SAli.Saidi@ARM.com return '%s = bits(%s, %d, 0);\n' % \ 4627749SAli.Saidi@ARM.com (self.base_name, code, self.size-1) 4637720Sgblack@eecs.umich.edu else: 4647404SAli.Saidi@ARM.com return '%s = %s;\n' % \ 4657404SAli.Saidi@ARM.com (self.base_name, code) 4667404SAli.Saidi@ARM.com 4677404SAli.Saidi@ARM.com def buildWriteCode(self, func = None): 4687749SAli.Saidi@ARM.com if (self.size != self.dflt_size and self.is_signed): 4697404SAli.Saidi@ARM.com final_val = 'sext<%d>(%s)' % (self.size, self.base_name) 4708552Sdaniel.johnson@arm.com else: 4718552Sdaniel.johnson@arm.com final_val = self.base_name 4728202SAli.Saidi@ARM.com code = self.write_code % {"name": self.base_name, 4737749SAli.Saidi@ARM.com "func": func, 4747603SGene.Wu@arm.com "op_idx": self.dest_reg_idx, 4757603SGene.Wu@arm.com "reg_idx": self.reg_spec, 4767603SGene.Wu@arm.com "size": self.size, 4777705Sgblack@eecs.umich.edu "ctype": self.ctype, 4787603SGene.Wu@arm.com "final_val": final_val} 4797606SGene.Wu@arm.com return ''' 4807705Sgblack@eecs.umich.edu { 4817603SGene.Wu@arm.com %s final_val = %s; 4827603SGene.Wu@arm.com %s; 4837608SGene.Wu@arm.com if (traceData) { traceData->setData(final_val); } 4847608SGene.Wu@arm.com }''' % (self.dflt_ctype, final_val, code) 4857608SGene.Wu@arm.com 4867608SGene.Wu@arm.com def __init__(self, full_name, ext, is_src, is_dest): 4877404SAli.Saidi@ARM.com self.full_name = full_name 4887404SAli.Saidi@ARM.com self.ext = ext 4897404SAli.Saidi@ARM.com self.is_src = is_src 4907404SAli.Saidi@ARM.com self.is_dest = is_dest 4917734SAli.Saidi@ARM.com # The 'effective extension' (eff_ext) is either the actual 4927404SAli.Saidi@ARM.com # extension, if one was explicitly provided, or the default. 4937404SAli.Saidi@ARM.com if ext: 4947404SAli.Saidi@ARM.com self.eff_ext = ext 4957404SAli.Saidi@ARM.com else: 4967404SAli.Saidi@ARM.com self.eff_ext = self.dflt_ext 4977404SAli.Saidi@ARM.com 4987404SAli.Saidi@ARM.com (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext] 4996757SAli.Saidi@ARM.com 5007093Sgblack@eecs.umich.edu # note that mem_acc_size is undefined for non-mem operands... 5017404SAli.Saidi@ARM.com # template must be careful not to use it if it doesn't apply. 5027404SAli.Saidi@ARM.com if self.isMem(): 5037404SAli.Saidi@ARM.com self.mem_acc_size = self.makeAccSize() 5047404SAli.Saidi@ARM.com if self.ctype in ['Twin32_t', 'Twin64_t']: 5057404SAli.Saidi@ARM.com self.mem_acc_type = 'Twin' 5067404SAli.Saidi@ARM.com else: 5077436Sdam.sunwoo@arm.com self.mem_acc_type = 'uint' 5087436Sdam.sunwoo@arm.com 5097436Sdam.sunwoo@arm.com # Finalize additional fields (primarily code fields). This step 5107439Sdam.sunwoo@arm.com # is done separately since some of these fields may depend on the 5117436Sdam.sunwoo@arm.com # register index enumeration that hasn't been performed yet at the 5127436Sdam.sunwoo@arm.com # time of __init__(). 5137436Sdam.sunwoo@arm.com def finalize(self): 5147436Sdam.sunwoo@arm.com self.flags = self.getFlags() 5157436Sdam.sunwoo@arm.com self.constructor = self.makeConstructor() 5167436Sdam.sunwoo@arm.com self.op_decl = self.makeDecl() 5177404SAli.Saidi@ARM.com 5187404SAli.Saidi@ARM.com if self.is_src: 5197404SAli.Saidi@ARM.com self.op_rd = self.makeRead() 5207749SAli.Saidi@ARM.com self.op_src_decl = self.makeDecl() 5217404SAli.Saidi@ARM.com else: 5227404SAli.Saidi@ARM.com self.op_rd = '' 5237749SAli.Saidi@ARM.com self.op_src_decl = '' 5247404SAli.Saidi@ARM.com 5257611SGene.Wu@arm.com if self.is_dest: 5267611SGene.Wu@arm.com self.op_wb = self.makeWrite() 5277611SGene.Wu@arm.com self.op_dest_decl = self.makeDecl() 5287734SAli.Saidi@ARM.com else: 5297611SGene.Wu@arm.com self.op_wb = '' 5307611SGene.Wu@arm.com self.op_dest_decl = '' 5317734SAli.Saidi@ARM.com 5327734SAli.Saidi@ARM.com def isMem(self): 5337734SAli.Saidi@ARM.com return 0 5347734SAli.Saidi@ARM.com 5357734SAli.Saidi@ARM.com def isReg(self): 5367734SAli.Saidi@ARM.com return 0 5377734SAli.Saidi@ARM.com 5387734SAli.Saidi@ARM.com def isFloatReg(self): 5397404SAli.Saidi@ARM.com return 0 5407404SAli.Saidi@ARM.com 5417404SAli.Saidi@ARM.com def isIntReg(self): 5427749SAli.Saidi@ARM.com return 0 5437749SAli.Saidi@ARM.com 5447404SAli.Saidi@ARM.com def isControlReg(self): 5458067SAli.Saidi@ARM.com return 0 5467404SAli.Saidi@ARM.com 5477437Sdam.sunwoo@arm.com def getFlags(self): 5487437Sdam.sunwoo@arm.com # note the empty slice '[:]' gives us a copy of self.flags[0] 5497437Sdam.sunwoo@arm.com # instead of a reference to it 5507404SAli.Saidi@ARM.com my_flags = self.flags[0][:] 5517404SAli.Saidi@ARM.com if self.is_src: 5527404SAli.Saidi@ARM.com my_flags += self.flags[1] 5537749SAli.Saidi@ARM.com if self.is_dest: 5547404SAli.Saidi@ARM.com my_flags += self.flags[2] 5557404SAli.Saidi@ARM.com return my_flags 5567404SAli.Saidi@ARM.com 5577734SAli.Saidi@ARM.com def makeDecl(self): 5587734SAli.Saidi@ARM.com # Note that initializations in the declarations are solely 5597734SAli.Saidi@ARM.com # to avoid 'uninitialized variable' errors from the compiler. 5607734SAli.Saidi@ARM.com return self.ctype + ' ' + self.base_name + ' = 0;\n'; 5617734SAli.Saidi@ARM.com 5627734SAli.Saidi@ARM.comclass IntRegOperand(Operand): 5637734SAli.Saidi@ARM.com def isReg(self): 5647404SAli.Saidi@ARM.com return 1 5657404SAli.Saidi@ARM.com 5667436Sdam.sunwoo@arm.com def isIntReg(self): 5677436Sdam.sunwoo@arm.com return 1 5687436Sdam.sunwoo@arm.com 5697436Sdam.sunwoo@arm.com def makeConstructor(self): 5707436Sdam.sunwoo@arm.com c = '' 5717436Sdam.sunwoo@arm.com if self.is_src: 5727850SMatt.Horsnell@arm.com c += '\n\t_srcRegIdx[%d] = %s;' % \ 5737606SGene.Wu@arm.com (self.src_reg_idx, self.reg_spec) 5747749SAli.Saidi@ARM.com if self.is_dest: 5757850SMatt.Horsnell@arm.com c += '\n\t_destRegIdx[%d] = %s;' % \ 5767850SMatt.Horsnell@arm.com (self.dest_reg_idx, self.reg_spec) 5777850SMatt.Horsnell@arm.com return c 5787850SMatt.Horsnell@arm.com 5797850SMatt.Horsnell@arm.com def makeRead(self): 5807850SMatt.Horsnell@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 5818527SAli.Saidi@ARM.com error(0, 'Attempt to read integer register as FP') 5828527SAli.Saidi@ARM.com if self.read_code != None: 5838527SAli.Saidi@ARM.com return self.buildReadCode('readIntRegOperand') 5848527SAli.Saidi@ARM.com if (self.size == self.dflt_size): 5858527SAli.Saidi@ARM.com return '%s = xc->readIntRegOperand(this, %d);\n' % \ 5867404SAli.Saidi@ARM.com (self.base_name, self.src_reg_idx) 5877404SAli.Saidi@ARM.com elif (self.size > self.dflt_size): 5887734SAli.Saidi@ARM.com int_reg_val = 'xc->readIntRegOperand(this, %d)' % \ 5897404SAli.Saidi@ARM.com (self.src_reg_idx) 5907404SAli.Saidi@ARM.com if (self.is_signed): 5917404SAli.Saidi@ARM.com int_reg_val = 'sext<%d>(%s)' % (self.dflt_size, int_reg_val) 5927404SAli.Saidi@ARM.com return '%s = %s;\n' % (self.base_name, int_reg_val) 5937404SAli.Saidi@ARM.com else: 5947404SAli.Saidi@ARM.com return '%s = bits(xc->readIntRegOperand(this, %d), %d, 0);\n' % \ 5957404SAli.Saidi@ARM.com (self.base_name, self.src_reg_idx, self.size-1) 5967404SAli.Saidi@ARM.com 5977404SAli.Saidi@ARM.com def makeWrite(self): 5987404SAli.Saidi@ARM.com if (self.ctype == 'float' or self.ctype == 'double'): 5997404SAli.Saidi@ARM.com error(0, 'Attempt to write integer register as FP') 6007404SAli.Saidi@ARM.com if self.write_code != None: 6017404SAli.Saidi@ARM.com return self.buildWriteCode('setIntRegOperand') 6027404SAli.Saidi@ARM.com if (self.size != self.dflt_size and self.is_signed): 6037404SAli.Saidi@ARM.com final_val = 'sext<%d>(%s)' % (self.size, self.base_name) 6047404SAli.Saidi@ARM.com else: 6057404SAli.Saidi@ARM.com final_val = self.base_name 6067404SAli.Saidi@ARM.com wb = ''' 6076757SAli.Saidi@ARM.com { 6086757SAli.Saidi@ARM.com %s final_val = %s; 6097404SAli.Saidi@ARM.com xc->setIntRegOperand(this, %d, final_val);\n 6107404SAli.Saidi@ARM.com if (traceData) { traceData->setData(final_val); } 6117404SAli.Saidi@ARM.com }''' % (self.dflt_ctype, final_val, self.dest_reg_idx) 6127404SAli.Saidi@ARM.com return wb 6137404SAli.Saidi@ARM.com 6147404SAli.Saidi@ARM.comclass FloatRegOperand(Operand): 6157404SAli.Saidi@ARM.com def isReg(self): 6167404SAli.Saidi@ARM.com return 1 6177406SAli.Saidi@ARM.com 6187406SAli.Saidi@ARM.com def isFloatReg(self): 6197406SAli.Saidi@ARM.com return 1 6207404SAli.Saidi@ARM.com 6217404SAli.Saidi@ARM.com def makeConstructor(self): 6227406SAli.Saidi@ARM.com c = '' 6237406SAli.Saidi@ARM.com if self.is_src: 6247406SAli.Saidi@ARM.com c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \ 6257406SAli.Saidi@ARM.com (self.src_reg_idx, self.reg_spec) 6267406SAli.Saidi@ARM.com if self.is_dest: 6277406SAli.Saidi@ARM.com c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \ 6287406SAli.Saidi@ARM.com (self.dest_reg_idx, self.reg_spec) 6297406SAli.Saidi@ARM.com return c 6307406SAli.Saidi@ARM.com 6317406SAli.Saidi@ARM.com def makeRead(self): 6327406SAli.Saidi@ARM.com bit_select = 0 6337406SAli.Saidi@ARM.com if (self.ctype == 'float' or self.ctype == 'double'): 6347406SAli.Saidi@ARM.com func = 'readFloatRegOperand' 6357406SAli.Saidi@ARM.com else: 6367406SAli.Saidi@ARM.com func = 'readFloatRegOperandBits' 6377406SAli.Saidi@ARM.com if (self.size != self.dflt_size): 6387406SAli.Saidi@ARM.com bit_select = 1 6397406SAli.Saidi@ARM.com base = 'xc->%s(this, %d)' % (func, self.src_reg_idx) 6407404SAli.Saidi@ARM.com if self.read_code != None: 6417404SAli.Saidi@ARM.com return self.buildReadCode(func) 6427404SAli.Saidi@ARM.com if bit_select: 6437404SAli.Saidi@ARM.com return '%s = bits(%s, %d, 0);\n' % \ 6447404SAli.Saidi@ARM.com (self.base_name, base, self.size-1) 6457404SAli.Saidi@ARM.com else: 6467404SAli.Saidi@ARM.com return '%s = %s;\n' % (self.base_name, base) 6477404SAli.Saidi@ARM.com 6487404SAli.Saidi@ARM.com def makeWrite(self): 6497404SAli.Saidi@ARM.com final_val = self.base_name 6507404SAli.Saidi@ARM.com final_ctype = self.ctype 6517404SAli.Saidi@ARM.com if (self.ctype == 'float' or self.ctype == 'double'): 6527404SAli.Saidi@ARM.com func = 'setFloatRegOperand' 6537404SAli.Saidi@ARM.com elif (self.ctype == 'uint32_t' or self.ctype == 'uint64_t'): 6547404SAli.Saidi@ARM.com func = 'setFloatRegOperandBits' 6557404SAli.Saidi@ARM.com else: 6567404SAli.Saidi@ARM.com func = 'setFloatRegOperandBits' 6577404SAli.Saidi@ARM.com final_ctype = 'uint%d_t' % self.dflt_size 6587404SAli.Saidi@ARM.com if (self.size != self.dflt_size and self.is_signed): 6597404SAli.Saidi@ARM.com final_val = 'sext<%d>(%s)' % (self.size, self.base_name) 6607404SAli.Saidi@ARM.com if self.write_code != None: 6617404SAli.Saidi@ARM.com return self.buildWriteCode(func) 6627404SAli.Saidi@ARM.com wb = ''' 6637734SAli.Saidi@ARM.com { 6647404SAli.Saidi@ARM.com %s final_val = %s; 6657404SAli.Saidi@ARM.com xc->%s(this, %d, final_val);\n 6667404SAli.Saidi@ARM.com if (traceData) { traceData->setData(final_val); } 6677404SAli.Saidi@ARM.com }''' % (final_ctype, final_val, func, self.dest_reg_idx) 6687404SAli.Saidi@ARM.com return wb 6697404SAli.Saidi@ARM.com 6707734SAli.Saidi@ARM.comclass ControlRegOperand(Operand): 6717404SAli.Saidi@ARM.com def isReg(self): 6727404SAli.Saidi@ARM.com return 1 6737404SAli.Saidi@ARM.com 6747404SAli.Saidi@ARM.com def isControlReg(self): 6757404SAli.Saidi@ARM.com return 1 6767404SAli.Saidi@ARM.com 6777404SAli.Saidi@ARM.com def makeConstructor(self): 6787404SAli.Saidi@ARM.com c = '' 6797404SAli.Saidi@ARM.com if self.is_src: 6807404SAli.Saidi@ARM.com c += '\n\t_srcRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \ 6817404SAli.Saidi@ARM.com (self.src_reg_idx, self.reg_spec) 6827404SAli.Saidi@ARM.com if self.is_dest: 6837404SAli.Saidi@ARM.com c += '\n\t_destRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \ 6846757SAli.Saidi@ARM.com (self.dest_reg_idx, self.reg_spec) 6857404SAli.Saidi@ARM.com return c 6866757SAli.Saidi@ARM.com 6876019Shines@cs.fsu.edu def makeRead(self): 6887404SAli.Saidi@ARM.com bit_select = 0 6897404SAli.Saidi@ARM.com if (self.ctype == 'float' or self.ctype == 'double'): 6907404SAli.Saidi@ARM.com error(0, 'Attempt to read control register as FP') 6917404SAli.Saidi@ARM.com if self.read_code != None: 6927404SAli.Saidi@ARM.com return self.buildReadCode('readMiscRegOperand') 6937404SAli.Saidi@ARM.com base = 'xc->readMiscRegOperand(this, %s)' % self.src_reg_idx 6947404SAli.Saidi@ARM.com if self.size == self.dflt_size: 6957404SAli.Saidi@ARM.com return '%s = %s;\n' % (self.base_name, base) 6967404SAli.Saidi@ARM.com else: 6977404SAli.Saidi@ARM.com return '%s = bits(%s, %d, 0);\n' % \ 6987404SAli.Saidi@ARM.com (self.base_name, base, self.size-1) 6997404SAli.Saidi@ARM.com 7007404SAli.Saidi@ARM.com def makeWrite(self): 7016019Shines@cs.fsu.edu if (self.ctype == 'float' or self.ctype == 'double'): 7026019Shines@cs.fsu.edu error(0, 'Attempt to write control register as FP') 7037404SAli.Saidi@ARM.com if self.write_code != None: 7046116Snate@binkert.org return self.buildWriteCode('setMiscRegOperand') 7056116Snate@binkert.org wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \ 7066020Sgblack@eecs.umich.edu (self.dest_reg_idx, self.base_name) 7076020Sgblack@eecs.umich.edu wb += 'if (traceData) { traceData->setData(%s); }' % \ 7087404SAli.Saidi@ARM.com self.base_name 7097404SAli.Saidi@ARM.com return wb 7107404SAli.Saidi@ARM.com 7117404SAli.Saidi@ARM.comclass MemOperand(Operand): 7127404SAli.Saidi@ARM.com def isMem(self): 7137404SAli.Saidi@ARM.com return 1 7147404SAli.Saidi@ARM.com 7158527SAli.Saidi@ARM.com def makeConstructor(self): 7168067SAli.Saidi@ARM.com return '' 7177404SAli.Saidi@ARM.com 7187404SAli.Saidi@ARM.com def makeDecl(self): 7197944SGiacomo.Gabrielli@arm.com # Note that initializations in the declarations are solely 7207944SGiacomo.Gabrielli@arm.com # to avoid 'uninitialized variable' errors from the compiler. 7217404SAli.Saidi@ARM.com # Declare memory data variable. 7226020Sgblack@eecs.umich.edu if self.ctype in ['Twin32_t','Twin64_t']: 7236020Sgblack@eecs.umich.edu return "%s %s; %s.a = 0; %s.b = 0;\n" % \ 7247781SAli.Saidi@ARM.com (self.ctype, self.base_name, self.base_name, self.base_name) 7257781SAli.Saidi@ARM.com return '%s %s = 0;\n' % (self.ctype, self.base_name) 7267781SAli.Saidi@ARM.com 7277781SAli.Saidi@ARM.com def makeRead(self): 7287781SAli.Saidi@ARM.com if self.read_code != None: 7297781SAli.Saidi@ARM.com return self.buildReadCode() 7307781SAli.Saidi@ARM.com return '' 7317781SAli.Saidi@ARM.com 7327781SAli.Saidi@ARM.com def makeWrite(self): 7337781SAli.Saidi@ARM.com if self.write_code != None: 7347781SAli.Saidi@ARM.com return self.buildWriteCode() 7357781SAli.Saidi@ARM.com return '' 7366116Snate@binkert.org 7376116Snate@binkert.org # Return the memory access size *in bits*, suitable for 7386019Shines@cs.fsu.edu # forming a type via "uint%d_t". Divide by 8 if you want bytes. 7396116Snate@binkert.org def makeAccSize(self): 7406019Shines@cs.fsu.edu return self.size 741 742class PCOperand(Operand): 743 def makeConstructor(self): 744 return '' 745 746 def makeRead(self): 747 return '%s = xc->readPC();\n' % self.base_name 748 749 def makeWrite(self): 750 return 'xc->setPC(%s);\n' % self.base_name 751 752class UPCOperand(Operand): 753 def makeConstructor(self): 754 return '' 755 756 def makeRead(self): 757 if self.read_code != None: 758 return self.buildReadCode('readMicroPC') 759 return '%s = xc->readMicroPC();\n' % self.base_name 760 761 def makeWrite(self): 762 if self.write_code != None: 763 return self.buildWriteCode('setMicroPC') 764 return 'xc->setMicroPC(%s);\n' % self.base_name 765 766class NUPCOperand(Operand): 767 def makeConstructor(self): 768 return '' 769 770 def makeRead(self): 771 if self.read_code != None: 772 return self.buildReadCode('readNextMicroPC') 773 return '%s = xc->readNextMicroPC();\n' % self.base_name 774 775 def makeWrite(self): 776 if self.write_code != None: 777 return self.buildWriteCode('setNextMicroPC') 778 return 'xc->setNextMicroPC(%s);\n' % self.base_name 779 780class NPCOperand(Operand): 781 def makeConstructor(self): 782 return '' 783 784 def makeRead(self): 785 if self.read_code != None: 786 return self.buildReadCode('readNextPC') 787 return '%s = xc->readNextPC();\n' % self.base_name 788 789 def makeWrite(self): 790 if self.write_code != None: 791 return self.buildWriteCode('setNextPC') 792 return 'xc->setNextPC(%s);\n' % self.base_name 793 794class NNPCOperand(Operand): 795 def makeConstructor(self): 796 return '' 797 798 def makeRead(self): 799 if self.read_code != None: 800 return self.buildReadCode('readNextNPC') 801 return '%s = xc->readNextNPC();\n' % self.base_name 802 803 def makeWrite(self): 804 if self.write_code != None: 805 return self.buildWriteCode('setNextNPC') 806 return 'xc->setNextNPC(%s);\n' % self.base_name 807 808def buildOperandNameMap(user_dict, lineno): 809 global operandNameMap 810 operandNameMap = {} 811 for (op_name, val) in user_dict.iteritems(): 812 (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val[:5] 813 if len(val) > 5: 814 read_code = val[5] 815 else: 816 read_code = None 817 if len(val) > 6: 818 write_code = val[6] 819 else: 820 write_code = None 821 if len(val) > 7: 822 error(lineno, 823 'error: too many attributes for operand "%s"' % 824 base_cls_name) 825 826 (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext] 827 # Canonical flag structure is a triple of lists, where each list 828 # indicates the set of flags implied by this operand always, when 829 # used as a source, and when used as a dest, respectively. 830 # For simplicity this can be initialized using a variety of fairly 831 # obvious shortcuts; we convert these to canonical form here. 832 if not flags: 833 # no flags specified (e.g., 'None') 834 flags = ( [], [], [] ) 835 elif isinstance(flags, str): 836 # a single flag: assumed to be unconditional 837 flags = ( [ flags ], [], [] ) 838 elif isinstance(flags, list): 839 # a list of flags: also assumed to be unconditional 840 flags = ( flags, [], [] ) 841 elif isinstance(flags, tuple): 842 # it's a tuple: it should be a triple, 843 # but each item could be a single string or a list 844 (uncond_flags, src_flags, dest_flags) = flags 845 flags = (makeList(uncond_flags), 846 makeList(src_flags), makeList(dest_flags)) 847 # Accumulate attributes of new operand class in tmp_dict 848 tmp_dict = {} 849 for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri', 850 'dflt_size', 'dflt_ctype', 'dflt_is_signed', 851 'read_code', 'write_code'): 852 tmp_dict[attr] = eval(attr) 853 tmp_dict['base_name'] = op_name 854 # New class name will be e.g. "IntReg_Ra" 855 cls_name = base_cls_name + '_' + op_name 856 # Evaluate string arg to get class object. Note that the 857 # actual base class for "IntReg" is "IntRegOperand", i.e. we 858 # have to append "Operand". 859 try: 860 base_cls = eval(base_cls_name + 'Operand') 861 except NameError: 862 error(lineno, 863 'error: unknown operand base class "%s"' % base_cls_name) 864 # The following statement creates a new class called 865 # <cls_name> as a subclass of <base_cls> with the attributes 866 # in tmp_dict, just as if we evaluated a class declaration. 867 operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict) 868 869 # Define operand variables. 870 operands = user_dict.keys() 871 872 operandsREString = (r''' 873 (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches 874 ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix 875 (?![\w\.]) # neg. lookahead assertion: prevent partial matches 876 ''' 877 % string.join(operands, '|')) 878 879 global operandsRE 880 operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) 881 882 # Same as operandsREString, but extension is mandatory, and only two 883 # groups are returned (base and ext, not full name as above). 884 # Used for subtituting '_' for '.' to make C++ identifiers. 885 operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])' 886 % string.join(operands, '|')) 887 888 global operandsWithExtRE 889 operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE) 890 891maxInstSrcRegs = 0 892maxInstDestRegs = 0 893 894class OperandList(object): 895 '''Find all the operands in the given code block. Returns an operand 896 descriptor list (instance of class OperandList).''' 897 def __init__(self, code): 898 self.items = [] 899 self.bases = {} 900 # delete comments so we don't match on reg specifiers inside 901 code = commentRE.sub('', code) 902 # search for operands 903 next_pos = 0 904 while 1: 905 match = operandsRE.search(code, next_pos) 906 if not match: 907 # no more matches: we're done 908 break 909 op = match.groups() 910 # regexp groups are operand full name, base, and extension 911 (op_full, op_base, op_ext) = op 912 # if the token following the operand is an assignment, this is 913 # a destination (LHS), else it's a source (RHS) 914 is_dest = (assignRE.match(code, match.end()) != None) 915 is_src = not is_dest 916 # see if we've already seen this one 917 op_desc = self.find_base(op_base) 918 if op_desc: 919 if op_desc.ext != op_ext: 920 error(0, 'Inconsistent extensions for operand %s' % \ 921 op_base) 922 op_desc.is_src = op_desc.is_src or is_src 923 op_desc.is_dest = op_desc.is_dest or is_dest 924 else: 925 # new operand: create new descriptor 926 op_desc = operandNameMap[op_base](op_full, op_ext, 927 is_src, is_dest) 928 self.append(op_desc) 929 # start next search after end of current match 930 next_pos = match.end() 931 self.sort() 932 # enumerate source & dest register operands... used in building 933 # constructor later 934 self.numSrcRegs = 0 935 self.numDestRegs = 0 936 self.numFPDestRegs = 0 937 self.numIntDestRegs = 0 938 self.memOperand = None 939 for op_desc in self.items: 940 if op_desc.isReg(): 941 if op_desc.is_src: 942 op_desc.src_reg_idx = self.numSrcRegs 943 self.numSrcRegs += 1 944 if op_desc.is_dest: 945 op_desc.dest_reg_idx = self.numDestRegs 946 self.numDestRegs += 1 947 if op_desc.isFloatReg(): 948 self.numFPDestRegs += 1 949 elif op_desc.isIntReg(): 950 self.numIntDestRegs += 1 951 elif op_desc.isMem(): 952 if self.memOperand: 953 error(0, "Code block has more than one memory operand.") 954 self.memOperand = op_desc 955 global maxInstSrcRegs 956 global maxInstDestRegs 957 if maxInstSrcRegs < self.numSrcRegs: 958 maxInstSrcRegs = self.numSrcRegs 959 if maxInstDestRegs < self.numDestRegs: 960 maxInstDestRegs = self.numDestRegs 961 # now make a final pass to finalize op_desc fields that may depend 962 # on the register enumeration 963 for op_desc in self.items: 964 op_desc.finalize() 965 966 def __len__(self): 967 return len(self.items) 968 969 def __getitem__(self, index): 970 return self.items[index] 971 972 def append(self, op_desc): 973 self.items.append(op_desc) 974 self.bases[op_desc.base_name] = op_desc 975 976 def find_base(self, base_name): 977 # like self.bases[base_name], but returns None if not found 978 # (rather than raising exception) 979 return self.bases.get(base_name) 980 981 # internal helper function for concat[Some]Attr{Strings|Lists} 982 def __internalConcatAttrs(self, attr_name, filter, result): 983 for op_desc in self.items: 984 if filter(op_desc): 985 result += getattr(op_desc, attr_name) 986 return result 987 988 # return a single string that is the concatenation of the (string) 989 # values of the specified attribute for all operands 990 def concatAttrStrings(self, attr_name): 991 return self.__internalConcatAttrs(attr_name, lambda x: 1, '') 992 993 # like concatAttrStrings, but only include the values for the operands 994 # for which the provided filter function returns true 995 def concatSomeAttrStrings(self, filter, attr_name): 996 return self.__internalConcatAttrs(attr_name, filter, '') 997 998 # return a single list that is the concatenation of the (list) 999 # values of the specified attribute for all operands 1000 def concatAttrLists(self, attr_name): 1001 return self.__internalConcatAttrs(attr_name, lambda x: 1, []) 1002 1003 # like concatAttrLists, but only include the values for the operands 1004 # for which the provided filter function returns true 1005 def concatSomeAttrLists(self, filter, attr_name): 1006 return self.__internalConcatAttrs(attr_name, filter, []) 1007 1008 def sort(self): 1009 self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) 1010 1011class SubOperandList(OperandList): 1012 '''Find all the operands in the given code block. Returns an operand 1013 descriptor list (instance of class OperandList).''' 1014 def __init__(self, code, master_list): 1015 self.items = [] 1016 self.bases = {} 1017 # delete comments so we don't match on reg specifiers inside 1018 code = commentRE.sub('', code) 1019 # search for operands 1020 next_pos = 0 1021 while 1: 1022 match = operandsRE.search(code, next_pos) 1023 if not match: 1024 # no more matches: we're done 1025 break 1026 op = match.groups() 1027 # regexp groups are operand full name, base, and extension 1028 (op_full, op_base, op_ext) = op 1029 # find this op in the master list 1030 op_desc = master_list.find_base(op_base) 1031 if not op_desc: 1032 error(0, 'Found operand %s which is not in the master list!' \ 1033 ' This is an internal error' % \ 1034 op_base) 1035 else: 1036 # See if we've already found this operand 1037 op_desc = self.find_base(op_base) 1038 if not op_desc: 1039 # if not, add a reference to it to this sub list 1040 self.append(master_list.bases[op_base]) 1041 1042 # start next search after end of current match 1043 next_pos = match.end() 1044 self.sort() 1045 self.memOperand = None 1046 for op_desc in self.items: 1047 if op_desc.isMem(): 1048 if self.memOperand: 1049 error(0, "Code block has more than one memory operand.") 1050 self.memOperand = op_desc 1051 1052# Regular expression object to match C++ comments 1053# (used in findOperands()) 1054commentRE = re.compile(r'//.*\n') 1055 1056# Regular expression object to match assignment statements 1057# (used in findOperands()) 1058assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) 1059 1060# Munge operand names in code string to make legal C++ variable names. 1061# This means getting rid of the type extension if any. 1062# (Will match base_name attribute of Operand object.) 1063def substMungedOpNames(code): 1064 return operandsWithExtRE.sub(r'\1', code) 1065 1066# Fix up code snippets for final substitution in templates. 1067def mungeSnippet(s): 1068 if isinstance(s, str): 1069 return substMungedOpNames(substBitOps(s)) 1070 else: 1071 return s 1072 1073def makeFlagConstructor(flag_list): 1074 if len(flag_list) == 0: 1075 return '' 1076 # filter out repeated flags 1077 flag_list.sort() 1078 i = 1 1079 while i < len(flag_list): 1080 if flag_list[i] == flag_list[i-1]: 1081 del flag_list[i] 1082 else: 1083 i += 1 1084 pre = '\n\tflags[' 1085 post = '] = true;' 1086 code = pre + string.join(flag_list, post + pre) + post 1087 return code 1088 1089# Assume all instruction flags are of the form 'IsFoo' 1090instFlagRE = re.compile(r'Is.*') 1091 1092# OpClass constants end in 'Op' except No_OpClass 1093opClassRE = re.compile(r'.*Op|No_OpClass') 1094 1095class InstObjParams(object): 1096 def __init__(self, mnem, class_name, base_class = '', 1097 snippets = {}, opt_args = []): 1098 self.mnemonic = mnem 1099 self.class_name = class_name 1100 self.base_class = base_class 1101 if not isinstance(snippets, dict): 1102 snippets = {'code' : snippets} 1103 compositeCode = ' '.join(map(str, snippets.values())) 1104 self.snippets = snippets 1105 1106 self.operands = OperandList(compositeCode) 1107 self.constructor = self.operands.concatAttrStrings('constructor') 1108 self.constructor += \ 1109 '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs 1110 self.constructor += \ 1111 '\n\t_numDestRegs = %d;' % self.operands.numDestRegs 1112 self.constructor += \ 1113 '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs 1114 self.constructor += \ 1115 '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs 1116 self.flags = self.operands.concatAttrLists('flags') 1117 1118 # Make a basic guess on the operand class (function unit type). 1119 # These are good enough for most cases, and can be overridden 1120 # later otherwise. 1121 if 'IsStore' in self.flags: 1122 self.op_class = 'MemWriteOp' 1123 elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: 1124 self.op_class = 'MemReadOp' 1125 elif 'IsFloating' in self.flags: 1126 self.op_class = 'FloatAddOp' 1127 else: 1128 self.op_class = 'IntAluOp' 1129 1130 # Optional arguments are assumed to be either StaticInst flags 1131 # or an OpClass value. To avoid having to import a complete 1132 # list of these values to match against, we do it ad-hoc 1133 # with regexps. 1134 for oa in opt_args: 1135 if instFlagRE.match(oa): 1136 self.flags.append(oa) 1137 elif opClassRE.match(oa): 1138 self.op_class = oa 1139 else: 1140 error(0, 'InstObjParams: optional arg "%s" not recognized ' 1141 'as StaticInst::Flag or OpClass.' % oa) 1142 1143 # add flag initialization to contructor here to include 1144 # any flags added via opt_args 1145 self.constructor += makeFlagConstructor(self.flags) 1146 1147 # if 'IsFloating' is set, add call to the FP enable check 1148 # function (which should be provided by isa_desc via a declare) 1149 if 'IsFloating' in self.flags: 1150 self.fp_enable_check = 'fault = checkFpEnableFault(xc);' 1151 else: 1152 self.fp_enable_check = '' 1153 1154############## 1155# Stack: a simple stack object. Used for both formats (formatStack) 1156# and default cases (defaultStack). Simply wraps a list to give more 1157# stack-like syntax and enable initialization with an argument list 1158# (as opposed to an argument that's a list). 1159 1160class Stack(list): 1161 def __init__(self, *items): 1162 list.__init__(self, items) 1163 1164 def push(self, item): 1165 self.append(item); 1166 1167 def top(self): 1168 return self[-1] 1169 1170# The global format stack. 1171formatStack = Stack(NoFormat()) 1172 1173# The global default case stack. 1174defaultStack = Stack(None) 1175 1176# Global stack that tracks current file and line number. 1177# Each element is a tuple (filename, lineno) that records the 1178# *current* filename and the line number in the *previous* file where 1179# it was included. 1180fileNameStack = Stack() 1181 1182 1183####################### 1184# 1185# Output file template 1186# 1187 1188file_template = ''' 1189/* 1190 * DO NOT EDIT THIS FILE!!! 1191 * 1192 * It was automatically generated from the ISA description in %(filename)s 1193 */ 1194 1195%(includes)s 1196 1197%(global_output)s 1198 1199namespace %(namespace)s { 1200 1201%(namespace_output)s 1202 1203} // namespace %(namespace)s 1204 1205%(decode_function)s 1206''' 1207 1208max_inst_regs_template = ''' 1209/* 1210 * DO NOT EDIT THIS FILE!!! 1211 * 1212 * It was automatically generated from the ISA description in %(filename)s 1213 */ 1214 1215namespace %(namespace)s { 1216 1217 const int MaxInstSrcRegs = %(MaxInstSrcRegs)d; 1218 const int MaxInstDestRegs = %(MaxInstDestRegs)d; 1219 1220} // namespace %(namespace)s 1221 1222''' 1223 1224class ISAParser(Grammar): 1225 def __init__(self, *args, **kwargs): 1226 super(ISAParser, self).__init__(*args, **kwargs) 1227 self.templateMap = {} 1228 1229 ##################################################################### 1230 # 1231 # Lexer 1232 # 1233 # The PLY lexer module takes two things as input: 1234 # - A list of token names (the string list 'tokens') 1235 # - A regular expression describing a match for each token. The 1236 # regexp for token FOO can be provided in two ways: 1237 # - as a string variable named t_FOO 1238 # - as the doc string for a function named t_FOO. In this case, 1239 # the function is also executed, allowing an action to be 1240 # associated with each token match. 1241 # 1242 ##################################################################### 1243 1244 # Reserved words. These are listed separately as they are matched 1245 # using the same regexp as generic IDs, but distinguished in the 1246 # t_ID() function. The PLY documentation suggests this approach. 1247 reserved = ( 1248 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', 1249 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', 1250 'OUTPUT', 'SIGNED', 'TEMPLATE' 1251 ) 1252 1253 # List of tokens. The lex module requires this. 1254 tokens = reserved + ( 1255 # identifier 1256 'ID', 1257 1258 # integer literal 1259 'INTLIT', 1260 1261 # string literal 1262 'STRLIT', 1263 1264 # code literal 1265 'CODELIT', 1266 1267 # ( ) [ ] { } < > , ; . : :: * 1268 'LPAREN', 'RPAREN', 1269 'LBRACKET', 'RBRACKET', 1270 'LBRACE', 'RBRACE', 1271 'LESS', 'GREATER', 'EQUALS', 1272 'COMMA', 'SEMI', 'DOT', 'COLON', 'DBLCOLON', 1273 'ASTERISK', 1274 1275 # C preprocessor directives 1276 'CPPDIRECTIVE' 1277 1278 # The following are matched but never returned. commented out to 1279 # suppress PLY warning 1280 # newfile directive 1281 # 'NEWFILE', 1282 1283 # endfile directive 1284 # 'ENDFILE' 1285 ) 1286 1287 # Regular expressions for token matching 1288 t_LPAREN = r'\(' 1289 t_RPAREN = r'\)' 1290 t_LBRACKET = r'\[' 1291 t_RBRACKET = r'\]' 1292 t_LBRACE = r'\{' 1293 t_RBRACE = r'\}' 1294 t_LESS = r'\<' 1295 t_GREATER = r'\>' 1296 t_EQUALS = r'=' 1297 t_COMMA = r',' 1298 t_SEMI = r';' 1299 t_DOT = r'\.' 1300 t_COLON = r':' 1301 t_DBLCOLON = r'::' 1302 t_ASTERISK = r'\*' 1303 1304 # Identifiers and reserved words 1305 reserved_map = { } 1306 for r in reserved: 1307 reserved_map[r.lower()] = r 1308 1309 def t_ID(self, t): 1310 r'[A-Za-z_]\w*' 1311 t.type = self.reserved_map.get(t.value, 'ID') 1312 return t 1313 1314 # Integer literal 1315 def t_INTLIT(self, t): 1316 r'-?(0x[\da-fA-F]+)|\d+' 1317 try: 1318 t.value = int(t.value,0) 1319 except ValueError: 1320 error(t.lexer.lineno, 'Integer value "%s" too large' % t.value) 1321 t.value = 0 1322 return t 1323 1324 # String literal. Note that these use only single quotes, and 1325 # can span multiple lines. 1326 def t_STRLIT(self, t): 1327 r"(?m)'([^'])+'" 1328 # strip off quotes 1329 t.value = t.value[1:-1] 1330 t.lexer.lineno += t.value.count('\n') 1331 return t 1332 1333 1334 # "Code literal"... like a string literal, but delimiters are 1335 # '{{' and '}}' so they get formatted nicely under emacs c-mode 1336 def t_CODELIT(self, t): 1337 r"(?m)\{\{([^\}]|}(?!\}))+\}\}" 1338 # strip off {{ & }} 1339 t.value = t.value[2:-2] 1340 t.lexer.lineno += t.value.count('\n') 1341 return t 1342 1343 def t_CPPDIRECTIVE(self, t): 1344 r'^\#[^\#].*\n' 1345 t.lexer.lineno += t.value.count('\n') 1346 return t 1347 1348 def t_NEWFILE(self, t): 1349 r'^\#\#newfile\s+"[\w/.-]*"' 1350 fileNameStack.push((t.value[11:-1], t.lexer.lineno)) 1351 t.lexer.lineno = 0 1352 1353 def t_ENDFILE(self, t): 1354 r'^\#\#endfile' 1355 (old_filename, t.lexer.lineno) = fileNameStack.pop() 1356 1357 # 1358 # The functions t_NEWLINE, t_ignore, and t_error are 1359 # special for the lex module. 1360 # 1361 1362 # Newlines 1363 def t_NEWLINE(self, t): 1364 r'\n+' 1365 t.lexer.lineno += t.value.count('\n') 1366 1367 # Comments 1368 def t_comment(self, t): 1369 r'//.*' 1370 1371 # Completely ignored characters 1372 t_ignore = ' \t\x0c' 1373 1374 # Error handler 1375 def t_error(self, t): 1376 error(t.lexer.lineno, "illegal character '%s'" % t.value[0]) 1377 t.skip(1) 1378 1379 ##################################################################### 1380 # 1381 # Parser 1382 # 1383 # Every function whose name starts with 'p_' defines a grammar 1384 # rule. The rule is encoded in the function's doc string, while 1385 # the function body provides the action taken when the rule is 1386 # matched. The argument to each function is a list of the values 1387 # of the rule's symbols: t[0] for the LHS, and t[1..n] for the 1388 # symbols on the RHS. For tokens, the value is copied from the 1389 # t.value attribute provided by the lexer. For non-terminals, the 1390 # value is assigned by the producing rule; i.e., the job of the 1391 # grammar rule function is to set the value for the non-terminal 1392 # on the LHS (by assigning to t[0]). 1393 ##################################################################### 1394 1395 # The LHS of the first grammar rule is used as the start symbol 1396 # (in this case, 'specification'). Note that this rule enforces 1397 # that there will be exactly one namespace declaration, with 0 or 1398 # more global defs/decls before and after it. The defs & decls 1399 # before the namespace decl will be outside the namespace; those 1400 # after will be inside. The decoder function is always inside the 1401 # namespace. 1402 def p_specification(self, t): 1403 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' 1404 global_code = t[1] 1405 isa_name = t[2] 1406 namespace = isa_name + "Inst" 1407 # wrap the decode block as a function definition 1408 t[4].wrap_decode_block(''' 1409StaticInstPtr 1410%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst) 1411{ 1412 using namespace %(namespace)s; 1413''' % vars(), '}') 1414 # both the latter output blocks and the decode block are in 1415 # the namespace 1416 namespace_code = t[3] + t[4] 1417 # pass it all back to the caller of yacc.parse() 1418 t[0] = (isa_name, namespace, global_code, namespace_code) 1419 1420 # ISA name declaration looks like "namespace <foo>;" 1421 def p_name_decl(self, t): 1422 'name_decl : NAMESPACE ID SEMI' 1423 t[0] = t[2] 1424 1425 # 'opt_defs_and_outputs' is a possibly empty sequence of 1426 # def and/or output statements. 1427 def p_opt_defs_and_outputs_0(self, t): 1428 'opt_defs_and_outputs : empty' 1429 t[0] = GenCode() 1430 1431 def p_opt_defs_and_outputs_1(self, t): 1432 'opt_defs_and_outputs : defs_and_outputs' 1433 t[0] = t[1] 1434 1435 def p_defs_and_outputs_0(self, t): 1436 'defs_and_outputs : def_or_output' 1437 t[0] = t[1] 1438 1439 def p_defs_and_outputs_1(self, t): 1440 'defs_and_outputs : defs_and_outputs def_or_output' 1441 t[0] = t[1] + t[2] 1442 1443 # The list of possible definition/output statements. 1444 def p_def_or_output(self, t): 1445 '''def_or_output : def_format 1446 | def_bitfield 1447 | def_bitfield_struct 1448 | def_template 1449 | def_operand_types 1450 | def_operands 1451 | output_header 1452 | output_decoder 1453 | output_exec 1454 | global_let''' 1455 t[0] = t[1] 1456 1457 # Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied 1458 # directly to the appropriate output section. 1459 1460 # Massage output block by substituting in template definitions and 1461 # bit operators. We handle '%'s embedded in the string that don't 1462 # indicate template substitutions (or CPU-specific symbols, which 1463 # get handled in GenCode) by doubling them first so that the 1464 # format operation will reduce them back to single '%'s. 1465 def process_output(self, s): 1466 s = protect_non_subst_percents(s) 1467 # protects cpu-specific symbols too 1468 s = protect_cpu_symbols(s) 1469 return substBitOps(s % self.templateMap) 1470 1471 def p_output_header(self, t): 1472 'output_header : OUTPUT HEADER CODELIT SEMI' 1473 t[0] = GenCode(header_output = self.process_output(t[3])) 1474 1475 def p_output_decoder(self, t): 1476 'output_decoder : OUTPUT DECODER CODELIT SEMI' 1477 t[0] = GenCode(decoder_output = self.process_output(t[3])) 1478 1479 def p_output_exec(self, t): 1480 'output_exec : OUTPUT EXEC CODELIT SEMI' 1481 t[0] = GenCode(exec_output = self.process_output(t[3])) 1482 1483 # global let blocks 'let {{...}}' (Python code blocks) are 1484 # executed directly when seen. Note that these execute in a 1485 # special variable context 'exportContext' to prevent the code 1486 # from polluting this script's namespace. 1487 def p_global_let(self, t): 1488 'global_let : LET CODELIT SEMI' 1489 updateExportContext() 1490 exportContext["header_output"] = '' 1491 exportContext["decoder_output"] = '' 1492 exportContext["exec_output"] = '' 1493 exportContext["decode_block"] = '' 1494 try: 1495 exec fixPythonIndentation(t[2]) in exportContext 1496 except Exception, exc: 1497 error(t.lexer.lineno, 1498 'error: %s in global let block "%s".' % (exc, t[2])) 1499 t[0] = GenCode(header_output = exportContext["header_output"], 1500 decoder_output = exportContext["decoder_output"], 1501 exec_output = exportContext["exec_output"], 1502 decode_block = exportContext["decode_block"]) 1503 1504 # Define the mapping from operand type extensions to C++ types and 1505 # bit widths (stored in operandTypeMap). 1506 def p_def_operand_types(self, t): 1507 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' 1508 try: 1509 user_dict = eval('{' + t[3] + '}') 1510 except Exception, exc: 1511 error(t.lexer.lineno, 1512 'error: %s in def operand_types block "%s".' % (exc, t[3])) 1513 buildOperandTypeMap(user_dict, t.lexer.lineno) 1514 t[0] = GenCode() # contributes nothing to the output C++ file 1515 1516 # Define the mapping from operand names to operand classes and 1517 # other traits. Stored in operandNameMap. 1518 def p_def_operands(self, t): 1519 'def_operands : DEF OPERANDS CODELIT SEMI' 1520 if not globals().has_key('operandTypeMap'): 1521 error(t.lexer.lineno, 1522 'error: operand types must be defined before operands') 1523 try: 1524 user_dict = eval('{' + t[3] + '}', exportContext) 1525 except Exception, exc: 1526 error(t.lexer.lineno, 1527 'error: %s in def operands block "%s".' % (exc, t[3])) 1528 buildOperandNameMap(user_dict, t.lexer.lineno) 1529 t[0] = GenCode() # contributes nothing to the output C++ file 1530 1531 # A bitfield definition looks like: 1532 # 'def [signed] bitfield <ID> [<first>:<last>]' 1533 # This generates a preprocessor macro in the output file. 1534 def p_def_bitfield_0(self, t): 1535 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' 1536 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) 1537 if (t[2] == 'signed'): 1538 expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) 1539 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 1540 t[0] = GenCode(header_output = hash_define) 1541 1542 # alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' 1543 def p_def_bitfield_1(self, t): 1544 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' 1545 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) 1546 if (t[2] == 'signed'): 1547 expr = 'sext<%d>(%s)' % (1, expr) 1548 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 1549 t[0] = GenCode(header_output = hash_define) 1550 1551 # alternate form for structure member: 'def bitfield <ID> <ID>' 1552 def p_def_bitfield_struct(self, t): 1553 'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI' 1554 if (t[2] != ''): 1555 error(t.lexer.lineno, 1556 'error: structure bitfields are always unsigned.') 1557 expr = 'machInst.%s' % t[5] 1558 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 1559 t[0] = GenCode(header_output = hash_define) 1560 1561 def p_id_with_dot_0(self, t): 1562 'id_with_dot : ID' 1563 t[0] = t[1] 1564 1565 def p_id_with_dot_1(self, t): 1566 'id_with_dot : ID DOT id_with_dot' 1567 t[0] = t[1] + t[2] + t[3] 1568 1569 def p_opt_signed_0(self, t): 1570 'opt_signed : SIGNED' 1571 t[0] = t[1] 1572 1573 def p_opt_signed_1(self, t): 1574 'opt_signed : empty' 1575 t[0] = '' 1576 1577 def p_def_template(self, t): 1578 'def_template : DEF TEMPLATE ID CODELIT SEMI' 1579 self.templateMap[t[3]] = Template(t[4]) 1580 t[0] = GenCode() 1581 1582 # An instruction format definition looks like 1583 # "def format <fmt>(<params>) {{...}};" 1584 def p_def_format(self, t): 1585 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' 1586 (id, params, code) = (t[3], t[5], t[7]) 1587 defFormat(id, params, code, t.lexer.lineno) 1588 t[0] = GenCode() 1589 1590 # The formal parameter list for an instruction format is a 1591 # possibly empty list of comma-separated parameters. Positional 1592 # (standard, non-keyword) parameters must come first, followed by 1593 # keyword parameters, followed by a '*foo' parameter that gets 1594 # excess positional arguments (as in Python). Each of these three 1595 # parameter categories is optional. 1596 # 1597 # Note that we do not support the '**foo' parameter for collecting 1598 # otherwise undefined keyword args. Otherwise the parameter list 1599 # is (I believe) identical to what is supported in Python. 1600 # 1601 # The param list generates a tuple, where the first element is a 1602 # list of the positional params and the second element is a dict 1603 # containing the keyword params. 1604 def p_param_list_0(self, t): 1605 'param_list : positional_param_list COMMA nonpositional_param_list' 1606 t[0] = t[1] + t[3] 1607 1608 def p_param_list_1(self, t): 1609 '''param_list : positional_param_list 1610 | nonpositional_param_list''' 1611 t[0] = t[1] 1612 1613 def p_positional_param_list_0(self, t): 1614 'positional_param_list : empty' 1615 t[0] = [] 1616 1617 def p_positional_param_list_1(self, t): 1618 'positional_param_list : ID' 1619 t[0] = [t[1]] 1620 1621 def p_positional_param_list_2(self, t): 1622 'positional_param_list : positional_param_list COMMA ID' 1623 t[0] = t[1] + [t[3]] 1624 1625 def p_nonpositional_param_list_0(self, t): 1626 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' 1627 t[0] = t[1] + t[3] 1628 1629 def p_nonpositional_param_list_1(self, t): 1630 '''nonpositional_param_list : keyword_param_list 1631 | excess_args_param''' 1632 t[0] = t[1] 1633 1634 def p_keyword_param_list_0(self, t): 1635 'keyword_param_list : keyword_param' 1636 t[0] = [t[1]] 1637 1638 def p_keyword_param_list_1(self, t): 1639 'keyword_param_list : keyword_param_list COMMA keyword_param' 1640 t[0] = t[1] + [t[3]] 1641 1642 def p_keyword_param(self, t): 1643 'keyword_param : ID EQUALS expr' 1644 t[0] = t[1] + ' = ' + t[3].__repr__() 1645 1646 def p_excess_args_param(self, t): 1647 'excess_args_param : ASTERISK ID' 1648 # Just concatenate them: '*ID'. Wrap in list to be consistent 1649 # with positional_param_list and keyword_param_list. 1650 t[0] = [t[1] + t[2]] 1651 1652 # End of format definition-related rules. 1653 ############## 1654 1655 # 1656 # A decode block looks like: 1657 # decode <field1> [, <field2>]* [default <inst>] { ... } 1658 # 1659 def p_decode_block(self, t): 1660 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' 1661 default_defaults = defaultStack.pop() 1662 codeObj = t[5] 1663 # use the "default defaults" only if there was no explicit 1664 # default statement in decode_stmt_list 1665 if not codeObj.has_decode_default: 1666 codeObj += default_defaults 1667 codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') 1668 t[0] = codeObj 1669 1670 # The opt_default statement serves only to push the "default 1671 # defaults" onto defaultStack. This value will be used by nested 1672 # decode blocks, and used and popped off when the current 1673 # decode_block is processed (in p_decode_block() above). 1674 def p_opt_default_0(self, t): 1675 'opt_default : empty' 1676 # no default specified: reuse the one currently at the top of 1677 # the stack 1678 defaultStack.push(defaultStack.top()) 1679 # no meaningful value returned 1680 t[0] = None 1681 1682 def p_opt_default_1(self, t): 1683 'opt_default : DEFAULT inst' 1684 # push the new default 1685 codeObj = t[2] 1686 codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') 1687 defaultStack.push(codeObj) 1688 # no meaningful value returned 1689 t[0] = None 1690 1691 def p_decode_stmt_list_0(self, t): 1692 'decode_stmt_list : decode_stmt' 1693 t[0] = t[1] 1694 1695 def p_decode_stmt_list_1(self, t): 1696 'decode_stmt_list : decode_stmt decode_stmt_list' 1697 if (t[1].has_decode_default and t[2].has_decode_default): 1698 error(t.lexer.lineno, 'Two default cases in decode block') 1699 t[0] = t[1] + t[2] 1700 1701 # 1702 # Decode statement rules 1703 # 1704 # There are four types of statements allowed in a decode block: 1705 # 1. Format blocks 'format <foo> { ... }' 1706 # 2. Nested decode blocks 1707 # 3. Instruction definitions. 1708 # 4. C preprocessor directives. 1709 1710 1711 # Preprocessor directives found in a decode statement list are 1712 # passed through to the output, replicated to all of the output 1713 # code streams. This works well for ifdefs, so we can ifdef out 1714 # both the declarations and the decode cases generated by an 1715 # instruction definition. Handling them as part of the grammar 1716 # makes it easy to keep them in the right place with respect to 1717 # the code generated by the other statements. 1718 def p_decode_stmt_cpp(self, t): 1719 'decode_stmt : CPPDIRECTIVE' 1720 t[0] = GenCode(t[1], t[1], t[1], t[1]) 1721 1722 # A format block 'format <foo> { ... }' sets the default 1723 # instruction format used to handle instruction definitions inside 1724 # the block. This format can be overridden by using an explicit 1725 # format on the instruction definition or with a nested format 1726 # block. 1727 def p_decode_stmt_format(self, t): 1728 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' 1729 # The format will be pushed on the stack when 'push_format_id' 1730 # is processed (see below). Once the parser has recognized 1731 # the full production (though the right brace), we're done 1732 # with the format, so now we can pop it. 1733 formatStack.pop() 1734 t[0] = t[4] 1735 1736 # This rule exists so we can set the current format (& push the 1737 # stack) when we recognize the format name part of the format 1738 # block. 1739 def p_push_format_id(self, t): 1740 'push_format_id : ID' 1741 try: 1742 formatStack.push(formatMap[t[1]]) 1743 t[0] = ('', '// format %s' % t[1]) 1744 except KeyError: 1745 error(t.lexer.lineno, 1746 'instruction format "%s" not defined.' % t[1]) 1747 1748 # Nested decode block: if the value of the current field matches 1749 # the specified constant, do a nested decode on some other field. 1750 def p_decode_stmt_decode(self, t): 1751 'decode_stmt : case_label COLON decode_block' 1752 label = t[1] 1753 codeObj = t[3] 1754 # just wrap the decoding code from the block as a case in the 1755 # outer switch statement. 1756 codeObj.wrap_decode_block('\n%s:\n' % label) 1757 codeObj.has_decode_default = (label == 'default') 1758 t[0] = codeObj 1759 1760 # Instruction definition (finally!). 1761 def p_decode_stmt_inst(self, t): 1762 'decode_stmt : case_label COLON inst SEMI' 1763 label = t[1] 1764 codeObj = t[3] 1765 codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') 1766 codeObj.has_decode_default = (label == 'default') 1767 t[0] = codeObj 1768 1769 # The case label is either a list of one or more constants or 1770 # 'default' 1771 def p_case_label_0(self, t): 1772 'case_label : intlit_list' 1773 def make_case(intlit): 1774 if intlit >= 2**32: 1775 return 'case ULL(%#x)' % intlit 1776 else: 1777 return 'case %#x' % intlit 1778 t[0] = ': '.join(map(make_case, t[1])) 1779 1780 def p_case_label_1(self, t): 1781 'case_label : DEFAULT' 1782 t[0] = 'default' 1783 1784 # 1785 # The constant list for a decode case label must be non-empty, but 1786 # may have one or more comma-separated integer literals in it. 1787 # 1788 def p_intlit_list_0(self, t): 1789 'intlit_list : INTLIT' 1790 t[0] = [t[1]] 1791 1792 def p_intlit_list_1(self, t): 1793 'intlit_list : intlit_list COMMA INTLIT' 1794 t[0] = t[1] 1795 t[0].append(t[3]) 1796 1797 # Define an instruction using the current instruction format 1798 # (specified by an enclosing format block). 1799 # "<mnemonic>(<args>)" 1800 def p_inst_0(self, t): 1801 'inst : ID LPAREN arg_list RPAREN' 1802 # Pass the ID and arg list to the current format class to deal with. 1803 currentFormat = formatStack.top() 1804 codeObj = currentFormat.defineInst(t[1], t[3], t.lexer.lineno) 1805 args = ','.join(map(str, t[3])) 1806 args = re.sub('(?m)^', '//', args) 1807 args = re.sub('^//', '', args) 1808 comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) 1809 codeObj.prepend_all(comment) 1810 t[0] = codeObj 1811 1812 # Define an instruction using an explicitly specified format: 1813 # "<fmt>::<mnemonic>(<args>)" 1814 def p_inst_1(self, t): 1815 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' 1816 try: 1817 format = formatMap[t[1]] 1818 except KeyError: 1819 error(t.lexer.lineno, 1820 'instruction format "%s" not defined.' % t[1]) 1821 codeObj = format.defineInst(t[3], t[5], t.lexer.lineno) 1822 comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) 1823 codeObj.prepend_all(comment) 1824 t[0] = codeObj 1825 1826 # The arg list generates a tuple, where the first element is a 1827 # list of the positional args and the second element is a dict 1828 # containing the keyword args. 1829 def p_arg_list_0(self, t): 1830 'arg_list : positional_arg_list COMMA keyword_arg_list' 1831 t[0] = ( t[1], t[3] ) 1832 1833 def p_arg_list_1(self, t): 1834 'arg_list : positional_arg_list' 1835 t[0] = ( t[1], {} ) 1836 1837 def p_arg_list_2(self, t): 1838 'arg_list : keyword_arg_list' 1839 t[0] = ( [], t[1] ) 1840 1841 def p_positional_arg_list_0(self, t): 1842 'positional_arg_list : empty' 1843 t[0] = [] 1844 1845 def p_positional_arg_list_1(self, t): 1846 'positional_arg_list : expr' 1847 t[0] = [t[1]] 1848 1849 def p_positional_arg_list_2(self, t): 1850 'positional_arg_list : positional_arg_list COMMA expr' 1851 t[0] = t[1] + [t[3]] 1852 1853 def p_keyword_arg_list_0(self, t): 1854 'keyword_arg_list : keyword_arg' 1855 t[0] = t[1] 1856 1857 def p_keyword_arg_list_1(self, t): 1858 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' 1859 t[0] = t[1] 1860 t[0].update(t[3]) 1861 1862 def p_keyword_arg(self, t): 1863 'keyword_arg : ID EQUALS expr' 1864 t[0] = { t[1] : t[3] } 1865 1866 # 1867 # Basic expressions. These constitute the argument values of 1868 # "function calls" (i.e. instruction definitions in the decode 1869 # block) and default values for formal parameters of format 1870 # functions. 1871 # 1872 # Right now, these are either strings, integers, or (recursively) 1873 # lists of exprs (using Python square-bracket list syntax). Note 1874 # that bare identifiers are trated as string constants here (since 1875 # there isn't really a variable namespace to refer to). 1876 # 1877 def p_expr_0(self, t): 1878 '''expr : ID 1879 | INTLIT 1880 | STRLIT 1881 | CODELIT''' 1882 t[0] = t[1] 1883 1884 def p_expr_1(self, t): 1885 '''expr : LBRACKET list_expr RBRACKET''' 1886 t[0] = t[2] 1887 1888 def p_list_expr_0(self, t): 1889 'list_expr : expr' 1890 t[0] = [t[1]] 1891 1892 def p_list_expr_1(self, t): 1893 'list_expr : list_expr COMMA expr' 1894 t[0] = t[1] + [t[3]] 1895 1896 def p_list_expr_2(self, t): 1897 'list_expr : empty' 1898 t[0] = [] 1899 1900 # 1901 # Empty production... use in other rules for readability. 1902 # 1903 def p_empty(self, t): 1904 'empty :' 1905 pass 1906 1907 # Parse error handler. Note that the argument here is the 1908 # offending *token*, not a grammar symbol (hence the need to use 1909 # t.value) 1910 def p_error(self, t): 1911 if t: 1912 error(t.lexer.lineno, "syntax error at '%s'" % t.value) 1913 else: 1914 error(0, "unknown syntax error", True) 1915 1916 # END OF GRAMMAR RULES 1917 1918# Now build the parser. 1919parser = ISAParser() 1920 1921# Update the output file only if the new contents are different from 1922# the current contents. Minimizes the files that need to be rebuilt 1923# after minor changes. 1924def update_if_needed(file, contents): 1925 update = False 1926 if os.access(file, os.R_OK): 1927 f = open(file, 'r') 1928 old_contents = f.read() 1929 f.close() 1930 if contents != old_contents: 1931 print 'Updating', file 1932 os.remove(file) # in case it's write-protected 1933 update = True 1934 else: 1935 print 'File', file, 'is unchanged' 1936 else: 1937 print 'Generating', file 1938 update = True 1939 if update: 1940 f = open(file, 'w') 1941 f.write(contents) 1942 f.close() 1943 1944# This regular expression matches '##include' directives 1945includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', 1946 re.MULTILINE) 1947 1948# Function to replace a matched '##include' directive with the 1949# contents of the specified file (with nested ##includes replaced 1950# recursively). 'matchobj' is an re match object (from a match of 1951# includeRE) and 'dirname' is the directory relative to which the file 1952# path should be resolved. 1953def replace_include(matchobj, dirname): 1954 fname = matchobj.group('filename') 1955 full_fname = os.path.normpath(os.path.join(dirname, fname)) 1956 contents = '##newfile "%s"\n%s\n##endfile\n' % \ 1957 (full_fname, read_and_flatten(full_fname)) 1958 return contents 1959 1960# Read a file and recursively flatten nested '##include' files. 1961def read_and_flatten(filename): 1962 current_dir = os.path.dirname(filename) 1963 try: 1964 contents = open(filename).read() 1965 except IOError: 1966 error(0, 'Error including file "%s"' % filename) 1967 fileNameStack.push((filename, 0)) 1968 # Find any includes and include them 1969 contents = includeRE.sub(lambda m: replace_include(m, current_dir), 1970 contents) 1971 fileNameStack.pop() 1972 return contents 1973 1974# 1975# Read in and parse the ISA description. 1976# 1977def parse_isa_desc(isa_desc_file, output_dir): 1978 # Read file and (recursively) all included files into a string. 1979 # PLY requires that the input be in a single string so we have to 1980 # do this up front. 1981 isa_desc = read_and_flatten(isa_desc_file) 1982 1983 # Initialize filename stack with outer file. 1984 fileNameStack.push((isa_desc_file, 0)) 1985 1986 # Parse it. 1987 (isa_name, namespace, global_code, namespace_code) = parser.parse(isa_desc) 1988 1989 # grab the last three path components of isa_desc_file to put in 1990 # the output 1991 filename = '/'.join(isa_desc_file.split('/')[-3:]) 1992 1993 # generate decoder.hh 1994 includes = '#include "base/bitfield.hh" // for bitfield support' 1995 global_output = global_code.header_output 1996 namespace_output = namespace_code.header_output 1997 decode_function = '' 1998 update_if_needed(output_dir + '/decoder.hh', file_template % vars()) 1999 2000 # generate decoder.cc 2001 includes = '#include "decoder.hh"' 2002 global_output = global_code.decoder_output 2003 namespace_output = namespace_code.decoder_output 2004 # namespace_output += namespace_code.decode_block 2005 decode_function = namespace_code.decode_block 2006 update_if_needed(output_dir + '/decoder.cc', file_template % vars()) 2007 2008 # generate per-cpu exec files 2009 for cpu in cpu_models: 2010 includes = '#include "decoder.hh"\n' 2011 includes += cpu.includes 2012 global_output = global_code.exec_output[cpu.name] 2013 namespace_output = namespace_code.exec_output[cpu.name] 2014 decode_function = '' 2015 update_if_needed(output_dir + '/' + cpu.filename, 2016 file_template % vars()) 2017 2018 # The variable names here are hacky, but this will creat local variables 2019 # which will be referenced in vars() which have the value of the globals. 2020 global maxInstSrcRegs 2021 MaxInstSrcRegs = maxInstSrcRegs 2022 global maxInstDestRegs 2023 MaxInstDestRegs = maxInstDestRegs 2024 # max_inst_regs.hh 2025 update_if_needed(output_dir + '/max_inst_regs.hh', \ 2026 max_inst_regs_template % vars()) 2027 2028# global list of CpuModel objects (see cpu_models.py) 2029cpu_models = [] 2030 2031# Called as script: get args from command line. 2032# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models> 2033if __name__ == '__main__': 2034 execfile(sys.argv[1]) # read in CpuModel definitions 2035 cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]] 2036 parse_isa_desc(sys.argv[2], sys.argv[3]) 2037