isa_parser.py revision 10592
12810Srdreslin@umich.edu# Copyright (c) 2014 ARM Limited 211375Sandreas.hansson@arm.com# All rights reserved 311051Sandreas.hansson@arm.com# 411051Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall 511051Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual 611051Sandreas.hansson@arm.com# property including but not limited to intellectual property relating 711051Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software 811051Sandreas.hansson@arm.com# licensed hereunder. You may use the software subject to the license 911051Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated 1011051Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software, 1111051Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form. 1211051Sandreas.hansson@arm.com# 1311051Sandreas.hansson@arm.com# Copyright (c) 2003-2005 The Regents of The University of Michigan 1411051Sandreas.hansson@arm.com# Copyright (c) 2013 Advanced Micro Devices, Inc. 1511051Sandreas.hansson@arm.com# All rights reserved. 162810Srdreslin@umich.edu# 172810Srdreslin@umich.edu# Redistribution and use in source and binary forms, with or without 182810Srdreslin@umich.edu# modification, are permitted provided that the following conditions are 192810Srdreslin@umich.edu# met: redistributions of source code must retain the above copyright 202810Srdreslin@umich.edu# notice, this list of conditions and the following disclaimer; 212810Srdreslin@umich.edu# redistributions in binary form must reproduce the above copyright 222810Srdreslin@umich.edu# notice, this list of conditions and the following disclaimer in the 232810Srdreslin@umich.edu# documentation and/or other materials provided with the distribution; 242810Srdreslin@umich.edu# neither the name of the copyright holders nor the names of its 252810Srdreslin@umich.edu# contributors may be used to endorse or promote products derived from 262810Srdreslin@umich.edu# this software without specific prior written permission. 272810Srdreslin@umich.edu# 282810Srdreslin@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292810Srdreslin@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302810Srdreslin@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312810Srdreslin@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322810Srdreslin@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332810Srdreslin@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342810Srdreslin@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352810Srdreslin@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362810Srdreslin@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372810Srdreslin@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382810Srdreslin@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392810Srdreslin@umich.edu# 402810Srdreslin@umich.edu# Authors: Steve Reinhardt 412810Srdreslin@umich.edu 4211051Sandreas.hansson@arm.comfrom __future__ import with_statement 4311051Sandreas.hansson@arm.comimport os 442810Srdreslin@umich.eduimport sys 4511051Sandreas.hansson@arm.comimport re 4611051Sandreas.hansson@arm.comimport string 472810Srdreslin@umich.eduimport inspect, traceback 482810Srdreslin@umich.edu# get type names 492810Srdreslin@umich.edufrom types import * 502810Srdreslin@umich.edu 5111051Sandreas.hansson@arm.comfrom m5.util.grammar import Grammar 522810Srdreslin@umich.edu 532810Srdreslin@umich.edudebug=False 5411051Sandreas.hansson@arm.com 552810Srdreslin@umich.edu################### 5612334Sgabeblack@google.com# Utility functions 5711051Sandreas.hansson@arm.com 5811051Sandreas.hansson@arm.com# 5911051Sandreas.hansson@arm.com# Indent every line in string 's' by two spaces 6011051Sandreas.hansson@arm.com# (except preprocessor directives). 6111288Ssteve.reinhardt@amd.com# Used to make nested code blocks look pretty. 6211051Sandreas.hansson@arm.com# 6311051Sandreas.hansson@arm.comdef indent(s): 6411051Sandreas.hansson@arm.com return re.sub(r'(?m)^(?!#)', ' ', s) 6511051Sandreas.hansson@arm.com 6611051Sandreas.hansson@arm.com# 6711053Sandreas.hansson@arm.com# Munge a somewhat arbitrarily formatted piece of Python code 6811053Sandreas.hansson@arm.com# (e.g. from a format 'let' block) into something whose indentation 6911051Sandreas.hansson@arm.com# will get by the Python parser. 7011051Sandreas.hansson@arm.com# 7111051Sandreas.hansson@arm.com# The two keys here are that Python will give a syntax error if 7211197Sandreas.hansson@arm.com# there's any whitespace at the beginning of the first line, and that 7311197Sandreas.hansson@arm.com# all lines at the same lexical nesting level must have identical 7411199Sandreas.hansson@arm.com# indentation. Unfortunately the way code literals work, an entire 7511197Sandreas.hansson@arm.com# let block tends to have some initial indentation. Rather than 7612084Sspwilson2@wisc.edu# trying to figure out what that is and strip it off, we prepend 'if 7712084Sspwilson2@wisc.edu# 1:' to make the let code the nested block inside the if (and have 7811197Sandreas.hansson@arm.com# the parser automatically deal with the indentation for us). 7911051Sandreas.hansson@arm.com# 8011051Sandreas.hansson@arm.com# We don't want to do this if (1) the code block is empty or (2) the 8111051Sandreas.hansson@arm.com# first line of the block doesn't have any whitespace at the front. 8211051Sandreas.hansson@arm.com 8311051Sandreas.hansson@arm.comdef fixPythonIndentation(s): 8411051Sandreas.hansson@arm.com # get rid of blank lines first 8511051Sandreas.hansson@arm.com s = re.sub(r'(?m)^\s*\n', '', s); 8611051Sandreas.hansson@arm.com if (s != '' and re.match(r'[ \t]', s[0])): 8711051Sandreas.hansson@arm.com s = 'if 1:\n' + s 8811051Sandreas.hansson@arm.com return s 8911051Sandreas.hansson@arm.com 9011051Sandreas.hansson@arm.comclass ISAParserError(Exception): 9111051Sandreas.hansson@arm.com """Error handler for parser errors""" 9211051Sandreas.hansson@arm.com def __init__(self, first, second=None): 9311051Sandreas.hansson@arm.com if second is None: 9411051Sandreas.hansson@arm.com self.lineno = 0 9511051Sandreas.hansson@arm.com self.string = first 9611051Sandreas.hansson@arm.com else: 9711051Sandreas.hansson@arm.com if hasattr(first, 'lexer'): 9811051Sandreas.hansson@arm.com first = first.lexer.lineno 9911051Sandreas.hansson@arm.com self.lineno = first 10011051Sandreas.hansson@arm.com self.string = second 10111051Sandreas.hansson@arm.com 10211051Sandreas.hansson@arm.com def display(self, filename_stack, print_traceback=debug): 10311051Sandreas.hansson@arm.com # Output formatted to work under Emacs compile-mode. Optional 10411051Sandreas.hansson@arm.com # 'print_traceback' arg, if set to True, prints a Python stack 10511051Sandreas.hansson@arm.com # backtrace too (can be handy when trying to debug the parser 10611051Sandreas.hansson@arm.com # itself). 10711051Sandreas.hansson@arm.com 10811051Sandreas.hansson@arm.com spaces = "" 10911051Sandreas.hansson@arm.com for (filename, line) in filename_stack[:-1]: 11011051Sandreas.hansson@arm.com print "%sIn file included from %s:" % (spaces, filename) 11111051Sandreas.hansson@arm.com spaces += " " 11211051Sandreas.hansson@arm.com 11311051Sandreas.hansson@arm.com # Print a Python stack backtrace if requested. 11411051Sandreas.hansson@arm.com if print_traceback or not self.lineno: 11511051Sandreas.hansson@arm.com traceback.print_exc() 11611051Sandreas.hansson@arm.com 11711051Sandreas.hansson@arm.com line_str = "%s:" % (filename_stack[-1][0], ) 11811051Sandreas.hansson@arm.com if self.lineno: 11911051Sandreas.hansson@arm.com line_str += "%d:" % (self.lineno, ) 12011051Sandreas.hansson@arm.com 12111051Sandreas.hansson@arm.com return "%s%s %s" % (spaces, line_str, self.string) 12211051Sandreas.hansson@arm.com 12311051Sandreas.hansson@arm.com def exit(self, filename_stack, print_traceback=debug): 12411051Sandreas.hansson@arm.com # Just call exit. 12511051Sandreas.hansson@arm.com 12611051Sandreas.hansson@arm.com sys.exit(self.display(filename_stack, print_traceback)) 12711051Sandreas.hansson@arm.com 12811051Sandreas.hansson@arm.comdef error(*args): 12911051Sandreas.hansson@arm.com raise ISAParserError(*args) 13011051Sandreas.hansson@arm.com 13111051Sandreas.hansson@arm.com#################### 13211051Sandreas.hansson@arm.com# Template objects. 13311051Sandreas.hansson@arm.com# 13411051Sandreas.hansson@arm.com# Template objects are format strings that allow substitution from 13511051Sandreas.hansson@arm.com# the attribute spaces of other objects (e.g. InstObjParams instances). 13611051Sandreas.hansson@arm.com 13711051Sandreas.hansson@arm.comlabelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]') 13811051Sandreas.hansson@arm.com 13911051Sandreas.hansson@arm.comclass Template(object): 14011051Sandreas.hansson@arm.com def __init__(self, parser, t): 14111051Sandreas.hansson@arm.com self.parser = parser 14211051Sandreas.hansson@arm.com self.template = t 14311051Sandreas.hansson@arm.com 14411051Sandreas.hansson@arm.com def subst(self, d): 14511051Sandreas.hansson@arm.com myDict = None 14611051Sandreas.hansson@arm.com 14711051Sandreas.hansson@arm.com # Protect non-Python-dict substitutions (e.g. if there's a printf 14811051Sandreas.hansson@arm.com # in the templated C++ code) 14911051Sandreas.hansson@arm.com template = self.parser.protectNonSubstPercents(self.template) 15011601Sandreas.hansson@arm.com # CPU-model-specific substitutions are handled later (in GenCode). 15111601Sandreas.hansson@arm.com template = self.parser.protectCpuSymbols(template) 15211051Sandreas.hansson@arm.com 15311051Sandreas.hansson@arm.com # Build a dict ('myDict') to use for the template substitution. 15411051Sandreas.hansson@arm.com # Start with the template namespace. Make a copy since we're 15511051Sandreas.hansson@arm.com # going to modify it. 15611051Sandreas.hansson@arm.com myDict = self.parser.templateMap.copy() 15711051Sandreas.hansson@arm.com 15811051Sandreas.hansson@arm.com if isinstance(d, InstObjParams): 15911051Sandreas.hansson@arm.com # If we're dealing with an InstObjParams object, we need 16011051Sandreas.hansson@arm.com # to be a little more sophisticated. The instruction-wide 16111051Sandreas.hansson@arm.com # parameters are already formed, but the parameters which 16211284Sandreas.hansson@arm.com # are only function wide still need to be generated. 16311051Sandreas.hansson@arm.com compositeCode = '' 16411051Sandreas.hansson@arm.com 16511051Sandreas.hansson@arm.com myDict.update(d.__dict__) 16611051Sandreas.hansson@arm.com # The "operands" and "snippets" attributes of the InstObjParams 16711051Sandreas.hansson@arm.com # objects are for internal use and not substitution. 16811051Sandreas.hansson@arm.com del myDict['operands'] 16911051Sandreas.hansson@arm.com del myDict['snippets'] 17011284Sandreas.hansson@arm.com 17111284Sandreas.hansson@arm.com snippetLabels = [l for l in labelRE.findall(template) 17211284Sandreas.hansson@arm.com if d.snippets.has_key(l)] 17311284Sandreas.hansson@arm.com 17411051Sandreas.hansson@arm.com snippets = dict([(s, self.parser.mungeSnippet(d.snippets[s])) 17511284Sandreas.hansson@arm.com for s in snippetLabels]) 17611051Sandreas.hansson@arm.com 17711051Sandreas.hansson@arm.com myDict.update(snippets) 17811051Sandreas.hansson@arm.com 17911284Sandreas.hansson@arm.com compositeCode = ' '.join(map(str, snippets.values())) 18011284Sandreas.hansson@arm.com 18111284Sandreas.hansson@arm.com # Add in template itself in case it references any 18211284Sandreas.hansson@arm.com # operands explicitly (like Mem) 18311051Sandreas.hansson@arm.com compositeCode += ' ' + template 18411744Snikos.nikoleris@arm.com 18511051Sandreas.hansson@arm.com operands = SubOperandList(self.parser, compositeCode, d.operands) 18611051Sandreas.hansson@arm.com 18711051Sandreas.hansson@arm.com myDict['op_decl'] = operands.concatAttrStrings('op_decl') 18811051Sandreas.hansson@arm.com if operands.readPC or operands.setPC: 18911286Sandreas.hansson@arm.com myDict['op_decl'] += 'TheISA::PCState __parserAutoPCState;\n' 19011286Sandreas.hansson@arm.com 19111286Sandreas.hansson@arm.com # In case there are predicated register reads and write, declare 19211051Sandreas.hansson@arm.com # the variables for register indicies. It is being assumed that 19311286Sandreas.hansson@arm.com # all the operands in the OperandList are also in the 19411600Sandreas.hansson@arm.com # SubOperandList and in the same order. Otherwise, it is 19511600Sandreas.hansson@arm.com # expected that predication would not be used for the operands. 19611051Sandreas.hansson@arm.com if operands.predRead: 19711051Sandreas.hansson@arm.com myDict['op_decl'] += 'uint8_t _sourceIndex = 0;\n' 19811051Sandreas.hansson@arm.com if operands.predWrite: 19911284Sandreas.hansson@arm.com myDict['op_decl'] += 'uint8_t M5_VAR_USED _destIndex = 0;\n' 20011051Sandreas.hansson@arm.com 20111051Sandreas.hansson@arm.com is_src = lambda op: op.is_src 20211051Sandreas.hansson@arm.com is_dest = lambda op: op.is_dest 20311602Sandreas.hansson@arm.com 20411051Sandreas.hansson@arm.com myDict['op_src_decl'] = \ 20511051Sandreas.hansson@arm.com operands.concatSomeAttrStrings(is_src, 'op_src_decl') 20611284Sandreas.hansson@arm.com myDict['op_dest_decl'] = \ 20711051Sandreas.hansson@arm.com operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') 20811284Sandreas.hansson@arm.com if operands.readPC: 20911602Sandreas.hansson@arm.com myDict['op_src_decl'] += \ 21011051Sandreas.hansson@arm.com 'TheISA::PCState __parserAutoPCState;\n' 21111051Sandreas.hansson@arm.com if operands.setPC: 21211284Sandreas.hansson@arm.com myDict['op_dest_decl'] += \ 21311051Sandreas.hansson@arm.com 'TheISA::PCState __parserAutoPCState;\n' 21411284Sandreas.hansson@arm.com 21511284Sandreas.hansson@arm.com myDict['op_rd'] = operands.concatAttrStrings('op_rd') 21611284Sandreas.hansson@arm.com if operands.readPC: 21711051Sandreas.hansson@arm.com myDict['op_rd'] = '__parserAutoPCState = xc->pcState();\n' + \ 21811051Sandreas.hansson@arm.com myDict['op_rd'] 21911051Sandreas.hansson@arm.com 22011284Sandreas.hansson@arm.com # Compose the op_wb string. If we're going to write back the 22111284Sandreas.hansson@arm.com # PC state because we changed some of its elements, we'll need to 22211284Sandreas.hansson@arm.com # do that as early as possible. That allows later uncoordinated 22311284Sandreas.hansson@arm.com # modifications to the PC to layer appropriately. 22411051Sandreas.hansson@arm.com reordered = list(operands.items) 22511051Sandreas.hansson@arm.com reordered.reverse() 22611051Sandreas.hansson@arm.com op_wb_str = '' 22711284Sandreas.hansson@arm.com pcWbStr = 'xc->pcState(__parserAutoPCState);\n' 22811284Sandreas.hansson@arm.com for op_desc in reordered: 22911284Sandreas.hansson@arm.com if op_desc.isPCPart() and op_desc.is_dest: 23011197Sandreas.hansson@arm.com op_wb_str = op_desc.op_wb + pcWbStr + op_wb_str 23111601Sandreas.hansson@arm.com pcWbStr = '' 23211601Sandreas.hansson@arm.com else: 23311601Sandreas.hansson@arm.com op_wb_str = op_desc.op_wb + op_wb_str 23411601Sandreas.hansson@arm.com myDict['op_wb'] = op_wb_str 23511601Sandreas.hansson@arm.com 23611601Sandreas.hansson@arm.com elif isinstance(d, dict): 23711601Sandreas.hansson@arm.com # if the argument is a dictionary, we just use it. 23811601Sandreas.hansson@arm.com myDict.update(d) 23911197Sandreas.hansson@arm.com elif hasattr(d, '__dict__'): 24011601Sandreas.hansson@arm.com # if the argument is an object, we use its attribute map. 24111601Sandreas.hansson@arm.com myDict.update(d.__dict__) 24211601Sandreas.hansson@arm.com else: 24311601Sandreas.hansson@arm.com raise TypeError, "Template.subst() arg must be or have dictionary" 24411601Sandreas.hansson@arm.com return template % myDict 24511601Sandreas.hansson@arm.com 24611601Sandreas.hansson@arm.com # Convert to string. This handles the case when a template with a 24711051Sandreas.hansson@arm.com # CPU-specific term gets interpolated into another template or into 24811051Sandreas.hansson@arm.com # an output block. 24911051Sandreas.hansson@arm.com def __str__(self): 25011051Sandreas.hansson@arm.com return self.parser.expandCpuSymbolsToString(self.template) 25111051Sandreas.hansson@arm.com 25211284Sandreas.hansson@arm.com################ 25311284Sandreas.hansson@arm.com# Format object. 25411051Sandreas.hansson@arm.com# 25511051Sandreas.hansson@arm.com# A format object encapsulates an instruction format. It must provide 25611051Sandreas.hansson@arm.com# a defineInst() method that generates the code for an instruction 25711051Sandreas.hansson@arm.com# definition. 25811284Sandreas.hansson@arm.com 25911051Sandreas.hansson@arm.comclass Format(object): 26011051Sandreas.hansson@arm.com def __init__(self, id, params, code): 26111602Sandreas.hansson@arm.com self.id = id 26211602Sandreas.hansson@arm.com self.params = params 26311602Sandreas.hansson@arm.com label = 'def format ' + id 26411602Sandreas.hansson@arm.com self.user_code = compile(fixPythonIndentation(code), label, 'exec') 26511602Sandreas.hansson@arm.com param_list = string.join(params, ", ") 26611602Sandreas.hansson@arm.com f = '''def defInst(_code, _context, %s): 26711602Sandreas.hansson@arm.com my_locals = vars().copy() 26811602Sandreas.hansson@arm.com exec _code in _context, my_locals 26911602Sandreas.hansson@arm.com return my_locals\n''' % param_list 27011602Sandreas.hansson@arm.com c = compile(f, label + ' wrapper', 'exec') 27111602Sandreas.hansson@arm.com exec c 27211051Sandreas.hansson@arm.com self.func = defInst 27311602Sandreas.hansson@arm.com 27411197Sandreas.hansson@arm.com def defineInst(self, parser, name, args, lineno): 27511744Snikos.nikoleris@arm.com parser.updateExportContext() 27611744Snikos.nikoleris@arm.com context = parser.exportContext.copy() 27711051Sandreas.hansson@arm.com if len(name): 27811051Sandreas.hansson@arm.com Name = name[0].upper() 27911051Sandreas.hansson@arm.com if len(name) > 1: 28011051Sandreas.hansson@arm.com Name += name[1:] 28111051Sandreas.hansson@arm.com context.update({ 'name' : name, 'Name' : Name }) 28211051Sandreas.hansson@arm.com try: 28311051Sandreas.hansson@arm.com vars = self.func(self.user_code, context, *args[0], **args[1]) 28411051Sandreas.hansson@arm.com except Exception, exc: 28511051Sandreas.hansson@arm.com if debug: 28611051Sandreas.hansson@arm.com raise 28711051Sandreas.hansson@arm.com error(lineno, 'error defining "%s": %s.' % (name, exc)) 28811051Sandreas.hansson@arm.com for k in vars.keys(): 28911051Sandreas.hansson@arm.com if k not in ('header_output', 'decoder_output', 29011051Sandreas.hansson@arm.com 'exec_output', 'decode_block'): 29111051Sandreas.hansson@arm.com del vars[k] 29211051Sandreas.hansson@arm.com return GenCode(parser, **vars) 29311051Sandreas.hansson@arm.com 29411051Sandreas.hansson@arm.com# Special null format to catch an implicit-format instruction 29511051Sandreas.hansson@arm.com# definition outside of any format block. 29611051Sandreas.hansson@arm.comclass NoFormat(object): 29711744Snikos.nikoleris@arm.com def __init__(self): 29811051Sandreas.hansson@arm.com self.defaultInst = '' 29911051Sandreas.hansson@arm.com 30011744Snikos.nikoleris@arm.com def defineInst(self, parser, name, args, lineno): 30111051Sandreas.hansson@arm.com error(lineno, 30211051Sandreas.hansson@arm.com 'instruction definition "%s" with no active format!' % name) 30311051Sandreas.hansson@arm.com 30411051Sandreas.hansson@arm.com############### 30511199Sandreas.hansson@arm.com# GenCode class 30611051Sandreas.hansson@arm.com# 30711051Sandreas.hansson@arm.com# The GenCode class encapsulates generated code destined for various 30811051Sandreas.hansson@arm.com# output files. The header_output and decoder_output attributes are 30911867Snikos.nikoleris@arm.com# strings containing code destined for decoder.hh and decoder.cc 31011051Sandreas.hansson@arm.com# respectively. The decode_block attribute contains code to be 31111051Sandreas.hansson@arm.com# incorporated in the decode function itself (that will also end up in 31211484Snikos.nikoleris@arm.com# decoder.cc). The exec_output attribute is a dictionary with a key 31311051Sandreas.hansson@arm.com# for each CPU model name; the value associated with a particular key 31411051Sandreas.hansson@arm.com# is the string of code for that CPU model's exec.cc file. The 31511051Sandreas.hansson@arm.com# has_decode_default attribute is used in the decode block to allow 31611051Sandreas.hansson@arm.com# explicit default clauses to override default default clauses. 31711051Sandreas.hansson@arm.com 31811051Sandreas.hansson@arm.comclass GenCode(object): 31911051Sandreas.hansson@arm.com # Constructor. At this point we substitute out all CPU-specific 32011870Snikos.nikoleris@arm.com # symbols. For the exec output, these go into the per-model 32111051Sandreas.hansson@arm.com # dictionary. For all other output types they get collapsed into 32211744Snikos.nikoleris@arm.com # a single string. 32311051Sandreas.hansson@arm.com def __init__(self, parser, 32411051Sandreas.hansson@arm.com header_output = '', decoder_output = '', exec_output = '', 32511051Sandreas.hansson@arm.com decode_block = '', has_decode_default = False): 32611199Sandreas.hansson@arm.com self.parser = parser 32711051Sandreas.hansson@arm.com self.header_output = parser.expandCpuSymbolsToString(header_output) 32811051Sandreas.hansson@arm.com self.decoder_output = parser.expandCpuSymbolsToString(decoder_output) 32911051Sandreas.hansson@arm.com self.exec_output = exec_output 33011051Sandreas.hansson@arm.com self.decode_block = decode_block 33111051Sandreas.hansson@arm.com self.has_decode_default = has_decode_default 33211051Sandreas.hansson@arm.com 33311051Sandreas.hansson@arm.com # Write these code chunks out to the filesystem. They will be properly 33411051Sandreas.hansson@arm.com # interwoven by the write_top_level_files(). 33511375Sandreas.hansson@arm.com def emit(self): 33611375Sandreas.hansson@arm.com if self.header_output: 33711375Sandreas.hansson@arm.com self.parser.get_file('header').write(self.header_output) 33811199Sandreas.hansson@arm.com if self.decoder_output: 33911199Sandreas.hansson@arm.com self.parser.get_file('decoder').write(self.decoder_output) 34011199Sandreas.hansson@arm.com if self.exec_output: 34111199Sandreas.hansson@arm.com self.parser.get_file('exec').write(self.exec_output) 34211199Sandreas.hansson@arm.com if self.decode_block: 34311199Sandreas.hansson@arm.com self.parser.get_file('decode_block').write(self.decode_block) 34411199Sandreas.hansson@arm.com 34511199Sandreas.hansson@arm.com # Override '+' operator: generate a new GenCode object that 34611199Sandreas.hansson@arm.com # concatenates all the individual strings in the operands. 34711199Sandreas.hansson@arm.com def __add__(self, other): 34811199Sandreas.hansson@arm.com return GenCode(self.parser, 34911199Sandreas.hansson@arm.com self.header_output + other.header_output, 35011199Sandreas.hansson@arm.com self.decoder_output + other.decoder_output, 35111199Sandreas.hansson@arm.com self.exec_output + other.exec_output, 35211199Sandreas.hansson@arm.com self.decode_block + other.decode_block, 35311199Sandreas.hansson@arm.com self.has_decode_default or other.has_decode_default) 35411199Sandreas.hansson@arm.com 35511199Sandreas.hansson@arm.com # Prepend a string (typically a comment) to all the strings. 35611199Sandreas.hansson@arm.com def prepend_all(self, pre): 35711199Sandreas.hansson@arm.com self.header_output = pre + self.header_output 35811375Sandreas.hansson@arm.com self.decoder_output = pre + self.decoder_output 35911199Sandreas.hansson@arm.com self.decode_block = pre + self.decode_block 36011199Sandreas.hansson@arm.com self.exec_output = pre + self.exec_output 36111051Sandreas.hansson@arm.com 36211051Sandreas.hansson@arm.com # Wrap the decode block in a pair of strings (e.g., 'case foo:' 36311051Sandreas.hansson@arm.com # and 'break;'). Used to build the big nested switch statement. 36411051Sandreas.hansson@arm.com def wrap_decode_block(self, pre, post = ''): 36511051Sandreas.hansson@arm.com self.decode_block = pre + indent(self.decode_block) + post 36611199Sandreas.hansson@arm.com 36711051Sandreas.hansson@arm.com##################################################################### 36811199Sandreas.hansson@arm.com# 36911199Sandreas.hansson@arm.com# Bitfield Operator Support 37011199Sandreas.hansson@arm.com# 37111199Sandreas.hansson@arm.com##################################################################### 37211199Sandreas.hansson@arm.com 37311199Sandreas.hansson@arm.combitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') 37411199Sandreas.hansson@arm.com 37511199Sandreas.hansson@arm.combitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') 37611199Sandreas.hansson@arm.combitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') 37711199Sandreas.hansson@arm.com 37811199Sandreas.hansson@arm.comdef substBitOps(code): 37911199Sandreas.hansson@arm.com # first convert single-bit selectors to two-index form 38011484Snikos.nikoleris@arm.com # i.e., <n> --> <n:n> 38111051Sandreas.hansson@arm.com code = bitOp1ArgRE.sub(r'<\1:\1>', code) 38211051Sandreas.hansson@arm.com # simple case: selector applied to ID (name) 38311484Snikos.nikoleris@arm.com # i.e., foo<a:b> --> bits(foo, a, b) 38411051Sandreas.hansson@arm.com code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) 38511051Sandreas.hansson@arm.com # if selector is applied to expression (ending in ')'), 38611051Sandreas.hansson@arm.com # we need to search backward for matching '(' 38711051Sandreas.hansson@arm.com match = bitOpExprRE.search(code) 38811051Sandreas.hansson@arm.com while match: 38911051Sandreas.hansson@arm.com exprEnd = match.start() 39011051Sandreas.hansson@arm.com here = exprEnd - 1 39111051Sandreas.hansson@arm.com nestLevel = 1 39211051Sandreas.hansson@arm.com while nestLevel > 0: 39311051Sandreas.hansson@arm.com if code[here] == '(': 39411051Sandreas.hansson@arm.com nestLevel -= 1 39511199Sandreas.hansson@arm.com elif code[here] == ')': 39611199Sandreas.hansson@arm.com nestLevel += 1 39711199Sandreas.hansson@arm.com here -= 1 39811199Sandreas.hansson@arm.com if here < 0: 39911199Sandreas.hansson@arm.com sys.exit("Didn't find '('!") 40011284Sandreas.hansson@arm.com exprStart = here+1 40111284Sandreas.hansson@arm.com newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], 40211284Sandreas.hansson@arm.com match.group(1), match.group(2)) 40311284Sandreas.hansson@arm.com code = code[:exprStart] + newExpr + code[match.end():] 40411051Sandreas.hansson@arm.com match = bitOpExprRE.search(code) 40511051Sandreas.hansson@arm.com return code 40611051Sandreas.hansson@arm.com 40711051Sandreas.hansson@arm.com 40811051Sandreas.hansson@arm.com##################################################################### 40911051Sandreas.hansson@arm.com# 41011051Sandreas.hansson@arm.com# Code Parser 41111051Sandreas.hansson@arm.com# 41211051Sandreas.hansson@arm.com# The remaining code is the support for automatically extracting 41311484Snikos.nikoleris@arm.com# instruction characteristics from pseudocode. 41411051Sandreas.hansson@arm.com# 41511051Sandreas.hansson@arm.com##################################################################### 41611051Sandreas.hansson@arm.com 41711051Sandreas.hansson@arm.com# Force the argument to be a list. Useful for flags, where a caller 41811051Sandreas.hansson@arm.com# can specify a singleton flag or a list of flags. Also usful for 41911051Sandreas.hansson@arm.com# converting tuples to lists so they can be modified. 42011051Sandreas.hansson@arm.comdef makeList(arg): 42111051Sandreas.hansson@arm.com if isinstance(arg, list): 42211051Sandreas.hansson@arm.com return arg 42311051Sandreas.hansson@arm.com elif isinstance(arg, tuple): 42411051Sandreas.hansson@arm.com return list(arg) 42512345Snikos.nikoleris@arm.com elif not arg: 42612345Snikos.nikoleris@arm.com return [] 42712345Snikos.nikoleris@arm.com else: 42812345Snikos.nikoleris@arm.com return [ arg ] 42912345Snikos.nikoleris@arm.com 43012345Snikos.nikoleris@arm.comclass Operand(object): 43112345Snikos.nikoleris@arm.com '''Base class for operand descriptors. An instance of this class 43212345Snikos.nikoleris@arm.com (or actually a class derived from this one) represents a specific 43312346Snikos.nikoleris@arm.com operand for a code block (e.g, "Rc.sq" as a dest). Intermediate 43412346Snikos.nikoleris@arm.com derived classes encapsulates the traits of a particular operand 43512346Snikos.nikoleris@arm.com type (e.g., "32-bit integer register").''' 43612345Snikos.nikoleris@arm.com 43712346Snikos.nikoleris@arm.com def buildReadCode(self, func = None): 43812346Snikos.nikoleris@arm.com subst_dict = {"name": self.base_name, 43912346Snikos.nikoleris@arm.com "func": func, 44012346Snikos.nikoleris@arm.com "reg_idx": self.reg_spec, 44112346Snikos.nikoleris@arm.com "ctype": self.ctype} 44212346Snikos.nikoleris@arm.com if hasattr(self, 'src_reg_idx'): 44312346Snikos.nikoleris@arm.com subst_dict['op_idx'] = self.src_reg_idx 44412346Snikos.nikoleris@arm.com code = self.read_code % subst_dict 44512346Snikos.nikoleris@arm.com return '%s = %s;\n' % (self.base_name, code) 44612346Snikos.nikoleris@arm.com 44712346Snikos.nikoleris@arm.com def buildWriteCode(self, func = None): 44812346Snikos.nikoleris@arm.com subst_dict = {"name": self.base_name, 44912346Snikos.nikoleris@arm.com "func": func, 45012346Snikos.nikoleris@arm.com "reg_idx": self.reg_spec, 45112346Snikos.nikoleris@arm.com "ctype": self.ctype, 45212346Snikos.nikoleris@arm.com "final_val": self.base_name} 45312345Snikos.nikoleris@arm.com if hasattr(self, 'dest_reg_idx'): 45412345Snikos.nikoleris@arm.com subst_dict['op_idx'] = self.dest_reg_idx 45512345Snikos.nikoleris@arm.com code = self.write_code % subst_dict 45612345Snikos.nikoleris@arm.com return ''' 45712345Snikos.nikoleris@arm.com { 45812345Snikos.nikoleris@arm.com %s final_val = %s; 45912345Snikos.nikoleris@arm.com %s; 46012346Snikos.nikoleris@arm.com if (traceData) { traceData->setData(final_val); } 46112346Snikos.nikoleris@arm.com }''' % (self.dflt_ctype, self.base_name, code) 46212346Snikos.nikoleris@arm.com 46312345Snikos.nikoleris@arm.com def __init__(self, parser, full_name, ext, is_src, is_dest): 46412345Snikos.nikoleris@arm.com self.full_name = full_name 46512345Snikos.nikoleris@arm.com self.ext = ext 46612345Snikos.nikoleris@arm.com self.is_src = is_src 46712345Snikos.nikoleris@arm.com self.is_dest = is_dest 46812345Snikos.nikoleris@arm.com # The 'effective extension' (eff_ext) is either the actual 46912345Snikos.nikoleris@arm.com # extension, if one was explicitly provided, or the default. 47012345Snikos.nikoleris@arm.com if ext: 47112345Snikos.nikoleris@arm.com self.eff_ext = ext 47212346Snikos.nikoleris@arm.com elif hasattr(self, 'dflt_ext'): 47312346Snikos.nikoleris@arm.com self.eff_ext = self.dflt_ext 47412346Snikos.nikoleris@arm.com 47511601Sandreas.hansson@arm.com if hasattr(self, 'eff_ext'): 47611601Sandreas.hansson@arm.com self.ctype = parser.operandTypeMap[self.eff_ext] 47711051Sandreas.hansson@arm.com 47811051Sandreas.hansson@arm.com # Finalize additional fields (primarily code fields). This step 47911601Sandreas.hansson@arm.com # is done separately since some of these fields may depend on the 48011601Sandreas.hansson@arm.com # register index enumeration that hasn't been performed yet at the 48111601Sandreas.hansson@arm.com # time of __init__(). The register index enumeration is affected 48211051Sandreas.hansson@arm.com # by predicated register reads/writes. Hence, we forward the flags 48311051Sandreas.hansson@arm.com # that indicate whether or not predication is in use. 48411051Sandreas.hansson@arm.com def finalize(self, predRead, predWrite): 48511484Snikos.nikoleris@arm.com self.flags = self.getFlags() 48611284Sandreas.hansson@arm.com self.constructor = self.makeConstructor(predRead, predWrite) 48711051Sandreas.hansson@arm.com self.op_decl = self.makeDecl() 48811051Sandreas.hansson@arm.com 48911051Sandreas.hansson@arm.com if self.is_src: 49011484Snikos.nikoleris@arm.com self.op_rd = self.makeRead(predRead) 49111051Sandreas.hansson@arm.com self.op_src_decl = self.makeDecl() 49211051Sandreas.hansson@arm.com else: 49311051Sandreas.hansson@arm.com self.op_rd = '' 49411051Sandreas.hansson@arm.com self.op_src_decl = '' 49511051Sandreas.hansson@arm.com 49611051Sandreas.hansson@arm.com if self.is_dest: 49711051Sandreas.hansson@arm.com self.op_wb = self.makeWrite(predWrite) 49811051Sandreas.hansson@arm.com self.op_dest_decl = self.makeDecl() 49911051Sandreas.hansson@arm.com else: 50011601Sandreas.hansson@arm.com self.op_wb = '' 50111601Sandreas.hansson@arm.com self.op_dest_decl = '' 50211601Sandreas.hansson@arm.com 50311601Sandreas.hansson@arm.com def isMem(self): 50411601Sandreas.hansson@arm.com return 0 50511601Sandreas.hansson@arm.com 50611601Sandreas.hansson@arm.com def isReg(self): 50711601Sandreas.hansson@arm.com return 0 50811601Sandreas.hansson@arm.com 50911601Sandreas.hansson@arm.com def isFloatReg(self): 51011601Sandreas.hansson@arm.com return 0 51111601Sandreas.hansson@arm.com 51211051Sandreas.hansson@arm.com def isIntReg(self): 51311051Sandreas.hansson@arm.com return 0 51411051Sandreas.hansson@arm.com 51511051Sandreas.hansson@arm.com def isCCReg(self): 51611051Sandreas.hansson@arm.com return 0 51712345Snikos.nikoleris@arm.com 51812345Snikos.nikoleris@arm.com def isControlReg(self): 51912345Snikos.nikoleris@arm.com return 0 52012345Snikos.nikoleris@arm.com 52111051Sandreas.hansson@arm.com def isPCState(self): 52211051Sandreas.hansson@arm.com return 0 52311051Sandreas.hansson@arm.com 52411051Sandreas.hansson@arm.com def isPCPart(self): 52511051Sandreas.hansson@arm.com return self.isPCState() and self.reg_spec 52611051Sandreas.hansson@arm.com 52711051Sandreas.hansson@arm.com def hasReadPred(self): 52811199Sandreas.hansson@arm.com return self.read_predicate != None 52911199Sandreas.hansson@arm.com 53011199Sandreas.hansson@arm.com def hasWritePred(self): 53111199Sandreas.hansson@arm.com return self.write_predicate != None 53211199Sandreas.hansson@arm.com 53311051Sandreas.hansson@arm.com def getFlags(self): 53412345Snikos.nikoleris@arm.com # note the empty slice '[:]' gives us a copy of self.flags[0] 53512345Snikos.nikoleris@arm.com # instead of a reference to it 53611051Sandreas.hansson@arm.com my_flags = self.flags[0][:] 53711051Sandreas.hansson@arm.com if self.is_src: 53811051Sandreas.hansson@arm.com my_flags += self.flags[1] 53911051Sandreas.hansson@arm.com if self.is_dest: 54011051Sandreas.hansson@arm.com my_flags += self.flags[2] 54111051Sandreas.hansson@arm.com return my_flags 54211051Sandreas.hansson@arm.com 54311051Sandreas.hansson@arm.com def makeDecl(self): 54411051Sandreas.hansson@arm.com # Note that initializations in the declarations are solely 54511051Sandreas.hansson@arm.com # to avoid 'uninitialized variable' errors from the compiler. 54611051Sandreas.hansson@arm.com return self.ctype + ' ' + self.base_name + ' = 0;\n'; 54711051Sandreas.hansson@arm.com 54811051Sandreas.hansson@arm.comclass IntRegOperand(Operand): 54911051Sandreas.hansson@arm.com def isReg(self): 55011051Sandreas.hansson@arm.com return 1 55111051Sandreas.hansson@arm.com 55211051Sandreas.hansson@arm.com def isIntReg(self): 55311130Sali.jafri@arm.com return 1 55411130Sali.jafri@arm.com 55511130Sali.jafri@arm.com def makeConstructor(self, predRead, predWrite): 55611130Sali.jafri@arm.com c_src = '' 55711130Sali.jafri@arm.com c_dest = '' 55811130Sali.jafri@arm.com 55911130Sali.jafri@arm.com if self.is_src: 56011130Sali.jafri@arm.com c_src = '\n\t_srcRegIdx[_numSrcRegs++] = %s;' % (self.reg_spec) 56111130Sali.jafri@arm.com if self.hasReadPred(): 56212345Snikos.nikoleris@arm.com c_src = '\n\tif (%s) {%s\n\t}' % \ 56312345Snikos.nikoleris@arm.com (self.read_predicate, c_src) 56411130Sali.jafri@arm.com 56511130Sali.jafri@arm.com if self.is_dest: 56611130Sali.jafri@arm.com c_dest = '\n\t_destRegIdx[_numDestRegs++] = %s;' % \ 56711130Sali.jafri@arm.com (self.reg_spec) 56811130Sali.jafri@arm.com c_dest += '\n\t_numIntDestRegs++;' 56911130Sali.jafri@arm.com if self.hasWritePred(): 57011130Sali.jafri@arm.com c_dest = '\n\tif (%s) {%s\n\t}' % \ 57111130Sali.jafri@arm.com (self.write_predicate, c_dest) 57211130Sali.jafri@arm.com 57311130Sali.jafri@arm.com return c_src + c_dest 57411130Sali.jafri@arm.com 57511130Sali.jafri@arm.com def makeRead(self, predRead): 57611130Sali.jafri@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 57711130Sali.jafri@arm.com error('Attempt to read integer register as FP') 57811130Sali.jafri@arm.com if self.read_code != None: 57911130Sali.jafri@arm.com return self.buildReadCode('readIntRegOperand') 58011130Sali.jafri@arm.com 58111130Sali.jafri@arm.com int_reg_val = '' 58211130Sali.jafri@arm.com if predRead: 58311130Sali.jafri@arm.com int_reg_val = 'xc->readIntRegOperand(this, _sourceIndex++)' 58411130Sali.jafri@arm.com if self.hasReadPred(): 58511130Sali.jafri@arm.com int_reg_val = '(%s) ? %s : 0' % \ 58611130Sali.jafri@arm.com (self.read_predicate, int_reg_val) 58711051Sandreas.hansson@arm.com else: 58811051Sandreas.hansson@arm.com int_reg_val = 'xc->readIntRegOperand(this, %d)' % self.src_reg_idx 58911051Sandreas.hansson@arm.com 59011051Sandreas.hansson@arm.com return '%s = %s;\n' % (self.base_name, int_reg_val) 59111744Snikos.nikoleris@arm.com 59211051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 59311051Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 59411051Sandreas.hansson@arm.com error('Attempt to write integer register as FP') 59511051Sandreas.hansson@arm.com if self.write_code != None: 59611276Sandreas.hansson@arm.com return self.buildWriteCode('setIntRegOperand') 59711276Sandreas.hansson@arm.com 59811276Sandreas.hansson@arm.com if predWrite: 59911276Sandreas.hansson@arm.com wp = 'true' 60011276Sandreas.hansson@arm.com if self.hasWritePred(): 60111276Sandreas.hansson@arm.com wp = self.write_predicate 60211276Sandreas.hansson@arm.com 60311276Sandreas.hansson@arm.com wcond = 'if (%s)' % (wp) 60411276Sandreas.hansson@arm.com windex = '_destIndex++' 60511051Sandreas.hansson@arm.com else: 60611276Sandreas.hansson@arm.com wcond = '' 60711276Sandreas.hansson@arm.com windex = '%d' % self.dest_reg_idx 60811276Sandreas.hansson@arm.com 60911276Sandreas.hansson@arm.com wb = ''' 61011276Sandreas.hansson@arm.com %s 61111051Sandreas.hansson@arm.com { 61211051Sandreas.hansson@arm.com %s final_val = %s; 61311051Sandreas.hansson@arm.com xc->setIntRegOperand(this, %s, final_val);\n 61411051Sandreas.hansson@arm.com if (traceData) { traceData->setData(final_val); } 61511051Sandreas.hansson@arm.com }''' % (wcond, self.ctype, self.base_name, windex) 61611051Sandreas.hansson@arm.com 61711051Sandreas.hansson@arm.com return wb 61811051Sandreas.hansson@arm.com 61911051Sandreas.hansson@arm.comclass FloatRegOperand(Operand): 62011051Sandreas.hansson@arm.com def isReg(self): 62111051Sandreas.hansson@arm.com return 1 62211051Sandreas.hansson@arm.com 62311051Sandreas.hansson@arm.com def isFloatReg(self): 62411051Sandreas.hansson@arm.com return 1 62511051Sandreas.hansson@arm.com 62611051Sandreas.hansson@arm.com def makeConstructor(self, predRead, predWrite): 62711051Sandreas.hansson@arm.com c_src = '' 62811051Sandreas.hansson@arm.com c_dest = '' 62911051Sandreas.hansson@arm.com 63011051Sandreas.hansson@arm.com if self.is_src: 63111051Sandreas.hansson@arm.com c_src = '\n\t_srcRegIdx[_numSrcRegs++] = %s + FP_Reg_Base;' % \ 63211051Sandreas.hansson@arm.com (self.reg_spec) 63311051Sandreas.hansson@arm.com 63411051Sandreas.hansson@arm.com if self.is_dest: 63511051Sandreas.hansson@arm.com c_dest = \ 63611051Sandreas.hansson@arm.com '\n\t_destRegIdx[_numDestRegs++] = %s + FP_Reg_Base;' % \ 63711051Sandreas.hansson@arm.com (self.reg_spec) 63811051Sandreas.hansson@arm.com c_dest += '\n\t_numFPDestRegs++;' 63911830Sbaz21@cam.ac.uk 64011051Sandreas.hansson@arm.com return c_src + c_dest 64111051Sandreas.hansson@arm.com 64211051Sandreas.hansson@arm.com def makeRead(self, predRead): 64311051Sandreas.hansson@arm.com bit_select = 0 64411051Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 64511051Sandreas.hansson@arm.com func = 'readFloatRegOperand' 64611051Sandreas.hansson@arm.com else: 64711051Sandreas.hansson@arm.com func = 'readFloatRegOperandBits' 64811051Sandreas.hansson@arm.com if self.read_code != None: 64911051Sandreas.hansson@arm.com return self.buildReadCode(func) 65011051Sandreas.hansson@arm.com 65111051Sandreas.hansson@arm.com if predRead: 65211051Sandreas.hansson@arm.com rindex = '_sourceIndex++' 65311284Sandreas.hansson@arm.com else: 65411051Sandreas.hansson@arm.com rindex = '%d' % self.src_reg_idx 65511284Sandreas.hansson@arm.com 65611284Sandreas.hansson@arm.com return '%s = xc->%s(this, %s);\n' % \ 65711744Snikos.nikoleris@arm.com (self.base_name, func, rindex) 65811744Snikos.nikoleris@arm.com 65911051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 66011284Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 66111284Sandreas.hansson@arm.com func = 'setFloatRegOperand' 66211284Sandreas.hansson@arm.com else: 66311284Sandreas.hansson@arm.com func = 'setFloatRegOperandBits' 66411284Sandreas.hansson@arm.com if self.write_code != None: 66511334Sandreas.hansson@arm.com return self.buildWriteCode(func) 66611284Sandreas.hansson@arm.com 66711334Sandreas.hansson@arm.com if predWrite: 66811334Sandreas.hansson@arm.com wp = '_destIndex++' 66911334Sandreas.hansson@arm.com else: 67011334Sandreas.hansson@arm.com wp = '%d' % self.dest_reg_idx 67111284Sandreas.hansson@arm.com wp = 'xc->%s(this, %s, final_val);' % (func, wp) 67211334Sandreas.hansson@arm.com 67311334Sandreas.hansson@arm.com wb = ''' 67411334Sandreas.hansson@arm.com { 67511334Sandreas.hansson@arm.com %s final_val = %s; 67611334Sandreas.hansson@arm.com %s\n 67711334Sandreas.hansson@arm.com if (traceData) { traceData->setData(final_val); } 67811051Sandreas.hansson@arm.com }''' % (self.ctype, self.base_name, wp) 67911334Sandreas.hansson@arm.com return wb 68011334Sandreas.hansson@arm.com 68111334Sandreas.hansson@arm.comclass CCRegOperand(Operand): 68211334Sandreas.hansson@arm.com def isReg(self): 68311051Sandreas.hansson@arm.com return 1 68411334Sandreas.hansson@arm.com 68511334Sandreas.hansson@arm.com def isCCReg(self): 68611334Sandreas.hansson@arm.com return 1 68711051Sandreas.hansson@arm.com 68811334Sandreas.hansson@arm.com def makeConstructor(self, predRead, predWrite): 68911334Sandreas.hansson@arm.com c_src = '' 69011334Sandreas.hansson@arm.com c_dest = '' 69111334Sandreas.hansson@arm.com 69211334Sandreas.hansson@arm.com if self.is_src: 69311334Sandreas.hansson@arm.com c_src = '\n\t_srcRegIdx[_numSrcRegs++] = %s + CC_Reg_Base;' % \ 69411334Sandreas.hansson@arm.com (self.reg_spec) 69511051Sandreas.hansson@arm.com if self.hasReadPred(): 69611334Sandreas.hansson@arm.com c_src = '\n\tif (%s) {%s\n\t}' % \ 69711334Sandreas.hansson@arm.com (self.read_predicate, c_src) 69811334Sandreas.hansson@arm.com 69911334Sandreas.hansson@arm.com if self.is_dest: 70011334Sandreas.hansson@arm.com c_dest = \ 70111334Sandreas.hansson@arm.com '\n\t_destRegIdx[_numDestRegs++] = %s + CC_Reg_Base;' % \ 70211334Sandreas.hansson@arm.com (self.reg_spec) 70311334Sandreas.hansson@arm.com c_dest += '\n\t_numCCDestRegs++;' 70411051Sandreas.hansson@arm.com if self.hasWritePred(): 70511284Sandreas.hansson@arm.com c_dest = '\n\tif (%s) {%s\n\t}' % \ 70611284Sandreas.hansson@arm.com (self.write_predicate, c_dest) 70711190Sandreas.hansson@arm.com 70811051Sandreas.hansson@arm.com return c_src + c_dest 70911334Sandreas.hansson@arm.com 71011334Sandreas.hansson@arm.com def makeRead(self, predRead): 71111334Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 71211334Sandreas.hansson@arm.com error('Attempt to read condition-code register as FP') 71311334Sandreas.hansson@arm.com if self.read_code != None: 71411051Sandreas.hansson@arm.com return self.buildReadCode('readCCRegOperand') 71511051Sandreas.hansson@arm.com 71611051Sandreas.hansson@arm.com int_reg_val = '' 71711051Sandreas.hansson@arm.com if predRead: 71811051Sandreas.hansson@arm.com int_reg_val = 'xc->readCCRegOperand(this, _sourceIndex++)' 71911051Sandreas.hansson@arm.com if self.hasReadPred(): 72011051Sandreas.hansson@arm.com int_reg_val = '(%s) ? %s : 0' % \ 72111051Sandreas.hansson@arm.com (self.read_predicate, int_reg_val) 72211051Sandreas.hansson@arm.com else: 72311051Sandreas.hansson@arm.com int_reg_val = 'xc->readCCRegOperand(this, %d)' % self.src_reg_idx 72411484Snikos.nikoleris@arm.com 72511051Sandreas.hansson@arm.com return '%s = %s;\n' % (self.base_name, int_reg_val) 72611051Sandreas.hansson@arm.com 72711051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 72811051Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 72911051Sandreas.hansson@arm.com error('Attempt to write condition-code register as FP') 73011051Sandreas.hansson@arm.com if self.write_code != None: 73111051Sandreas.hansson@arm.com return self.buildWriteCode('setCCRegOperand') 73211051Sandreas.hansson@arm.com 73311051Sandreas.hansson@arm.com if predWrite: 73411051Sandreas.hansson@arm.com wp = 'true' 73511051Sandreas.hansson@arm.com if self.hasWritePred(): 73611051Sandreas.hansson@arm.com wp = self.write_predicate 73711051Sandreas.hansson@arm.com 73811051Sandreas.hansson@arm.com wcond = 'if (%s)' % (wp) 73911051Sandreas.hansson@arm.com windex = '_destIndex++' 74011051Sandreas.hansson@arm.com else: 74111051Sandreas.hansson@arm.com wcond = '' 74211051Sandreas.hansson@arm.com windex = '%d' % self.dest_reg_idx 74311051Sandreas.hansson@arm.com 74411051Sandreas.hansson@arm.com wb = ''' 74511051Sandreas.hansson@arm.com %s 74611051Sandreas.hansson@arm.com { 74711051Sandreas.hansson@arm.com %s final_val = %s; 74811051Sandreas.hansson@arm.com xc->setCCRegOperand(this, %s, final_val);\n 74911051Sandreas.hansson@arm.com if (traceData) { traceData->setData(final_val); } 75011051Sandreas.hansson@arm.com }''' % (wcond, self.ctype, self.base_name, windex) 75111051Sandreas.hansson@arm.com 75211051Sandreas.hansson@arm.com return wb 75311051Sandreas.hansson@arm.com 75411051Sandreas.hansson@arm.comclass ControlRegOperand(Operand): 75511051Sandreas.hansson@arm.com def isReg(self): 75611051Sandreas.hansson@arm.com return 1 75711051Sandreas.hansson@arm.com 75811051Sandreas.hansson@arm.com def isControlReg(self): 75911051Sandreas.hansson@arm.com return 1 76011483Snikos.nikoleris@arm.com 76111483Snikos.nikoleris@arm.com def makeConstructor(self, predRead, predWrite): 76211051Sandreas.hansson@arm.com c_src = '' 76311051Sandreas.hansson@arm.com c_dest = '' 76411051Sandreas.hansson@arm.com 76511051Sandreas.hansson@arm.com if self.is_src: 76611051Sandreas.hansson@arm.com c_src = \ 76711051Sandreas.hansson@arm.com '\n\t_srcRegIdx[_numSrcRegs++] = %s + Misc_Reg_Base;' % \ 76811051Sandreas.hansson@arm.com (self.reg_spec) 76911051Sandreas.hansson@arm.com 77011051Sandreas.hansson@arm.com if self.is_dest: 77111051Sandreas.hansson@arm.com c_dest = \ 77211051Sandreas.hansson@arm.com '\n\t_destRegIdx[_numDestRegs++] = %s + Misc_Reg_Base;' % \ 77311051Sandreas.hansson@arm.com (self.reg_spec) 77411051Sandreas.hansson@arm.com 77511051Sandreas.hansson@arm.com return c_src + c_dest 77611051Sandreas.hansson@arm.com 77711051Sandreas.hansson@arm.com def makeRead(self, predRead): 77811051Sandreas.hansson@arm.com bit_select = 0 77911051Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 78011194Sali.jafri@arm.com error('Attempt to read control register as FP') 78111051Sandreas.hansson@arm.com if self.read_code != None: 78211744Snikos.nikoleris@arm.com return self.buildReadCode('readMiscRegOperand') 78311744Snikos.nikoleris@arm.com 78411199Sandreas.hansson@arm.com if predRead: 78511190Sandreas.hansson@arm.com rindex = '_sourceIndex++' 78611190Sandreas.hansson@arm.com else: 78711190Sandreas.hansson@arm.com rindex = '%d' % self.src_reg_idx 78811190Sandreas.hansson@arm.com 78911190Sandreas.hansson@arm.com return '%s = xc->readMiscRegOperand(this, %s);\n' % \ 79011051Sandreas.hansson@arm.com (self.base_name, rindex) 79111051Sandreas.hansson@arm.com 79211051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 79311051Sandreas.hansson@arm.com if (self.ctype == 'float' or self.ctype == 'double'): 79411892Snikos.nikoleris@arm.com error('Attempt to write control register as FP') 79511051Sandreas.hansson@arm.com if self.write_code != None: 79611051Sandreas.hansson@arm.com return self.buildWriteCode('setMiscRegOperand') 79711051Sandreas.hansson@arm.com 79811051Sandreas.hansson@arm.com if predWrite: 79911051Sandreas.hansson@arm.com windex = '_destIndex++' 80011051Sandreas.hansson@arm.com else: 80111051Sandreas.hansson@arm.com windex = '%d' % self.dest_reg_idx 80211051Sandreas.hansson@arm.com 80311051Sandreas.hansson@arm.com wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \ 80411051Sandreas.hansson@arm.com (windex, self.base_name) 80511051Sandreas.hansson@arm.com wb += 'if (traceData) { traceData->setData(%s); }' % \ 80611051Sandreas.hansson@arm.com self.base_name 80711051Sandreas.hansson@arm.com 80811051Sandreas.hansson@arm.com return wb 80911051Sandreas.hansson@arm.com 81011051Sandreas.hansson@arm.comclass MemOperand(Operand): 81111051Sandreas.hansson@arm.com def isMem(self): 81211051Sandreas.hansson@arm.com return 1 81311051Sandreas.hansson@arm.com 81411051Sandreas.hansson@arm.com def makeConstructor(self, predRead, predWrite): 81511051Sandreas.hansson@arm.com return '' 81611051Sandreas.hansson@arm.com 81711051Sandreas.hansson@arm.com def makeDecl(self): 81811051Sandreas.hansson@arm.com # Note that initializations in the declarations are solely 81911051Sandreas.hansson@arm.com # to avoid 'uninitialized variable' errors from the compiler. 82011051Sandreas.hansson@arm.com # Declare memory data variable. 82111051Sandreas.hansson@arm.com return '%s %s = 0;\n' % (self.ctype, self.base_name) 82211051Sandreas.hansson@arm.com 82311051Sandreas.hansson@arm.com def makeRead(self, predRead): 82411051Sandreas.hansson@arm.com if self.read_code != None: 82511051Sandreas.hansson@arm.com return self.buildReadCode() 82611051Sandreas.hansson@arm.com return '' 82711051Sandreas.hansson@arm.com 82811051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 82911051Sandreas.hansson@arm.com if self.write_code != None: 83011051Sandreas.hansson@arm.com return self.buildWriteCode() 83111051Sandreas.hansson@arm.com return '' 83211051Sandreas.hansson@arm.com 83311051Sandreas.hansson@arm.comclass PCStateOperand(Operand): 83411286Sandreas.hansson@arm.com def makeConstructor(self, predRead, predWrite): 83511051Sandreas.hansson@arm.com return '' 83611051Sandreas.hansson@arm.com 83711194Sali.jafri@arm.com def makeRead(self, predRead): 83811051Sandreas.hansson@arm.com if self.reg_spec: 83911051Sandreas.hansson@arm.com # A component of the PC state. 84011051Sandreas.hansson@arm.com return '%s = __parserAutoPCState.%s();\n' % \ 84111051Sandreas.hansson@arm.com (self.base_name, self.reg_spec) 84211051Sandreas.hansson@arm.com else: 84311051Sandreas.hansson@arm.com # The whole PC state itself. 84411051Sandreas.hansson@arm.com return '%s = xc->pcState();\n' % self.base_name 84511051Sandreas.hansson@arm.com 84611051Sandreas.hansson@arm.com def makeWrite(self, predWrite): 84711051Sandreas.hansson@arm.com if self.reg_spec: 84811051Sandreas.hansson@arm.com # A component of the PC state. 84911051Sandreas.hansson@arm.com return '__parserAutoPCState.%s(%s);\n' % \ 85011051Sandreas.hansson@arm.com (self.reg_spec, self.base_name) 85111051Sandreas.hansson@arm.com else: 85211051Sandreas.hansson@arm.com # The whole PC state itself. 85311199Sandreas.hansson@arm.com return 'xc->pcState(%s);\n' % self.base_name 85411199Sandreas.hansson@arm.com 85511199Sandreas.hansson@arm.com def makeDecl(self): 85611051Sandreas.hansson@arm.com ctype = 'TheISA::PCState' 85711190Sandreas.hansson@arm.com if self.isPCPart(): 85811051Sandreas.hansson@arm.com ctype = self.ctype 85911744Snikos.nikoleris@arm.com # Note that initializations in the declarations are solely 86011744Snikos.nikoleris@arm.com # to avoid 'uninitialized variable' errors from the compiler. 86111051Sandreas.hansson@arm.com return '%s %s = 0;\n' % (ctype, self.base_name) 86211051Sandreas.hansson@arm.com 86311051Sandreas.hansson@arm.com def isPCState(self): 86411051Sandreas.hansson@arm.com return 1 86511051Sandreas.hansson@arm.com 86611051Sandreas.hansson@arm.comclass OperandList(object): 86711051Sandreas.hansson@arm.com '''Find all the operands in the given code block. Returns an operand 86811051Sandreas.hansson@arm.com descriptor list (instance of class OperandList).''' 86911051Sandreas.hansson@arm.com def __init__(self, parser, code): 87011051Sandreas.hansson@arm.com self.items = [] 87111197Sandreas.hansson@arm.com self.bases = {} 87211197Sandreas.hansson@arm.com # delete strings and comments so we don't match on operands inside 87311051Sandreas.hansson@arm.com for regEx in (stringRE, commentRE): 87411051Sandreas.hansson@arm.com code = regEx.sub('', code) 87511051Sandreas.hansson@arm.com # search for operands 87611051Sandreas.hansson@arm.com next_pos = 0 87711051Sandreas.hansson@arm.com while 1: 87811051Sandreas.hansson@arm.com match = parser.operandsRE.search(code, next_pos) 87911051Sandreas.hansson@arm.com if not match: 88011051Sandreas.hansson@arm.com # no more matches: we're done 88111051Sandreas.hansson@arm.com break 88211051Sandreas.hansson@arm.com op = match.groups() 88311483Snikos.nikoleris@arm.com # regexp groups are operand full name, base, and extension 88411483Snikos.nikoleris@arm.com (op_full, op_base, op_ext) = op 88511051Sandreas.hansson@arm.com # if the token following the operand is an assignment, this is 88611051Sandreas.hansson@arm.com # a destination (LHS), else it's a source (RHS) 88711483Snikos.nikoleris@arm.com is_dest = (assignRE.match(code, match.end()) != None) 88811483Snikos.nikoleris@arm.com is_src = not is_dest 88911051Sandreas.hansson@arm.com # see if we've already seen this one 89011051Sandreas.hansson@arm.com op_desc = self.find_base(op_base) 89111051Sandreas.hansson@arm.com if op_desc: 89211051Sandreas.hansson@arm.com if op_desc.ext != op_ext: 89311051Sandreas.hansson@arm.com error('Inconsistent extensions for operand %s' % \ 89411051Sandreas.hansson@arm.com op_base) 89511051Sandreas.hansson@arm.com op_desc.is_src = op_desc.is_src or is_src 89611051Sandreas.hansson@arm.com op_desc.is_dest = op_desc.is_dest or is_dest 89711051Sandreas.hansson@arm.com else: 89811051Sandreas.hansson@arm.com # new operand: create new descriptor 89911051Sandreas.hansson@arm.com op_desc = parser.operandNameMap[op_base](parser, 90011051Sandreas.hansson@arm.com op_full, op_ext, is_src, is_dest) 90111051Sandreas.hansson@arm.com self.append(op_desc) 90211051Sandreas.hansson@arm.com # start next search after end of current match 90311051Sandreas.hansson@arm.com next_pos = match.end() 90412345Snikos.nikoleris@arm.com self.sort() 90511051Sandreas.hansson@arm.com # enumerate source & dest register operands... used in building 90611051Sandreas.hansson@arm.com # constructor later 90711051Sandreas.hansson@arm.com self.numSrcRegs = 0 90811051Sandreas.hansson@arm.com self.numDestRegs = 0 90911051Sandreas.hansson@arm.com self.numFPDestRegs = 0 91011051Sandreas.hansson@arm.com self.numIntDestRegs = 0 91111051Sandreas.hansson@arm.com self.numCCDestRegs = 0 91211051Sandreas.hansson@arm.com self.numMiscDestRegs = 0 91311051Sandreas.hansson@arm.com self.memOperand = None 91411051Sandreas.hansson@arm.com 91511051Sandreas.hansson@arm.com # Flags to keep track if one or more operands are to be read/written 91611051Sandreas.hansson@arm.com # conditionally. 91711051Sandreas.hansson@arm.com self.predRead = False 91811051Sandreas.hansson@arm.com self.predWrite = False 91911051Sandreas.hansson@arm.com 92011051Sandreas.hansson@arm.com for op_desc in self.items: 92111051Sandreas.hansson@arm.com if op_desc.isReg(): 92211051Sandreas.hansson@arm.com if op_desc.is_src: 92311051Sandreas.hansson@arm.com op_desc.src_reg_idx = self.numSrcRegs 92411051Sandreas.hansson@arm.com self.numSrcRegs += 1 92511051Sandreas.hansson@arm.com if op_desc.is_dest: 92611051Sandreas.hansson@arm.com op_desc.dest_reg_idx = self.numDestRegs 92711051Sandreas.hansson@arm.com self.numDestRegs += 1 92811051Sandreas.hansson@arm.com if op_desc.isFloatReg(): 92911284Sandreas.hansson@arm.com self.numFPDestRegs += 1 93011051Sandreas.hansson@arm.com elif op_desc.isIntReg(): 93111051Sandreas.hansson@arm.com self.numIntDestRegs += 1 93211051Sandreas.hansson@arm.com elif op_desc.isCCReg(): 93311051Sandreas.hansson@arm.com self.numCCDestRegs += 1 93411051Sandreas.hansson@arm.com elif op_desc.isControlReg(): 93511051Sandreas.hansson@arm.com self.numMiscDestRegs += 1 93611051Sandreas.hansson@arm.com elif op_desc.isMem(): 93711051Sandreas.hansson@arm.com if self.memOperand: 93811051Sandreas.hansson@arm.com error("Code block has more than one memory operand.") 93911051Sandreas.hansson@arm.com self.memOperand = op_desc 94011051Sandreas.hansson@arm.com 94111051Sandreas.hansson@arm.com # Check if this operand has read/write predication. If true, then 94211051Sandreas.hansson@arm.com # the microop will dynamically index source/dest registers. 94311051Sandreas.hansson@arm.com self.predRead = self.predRead or op_desc.hasReadPred() 94411051Sandreas.hansson@arm.com self.predWrite = self.predWrite or op_desc.hasWritePred() 94511051Sandreas.hansson@arm.com 94611051Sandreas.hansson@arm.com if parser.maxInstSrcRegs < self.numSrcRegs: 94711051Sandreas.hansson@arm.com parser.maxInstSrcRegs = self.numSrcRegs 94811051Sandreas.hansson@arm.com if parser.maxInstDestRegs < self.numDestRegs: 94911051Sandreas.hansson@arm.com parser.maxInstDestRegs = self.numDestRegs 95011051Sandreas.hansson@arm.com if parser.maxMiscDestRegs < self.numMiscDestRegs: 95111051Sandreas.hansson@arm.com parser.maxMiscDestRegs = self.numMiscDestRegs 95211051Sandreas.hansson@arm.com 95311051Sandreas.hansson@arm.com # now make a final pass to finalize op_desc fields that may depend 95411452Sandreas.hansson@arm.com # on the register enumeration 95511452Sandreas.hansson@arm.com for op_desc in self.items: 95611051Sandreas.hansson@arm.com op_desc.finalize(self.predRead, self.predWrite) 95711452Sandreas.hansson@arm.com 95811452Sandreas.hansson@arm.com def __len__(self): 95911452Sandreas.hansson@arm.com return len(self.items) 96011051Sandreas.hansson@arm.com 96111051Sandreas.hansson@arm.com def __getitem__(self, index): 96211452Sandreas.hansson@arm.com return self.items[index] 96311745Sandreas.hansson@arm.com 96411745Sandreas.hansson@arm.com def append(self, op_desc): 96511452Sandreas.hansson@arm.com self.items.append(op_desc) 96611452Sandreas.hansson@arm.com self.bases[op_desc.base_name] = op_desc 96711452Sandreas.hansson@arm.com 96811051Sandreas.hansson@arm.com def find_base(self, base_name): 96911051Sandreas.hansson@arm.com # like self.bases[base_name], but returns None if not found 97011051Sandreas.hansson@arm.com # (rather than raising exception) 97111051Sandreas.hansson@arm.com return self.bases.get(base_name) 97211051Sandreas.hansson@arm.com 97311051Sandreas.hansson@arm.com # internal helper function for concat[Some]Attr{Strings|Lists} 97411051Sandreas.hansson@arm.com def __internalConcatAttrs(self, attr_name, filter, result): 97511051Sandreas.hansson@arm.com for op_desc in self.items: 97611051Sandreas.hansson@arm.com if filter(op_desc): 97711051Sandreas.hansson@arm.com result += getattr(op_desc, attr_name) 97811747Snikos.nikoleris@arm.com return result 97911747Snikos.nikoleris@arm.com 98011747Snikos.nikoleris@arm.com # return a single string that is the concatenation of the (string) 98111747Snikos.nikoleris@arm.com # values of the specified attribute for all operands 98211747Snikos.nikoleris@arm.com def concatAttrStrings(self, attr_name): 98311747Snikos.nikoleris@arm.com return self.__internalConcatAttrs(attr_name, lambda x: 1, '') 98411747Snikos.nikoleris@arm.com 98511284Sandreas.hansson@arm.com # like concatAttrStrings, but only include the values for the operands 98611284Sandreas.hansson@arm.com # for which the provided filter function returns true 98711284Sandreas.hansson@arm.com def concatSomeAttrStrings(self, filter, attr_name): 98811051Sandreas.hansson@arm.com return self.__internalConcatAttrs(attr_name, filter, '') 98911051Sandreas.hansson@arm.com 99011051Sandreas.hansson@arm.com # return a single list that is the concatenation of the (list) 99111051Sandreas.hansson@arm.com # values of the specified attribute for all operands 99211051Sandreas.hansson@arm.com def concatAttrLists(self, attr_name): 99311051Sandreas.hansson@arm.com return self.__internalConcatAttrs(attr_name, lambda x: 1, []) 99411051Sandreas.hansson@arm.com 99511051Sandreas.hansson@arm.com # like concatAttrLists, but only include the values for the operands 99611051Sandreas.hansson@arm.com # for which the provided filter function returns true 99711051Sandreas.hansson@arm.com def concatSomeAttrLists(self, filter, attr_name): 99811051Sandreas.hansson@arm.com return self.__internalConcatAttrs(attr_name, filter, []) 99911284Sandreas.hansson@arm.com 100011051Sandreas.hansson@arm.com def sort(self): 100111051Sandreas.hansson@arm.com self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) 100211051Sandreas.hansson@arm.com 100311051Sandreas.hansson@arm.comclass SubOperandList(OperandList): 100411284Sandreas.hansson@arm.com '''Find all the operands in the given code block. Returns an operand 100511284Sandreas.hansson@arm.com descriptor list (instance of class OperandList).''' 100611284Sandreas.hansson@arm.com def __init__(self, parser, code, master_list): 100711602Sandreas.hansson@arm.com self.items = [] 100811051Sandreas.hansson@arm.com self.bases = {} 100911051Sandreas.hansson@arm.com # delete strings and comments so we don't match on operands inside 101011051Sandreas.hansson@arm.com for regEx in (stringRE, commentRE): 101111284Sandreas.hansson@arm.com code = regEx.sub('', code) 101211284Sandreas.hansson@arm.com # search for operands 101311744Snikos.nikoleris@arm.com next_pos = 0 101411744Snikos.nikoleris@arm.com while 1: 101511051Sandreas.hansson@arm.com match = parser.operandsRE.search(code, next_pos) 101611051Sandreas.hansson@arm.com if not match: 101711051Sandreas.hansson@arm.com # no more matches: we're done 101811892Snikos.nikoleris@arm.com break 101911051Sandreas.hansson@arm.com op = match.groups() 102011051Sandreas.hansson@arm.com # regexp groups are operand full name, base, and extension 102111744Snikos.nikoleris@arm.com (op_full, op_base, op_ext) = op 102211744Snikos.nikoleris@arm.com # find this op in the master list 102311051Sandreas.hansson@arm.com op_desc = master_list.find_base(op_base) 102411051Sandreas.hansson@arm.com if not op_desc: 102511051Sandreas.hansson@arm.com error('Found operand %s which is not in the master list!' \ 102611051Sandreas.hansson@arm.com ' This is an internal error' % op_base) 102711051Sandreas.hansson@arm.com else: 102811051Sandreas.hansson@arm.com # See if we've already found this operand 102911051Sandreas.hansson@arm.com op_desc = self.find_base(op_base) 103011051Sandreas.hansson@arm.com if not op_desc: 103111051Sandreas.hansson@arm.com # if not, add a reference to it to this sub list 103211051Sandreas.hansson@arm.com self.append(master_list.bases[op_base]) 103311051Sandreas.hansson@arm.com 103411051Sandreas.hansson@arm.com # start next search after end of current match 103511051Sandreas.hansson@arm.com next_pos = match.end() 103611051Sandreas.hansson@arm.com self.sort() 103711051Sandreas.hansson@arm.com self.memOperand = None 103811051Sandreas.hansson@arm.com # Whether the whole PC needs to be read so parts of it can be accessed 103911333Sandreas.hansson@arm.com self.readPC = False 104011333Sandreas.hansson@arm.com # Whether the whole PC needs to be written after parts of it were 104111284Sandreas.hansson@arm.com # changed 104211744Snikos.nikoleris@arm.com self.setPC = False 104311744Snikos.nikoleris@arm.com # Whether this instruction manipulates the whole PC or parts of it. 104411333Sandreas.hansson@arm.com # Mixing the two is a bad idea and flagged as an error. 104511333Sandreas.hansson@arm.com self.pcPart = None 104611333Sandreas.hansson@arm.com 104711333Sandreas.hansson@arm.com # Flags to keep track if one or more operands are to be read/written 104811334Sandreas.hansson@arm.com # conditionally. 104911334Sandreas.hansson@arm.com self.predRead = False 105011051Sandreas.hansson@arm.com self.predWrite = False 105111051Sandreas.hansson@arm.com 105211051Sandreas.hansson@arm.com for op_desc in self.items: 105311051Sandreas.hansson@arm.com if op_desc.isPCPart(): 105411051Sandreas.hansson@arm.com self.readPC = True 105511051Sandreas.hansson@arm.com if op_desc.is_dest: 105611051Sandreas.hansson@arm.com self.setPC = True 105711051Sandreas.hansson@arm.com 105811484Snikos.nikoleris@arm.com if op_desc.isPCState(): 105911051Sandreas.hansson@arm.com if self.pcPart is not None: 106011051Sandreas.hansson@arm.com if self.pcPart and not op_desc.isPCPart() or \ 106111051Sandreas.hansson@arm.com not self.pcPart and op_desc.isPCPart(): 106211051Sandreas.hansson@arm.com error("Mixed whole and partial PC state operands.") 106311051Sandreas.hansson@arm.com self.pcPart = op_desc.isPCPart() 106411130Sali.jafri@arm.com 106511051Sandreas.hansson@arm.com if op_desc.isMem(): 106611051Sandreas.hansson@arm.com if self.memOperand: 106711051Sandreas.hansson@arm.com error("Code block has more than one memory operand.") 106811051Sandreas.hansson@arm.com self.memOperand = op_desc 106911452Sandreas.hansson@arm.com 107012345Snikos.nikoleris@arm.com # Check if this operand has read/write predication. If true, then 107112345Snikos.nikoleris@arm.com # the microop will dynamically index source/dest registers. 107211452Sandreas.hansson@arm.com self.predRead = self.predRead or op_desc.hasReadPred() 107311452Sandreas.hansson@arm.com self.predWrite = self.predWrite or op_desc.hasWritePred() 107411452Sandreas.hansson@arm.com 107511452Sandreas.hansson@arm.com# Regular expression object to match C++ strings 107611452Sandreas.hansson@arm.comstringRE = re.compile(r'"([^"\\]|\\.)*"') 107711452Sandreas.hansson@arm.com 107811452Sandreas.hansson@arm.com# Regular expression object to match C++ comments 107911051Sandreas.hansson@arm.com# (used in findOperands()) 108011484Snikos.nikoleris@arm.comcommentRE = re.compile(r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?', 108111051Sandreas.hansson@arm.com re.DOTALL | re.MULTILINE) 108211051Sandreas.hansson@arm.com 108311051Sandreas.hansson@arm.com# Regular expression object to match assignment statements 108411051Sandreas.hansson@arm.com# (used in findOperands()) 108511051Sandreas.hansson@arm.comassignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) 108611051Sandreas.hansson@arm.com 108711051Sandreas.hansson@arm.comdef makeFlagConstructor(flag_list): 108811744Snikos.nikoleris@arm.com if len(flag_list) == 0: 108911744Snikos.nikoleris@arm.com return '' 109011051Sandreas.hansson@arm.com # filter out repeated flags 109111051Sandreas.hansson@arm.com flag_list.sort() 109211051Sandreas.hansson@arm.com i = 1 109311051Sandreas.hansson@arm.com while i < len(flag_list): 109411051Sandreas.hansson@arm.com if flag_list[i] == flag_list[i-1]: 109511051Sandreas.hansson@arm.com del flag_list[i] 109611051Sandreas.hansson@arm.com else: 109711452Sandreas.hansson@arm.com i += 1 109811452Sandreas.hansson@arm.com pre = '\n\tflags[' 109911051Sandreas.hansson@arm.com post = '] = true;' 110011744Snikos.nikoleris@arm.com code = pre + string.join(flag_list, post + pre) + post 110111744Snikos.nikoleris@arm.com return code 110211051Sandreas.hansson@arm.com 110311051Sandreas.hansson@arm.com# Assume all instruction flags are of the form 'IsFoo' 110411051Sandreas.hansson@arm.cominstFlagRE = re.compile(r'Is.*') 110511051Sandreas.hansson@arm.com 110611051Sandreas.hansson@arm.com# OpClass constants end in 'Op' except No_OpClass 110711051Sandreas.hansson@arm.comopClassRE = re.compile(r'.*Op|No_OpClass') 110811051Sandreas.hansson@arm.com 110911051Sandreas.hansson@arm.comclass InstObjParams(object): 111011051Sandreas.hansson@arm.com def __init__(self, parser, mnem, class_name, base_class = '', 111111051Sandreas.hansson@arm.com snippets = {}, opt_args = []): 111211051Sandreas.hansson@arm.com self.mnemonic = mnem 111311051Sandreas.hansson@arm.com self.class_name = class_name 111411051Sandreas.hansson@arm.com self.base_class = base_class 111511051Sandreas.hansson@arm.com if not isinstance(snippets, dict): 111611051Sandreas.hansson@arm.com snippets = {'code' : snippets} 111711051Sandreas.hansson@arm.com compositeCode = ' '.join(map(str, snippets.values())) 111811197Sandreas.hansson@arm.com self.snippets = snippets 111911197Sandreas.hansson@arm.com 112011452Sandreas.hansson@arm.com self.operands = OperandList(parser, compositeCode) 112111452Sandreas.hansson@arm.com 112211601Sandreas.hansson@arm.com # The header of the constructor declares the variables to be used 112311051Sandreas.hansson@arm.com # in the body of the constructor. 112411051Sandreas.hansson@arm.com header = '' 112511051Sandreas.hansson@arm.com header += '\n\t_numSrcRegs = 0;' 112611051Sandreas.hansson@arm.com header += '\n\t_numDestRegs = 0;' 112711197Sandreas.hansson@arm.com header += '\n\t_numFPDestRegs = 0;' 112811197Sandreas.hansson@arm.com header += '\n\t_numIntDestRegs = 0;' 112911601Sandreas.hansson@arm.com header += '\n\t_numCCDestRegs = 0;' 113011601Sandreas.hansson@arm.com 113111051Sandreas.hansson@arm.com self.constructor = header + \ 113211051Sandreas.hansson@arm.com self.operands.concatAttrStrings('constructor') 113311051Sandreas.hansson@arm.com 113411051Sandreas.hansson@arm.com self.flags = self.operands.concatAttrLists('flags') 113511051Sandreas.hansson@arm.com 113611051Sandreas.hansson@arm.com self.op_class = None 113711051Sandreas.hansson@arm.com 113811051Sandreas.hansson@arm.com # Optional arguments are assumed to be either StaticInst flags 113911452Sandreas.hansson@arm.com # or an OpClass value. To avoid having to import a complete 114011452Sandreas.hansson@arm.com # list of these values to match against, we do it ad-hoc 114111452Sandreas.hansson@arm.com # with regexps. 114211452Sandreas.hansson@arm.com for oa in opt_args: 114311051Sandreas.hansson@arm.com if instFlagRE.match(oa): 114411051Sandreas.hansson@arm.com self.flags.append(oa) 114511051Sandreas.hansson@arm.com elif opClassRE.match(oa): 114611051Sandreas.hansson@arm.com self.op_class = oa 114711051Sandreas.hansson@arm.com else: 114811051Sandreas.hansson@arm.com error('InstObjParams: optional arg "%s" not recognized ' 114911051Sandreas.hansson@arm.com 'as StaticInst::Flag or OpClass.' % oa) 115011051Sandreas.hansson@arm.com 115111051Sandreas.hansson@arm.com # Make a basic guess on the operand class if not set. 115211051Sandreas.hansson@arm.com # These are good enough for most cases. 115311051Sandreas.hansson@arm.com if not self.op_class: 115411051Sandreas.hansson@arm.com if 'IsStore' in self.flags: 115511051Sandreas.hansson@arm.com self.op_class = 'MemWriteOp' 115611197Sandreas.hansson@arm.com elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: 115711130Sali.jafri@arm.com self.op_class = 'MemReadOp' 115811051Sandreas.hansson@arm.com elif 'IsFloating' in self.flags: 115911197Sandreas.hansson@arm.com self.op_class = 'FloatAddOp' 116011197Sandreas.hansson@arm.com else: 116111197Sandreas.hansson@arm.com self.op_class = 'IntAluOp' 116211197Sandreas.hansson@arm.com 116311197Sandreas.hansson@arm.com # add flag initialization to contructor here to include 116411197Sandreas.hansson@arm.com # any flags added via opt_args 116511197Sandreas.hansson@arm.com self.constructor += makeFlagConstructor(self.flags) 116611197Sandreas.hansson@arm.com 116711197Sandreas.hansson@arm.com # if 'IsFloating' is set, add call to the FP enable check 116811197Sandreas.hansson@arm.com # function (which should be provided by isa_desc via a declare) 116911197Sandreas.hansson@arm.com if 'IsFloating' in self.flags: 117011197Sandreas.hansson@arm.com self.fp_enable_check = 'fault = checkFpEnableFault(xc);' 117111197Sandreas.hansson@arm.com else: 117211197Sandreas.hansson@arm.com self.fp_enable_check = '' 117311197Sandreas.hansson@arm.com 117411197Sandreas.hansson@arm.com############## 117511197Sandreas.hansson@arm.com# Stack: a simple stack object. Used for both formats (formatStack) 117611197Sandreas.hansson@arm.com# and default cases (defaultStack). Simply wraps a list to give more 117711197Sandreas.hansson@arm.com# stack-like syntax and enable initialization with an argument list 117811197Sandreas.hansson@arm.com# (as opposed to an argument that's a list). 117911199Sandreas.hansson@arm.com 118011199Sandreas.hansson@arm.comclass Stack(list): 118111867Snikos.nikoleris@arm.com def __init__(self, *items): 118211197Sandreas.hansson@arm.com list.__init__(self, items) 118311197Sandreas.hansson@arm.com 118411051Sandreas.hansson@arm.com def push(self, item): 118511051Sandreas.hansson@arm.com self.append(item); 118611051Sandreas.hansson@arm.com 118711051Sandreas.hansson@arm.com def top(self): 118811051Sandreas.hansson@arm.com return self[-1] 118911051Sandreas.hansson@arm.com 119011051Sandreas.hansson@arm.com####################### 119111051Sandreas.hansson@arm.com# 119211051Sandreas.hansson@arm.com# ISA Parser 119311051Sandreas.hansson@arm.com# parses ISA DSL and emits C++ headers and source 119411051Sandreas.hansson@arm.com# 119511051Sandreas.hansson@arm.com 119611051Sandreas.hansson@arm.comclass ISAParser(Grammar): 119711051Sandreas.hansson@arm.com class CpuModel(object): 119811051Sandreas.hansson@arm.com def __init__(self, name, filename, includes, strings): 119911051Sandreas.hansson@arm.com self.name = name 120011051Sandreas.hansson@arm.com self.filename = filename 120111051Sandreas.hansson@arm.com self.includes = includes 120211051Sandreas.hansson@arm.com self.strings = strings 120311051Sandreas.hansson@arm.com 120411051Sandreas.hansson@arm.com def __init__(self, output_dir): 120511051Sandreas.hansson@arm.com super(ISAParser, self).__init__() 120611892Snikos.nikoleris@arm.com self.output_dir = output_dir 120711051Sandreas.hansson@arm.com 120811051Sandreas.hansson@arm.com self.filename = None # for output file watermarking/scaremongering 120911051Sandreas.hansson@arm.com 121011051Sandreas.hansson@arm.com self.cpuModels = [ 121111051Sandreas.hansson@arm.com ISAParser.CpuModel('ExecContext', 121211051Sandreas.hansson@arm.com 'generic_cpu_exec.cc', 121311051Sandreas.hansson@arm.com '#include "cpu/exec_context.hh"', 121411051Sandreas.hansson@arm.com { "CPU_exec_context" : "ExecContext" }), 121511051Sandreas.hansson@arm.com ] 121611051Sandreas.hansson@arm.com 121711051Sandreas.hansson@arm.com # variable to hold templates 121811051Sandreas.hansson@arm.com self.templateMap = {} 121911051Sandreas.hansson@arm.com 122011051Sandreas.hansson@arm.com # This dictionary maps format name strings to Format objects. 122111051Sandreas.hansson@arm.com self.formatMap = {} 122211051Sandreas.hansson@arm.com 122311051Sandreas.hansson@arm.com # Track open files and, if applicable, how many chunks it has been 122411051Sandreas.hansson@arm.com # split into so far. 122511284Sandreas.hansson@arm.com self.files = {} 122611284Sandreas.hansson@arm.com self.splits = {} 122711051Sandreas.hansson@arm.com 122811051Sandreas.hansson@arm.com # isa_name / namespace identifier from namespace declaration. 122911284Sandreas.hansson@arm.com # before the namespace declaration, None. 123011051Sandreas.hansson@arm.com self.isa_name = None 123111051Sandreas.hansson@arm.com self.namespace = None 123211051Sandreas.hansson@arm.com 123311051Sandreas.hansson@arm.com # The format stack. 123411051Sandreas.hansson@arm.com self.formatStack = Stack(NoFormat()) 123511051Sandreas.hansson@arm.com 123611051Sandreas.hansson@arm.com # The default case stack. 123711744Snikos.nikoleris@arm.com self.defaultStack = Stack(None) 123811051Sandreas.hansson@arm.com 123911051Sandreas.hansson@arm.com # Stack that tracks current file and line number. Each 124011051Sandreas.hansson@arm.com # element is a tuple (filename, lineno) that records the 124111051Sandreas.hansson@arm.com # *current* filename and the line number in the *previous* 124211051Sandreas.hansson@arm.com # file where it was included. 124311051Sandreas.hansson@arm.com self.fileNameStack = Stack() 124411051Sandreas.hansson@arm.com 124511051Sandreas.hansson@arm.com symbols = ('makeList', 're', 'string') 124611051Sandreas.hansson@arm.com self.exportContext = dict([(s, eval(s)) for s in symbols]) 124711051Sandreas.hansson@arm.com 124811051Sandreas.hansson@arm.com self.maxInstSrcRegs = 0 124911051Sandreas.hansson@arm.com self.maxInstDestRegs = 0 125011051Sandreas.hansson@arm.com self.maxMiscDestRegs = 0 125111485Snikos.nikoleris@arm.com 125211051Sandreas.hansson@arm.com def __getitem__(self, i): # Allow object (self) to be 125311051Sandreas.hansson@arm.com return getattr(self, i) # passed to %-substitutions 125411051Sandreas.hansson@arm.com 125511051Sandreas.hansson@arm.com # Change the file suffix of a base filename: 125611051Sandreas.hansson@arm.com # (e.g.) decoder.cc -> decoder-g.cc.inc for 'global' outputs 125711051Sandreas.hansson@arm.com def suffixize(self, s, sec): 125811051Sandreas.hansson@arm.com extn = re.compile('(\.[^\.]+)$') # isolate extension 125911051Sandreas.hansson@arm.com if self.namespace: 126011051Sandreas.hansson@arm.com return extn.sub(r'-ns\1.inc', s) # insert some text on either side 126111051Sandreas.hansson@arm.com else: 126211051Sandreas.hansson@arm.com return extn.sub(r'-g\1.inc', s) 126311051Sandreas.hansson@arm.com 126411051Sandreas.hansson@arm.com # Get the file object for emitting code into the specified section 126511051Sandreas.hansson@arm.com # (header, decoder, exec, decode_block). 126611051Sandreas.hansson@arm.com def get_file(self, section): 126711051Sandreas.hansson@arm.com if section == 'decode_block': 126811375Sandreas.hansson@arm.com filename = 'decode-method.cc.inc' 126911375Sandreas.hansson@arm.com else: 127011375Sandreas.hansson@arm.com if section == 'header': 127111375Sandreas.hansson@arm.com file = 'decoder.hh' 127211375Sandreas.hansson@arm.com else: 127311453Sandreas.hansson@arm.com file = '%s.cc' % section 127411453Sandreas.hansson@arm.com filename = self.suffixize(file, section) 127511375Sandreas.hansson@arm.com try: 127611453Sandreas.hansson@arm.com return self.files[filename] 127711375Sandreas.hansson@arm.com except KeyError: pass 127811375Sandreas.hansson@arm.com 127911375Sandreas.hansson@arm.com f = self.open(filename) 128011051Sandreas.hansson@arm.com self.files[filename] = f 128111051Sandreas.hansson@arm.com 128211051Sandreas.hansson@arm.com # The splittable files are the ones with many independent 128311051Sandreas.hansson@arm.com # per-instruction functions - the decoder's instruction constructors 128411051Sandreas.hansson@arm.com # and the instruction execution (execute()) methods. These both have 128511051Sandreas.hansson@arm.com # the suffix -ns.cc.inc, meaning they are within the namespace part 128611051Sandreas.hansson@arm.com # of the ISA, contain object-emitting C++ source, and are included 128711051Sandreas.hansson@arm.com # into other top-level files. These are the files that need special 128811051Sandreas.hansson@arm.com # #define's to allow parts of them to be compiled separately. Rather 128911051Sandreas.hansson@arm.com # than splitting the emissions into separate files, the monolithic 129011051Sandreas.hansson@arm.com # output of the ISA parser is maintained, but the value (or lack 129111051Sandreas.hansson@arm.com # thereof) of the __SPLIT definition during C preprocessing will 129211744Snikos.nikoleris@arm.com # select the different chunks. If no 'split' directives are used, 129311744Snikos.nikoleris@arm.com # the cpp emissions have no effect. 129411051Sandreas.hansson@arm.com if re.search('-ns.cc.inc$', filename): 129511051Sandreas.hansson@arm.com print >>f, '#if !defined(__SPLIT) || (__SPLIT == 1)' 129611744Snikos.nikoleris@arm.com self.splits[f] = 1 129711744Snikos.nikoleris@arm.com # ensure requisite #include's 129811051Sandreas.hansson@arm.com elif filename in ['decoder-g.cc.inc', 'exec-g.cc.inc']: 129911375Sandreas.hansson@arm.com print >>f, '#include "decoder.hh"' 130011375Sandreas.hansson@arm.com elif filename == 'decoder-g.hh.inc': 130111375Sandreas.hansson@arm.com print >>f, '#include "base/bitfield.hh"' 130211375Sandreas.hansson@arm.com 130311375Sandreas.hansson@arm.com return f 130411375Sandreas.hansson@arm.com 130511375Sandreas.hansson@arm.com # Weave together the parts of the different output sections by 130611375Sandreas.hansson@arm.com # #include'ing them into some very short top-level .cc/.hh files. 130711375Sandreas.hansson@arm.com # These small files make it much clearer how this tool works, since 130811375Sandreas.hansson@arm.com # you directly see the chunks emitted as files that are #include'd. 130911453Sandreas.hansson@arm.com def write_top_level_files(self): 131011375Sandreas.hansson@arm.com dep = self.open('inc.d', bare=True) 131111051Sandreas.hansson@arm.com 131211051Sandreas.hansson@arm.com # decoder header - everything depends on this 131311051Sandreas.hansson@arm.com file = 'decoder.hh' 131411051Sandreas.hansson@arm.com with self.open(file) as f: 131511484Snikos.nikoleris@arm.com inc = [] 131611051Sandreas.hansson@arm.com 131711051Sandreas.hansson@arm.com fn = 'decoder-g.hh.inc' 131811051Sandreas.hansson@arm.com assert(fn in self.files) 131911051Sandreas.hansson@arm.com f.write('#include "%s"\n' % fn) 132011051Sandreas.hansson@arm.com inc.append(fn) 132111051Sandreas.hansson@arm.com 132211051Sandreas.hansson@arm.com fn = 'decoder-ns.hh.inc' 132311051Sandreas.hansson@arm.com assert(fn in self.files) 132411051Sandreas.hansson@arm.com f.write('namespace %s {\n#include "%s"\n}\n' 132511051Sandreas.hansson@arm.com % (self.namespace, fn)) 132611051Sandreas.hansson@arm.com inc.append(fn) 132711051Sandreas.hansson@arm.com 132811051Sandreas.hansson@arm.com print >>dep, file+':', ' '.join(inc) 132911051Sandreas.hansson@arm.com 133011051Sandreas.hansson@arm.com # decoder method - cannot be split 133111051Sandreas.hansson@arm.com file = 'decoder.cc' 133211051Sandreas.hansson@arm.com with self.open(file) as f: 133311375Sandreas.hansson@arm.com inc = [] 133411375Sandreas.hansson@arm.com 133511375Sandreas.hansson@arm.com fn = 'decoder-g.cc.inc' 133611375Sandreas.hansson@arm.com assert(fn in self.files) 133711375Sandreas.hansson@arm.com f.write('#include "%s"\n' % fn) 133811375Sandreas.hansson@arm.com inc.append(fn) 133911284Sandreas.hansson@arm.com 134011284Sandreas.hansson@arm.com fn = 'decode-method.cc.inc' 134111284Sandreas.hansson@arm.com # is guaranteed to have been written for parse to complete 134211284Sandreas.hansson@arm.com f.write('#include "%s"\n' % fn) 134311177Sandreas.hansson@arm.com inc.append(fn) 134411177Sandreas.hansson@arm.com 134511051Sandreas.hansson@arm.com inc.append("decoder.hh") 134611051Sandreas.hansson@arm.com print >>dep, file+':', ' '.join(inc) 134711051Sandreas.hansson@arm.com 134811177Sandreas.hansson@arm.com extn = re.compile('(\.[^\.]+)$') 134911177Sandreas.hansson@arm.com 135011051Sandreas.hansson@arm.com # instruction constructors 135111051Sandreas.hansson@arm.com splits = self.splits[self.get_file('decoder')] 135211051Sandreas.hansson@arm.com file_ = 'inst-constrs.cc' 135311051Sandreas.hansson@arm.com for i in range(1, splits+1): 135411741Snikos.nikoleris@arm.com if splits > 1: 135511484Snikos.nikoleris@arm.com file = extn.sub(r'-%d\1' % i, file_) 135611051Sandreas.hansson@arm.com else: 135711051Sandreas.hansson@arm.com file = file_ 135811051Sandreas.hansson@arm.com with self.open(file) as f: 135911051Sandreas.hansson@arm.com inc = [] 136011136Sandreas.hansson@arm.com 136111051Sandreas.hansson@arm.com fn = 'decoder-g.cc.inc' 136211051Sandreas.hansson@arm.com assert(fn in self.files) 136311051Sandreas.hansson@arm.com f.write('#include "%s"\n' % fn) 136411051Sandreas.hansson@arm.com inc.append(fn) 136511601Sandreas.hansson@arm.com 136611742Snikos.nikoleris@arm.com fn = 'decoder-ns.cc.inc' 136711742Snikos.nikoleris@arm.com assert(fn in self.files) 136811742Snikos.nikoleris@arm.com print >>f, 'namespace %s {' % self.namespace 136911742Snikos.nikoleris@arm.com if splits > 1: 137011051Sandreas.hansson@arm.com print >>f, '#define __SPLIT %u' % i 137111051Sandreas.hansson@arm.com print >>f, '#include "%s"' % fn 137211051Sandreas.hansson@arm.com print >>f, '}' 137311051Sandreas.hansson@arm.com inc.append(fn) 137411051Sandreas.hansson@arm.com 137511051Sandreas.hansson@arm.com inc.append("decoder.hh") 137611051Sandreas.hansson@arm.com print >>dep, file+':', ' '.join(inc) 137711051Sandreas.hansson@arm.com 137811483Snikos.nikoleris@arm.com # instruction execution per-CPU model 137911483Snikos.nikoleris@arm.com splits = self.splits[self.get_file('exec')] 138011483Snikos.nikoleris@arm.com for cpu in self.cpuModels: 138111483Snikos.nikoleris@arm.com for i in range(1, splits+1): 138211051Sandreas.hansson@arm.com if splits > 1: 138311051Sandreas.hansson@arm.com file = extn.sub(r'_%d\1' % i, cpu.filename) 138411051Sandreas.hansson@arm.com else: 138511051Sandreas.hansson@arm.com file = cpu.filename 138611051Sandreas.hansson@arm.com with self.open(file) as f: 138711601Sandreas.hansson@arm.com inc = [] 138811601Sandreas.hansson@arm.com 138911601Sandreas.hansson@arm.com fn = 'exec-g.cc.inc' 139011601Sandreas.hansson@arm.com assert(fn in self.files) 139111051Sandreas.hansson@arm.com f.write('#include "%s"\n' % fn) 139211051Sandreas.hansson@arm.com inc.append(fn) 139311051Sandreas.hansson@arm.com 139411051Sandreas.hansson@arm.com f.write(cpu.includes+"\n") 139511051Sandreas.hansson@arm.com 139611051Sandreas.hansson@arm.com fn = 'exec-ns.cc.inc' 139711051Sandreas.hansson@arm.com assert(fn in self.files) 139811051Sandreas.hansson@arm.com print >>f, 'namespace %s {' % self.namespace 139911284Sandreas.hansson@arm.com print >>f, '#define CPU_EXEC_CONTEXT %s' \ 140011284Sandreas.hansson@arm.com % cpu.strings['CPU_exec_context'] 140111284Sandreas.hansson@arm.com if splits > 1: 140211051Sandreas.hansson@arm.com print >>f, '#define __SPLIT %u' % i 140311741Snikos.nikoleris@arm.com print >>f, '#include "%s"' % fn 140411742Snikos.nikoleris@arm.com print >>f, '}' 140511484Snikos.nikoleris@arm.com inc.append(fn) 140611051Sandreas.hansson@arm.com 140711051Sandreas.hansson@arm.com inc.append("decoder.hh") 140811051Sandreas.hansson@arm.com print >>dep, file+':', ' '.join(inc) 140911051Sandreas.hansson@arm.com 141011136Sandreas.hansson@arm.com # max_inst_regs.hh 141111051Sandreas.hansson@arm.com self.update('max_inst_regs.hh', 141211051Sandreas.hansson@arm.com '''namespace %(namespace)s { 141311051Sandreas.hansson@arm.com const int MaxInstSrcRegs = %(maxInstSrcRegs)d; 141411601Sandreas.hansson@arm.com const int MaxInstDestRegs = %(maxInstDestRegs)d; 141511051Sandreas.hansson@arm.com const int MaxMiscDestRegs = %(maxMiscDestRegs)d;\n}\n''' % self) 141611051Sandreas.hansson@arm.com print >>dep, 'max_inst_regs.hh:' 141711051Sandreas.hansson@arm.com 141811051Sandreas.hansson@arm.com dep.close() 141911051Sandreas.hansson@arm.com 142011051Sandreas.hansson@arm.com 142111051Sandreas.hansson@arm.com scaremonger_template ='''// DO NOT EDIT 142211051Sandreas.hansson@arm.com// This file was automatically generated from an ISA description: 142311051Sandreas.hansson@arm.com// %(filename)s 142411051Sandreas.hansson@arm.com 142511051Sandreas.hansson@arm.com'''; 142611051Sandreas.hansson@arm.com 142711051Sandreas.hansson@arm.com ##################################################################### 142811051Sandreas.hansson@arm.com # 142911051Sandreas.hansson@arm.com # Lexer 143011051Sandreas.hansson@arm.com # 143111051Sandreas.hansson@arm.com # The PLY lexer module takes two things as input: 143211051Sandreas.hansson@arm.com # - A list of token names (the string list 'tokens') 143311051Sandreas.hansson@arm.com # - A regular expression describing a match for each token. The 143411742Snikos.nikoleris@arm.com # regexp for token FOO can be provided in two ways: 143511051Sandreas.hansson@arm.com # - as a string variable named t_FOO 143611051Sandreas.hansson@arm.com # - as the doc string for a function named t_FOO. In this case, 143711051Sandreas.hansson@arm.com # the function is also executed, allowing an action to be 143811051Sandreas.hansson@arm.com # associated with each token match. 143911051Sandreas.hansson@arm.com # 144011051Sandreas.hansson@arm.com ##################################################################### 144111051Sandreas.hansson@arm.com 144211051Sandreas.hansson@arm.com # Reserved words. These are listed separately as they are matched 144311051Sandreas.hansson@arm.com # using the same regexp as generic IDs, but distinguished in the 144411051Sandreas.hansson@arm.com # t_ID() function. The PLY documentation suggests this approach. 144511051Sandreas.hansson@arm.com reserved = ( 144611051Sandreas.hansson@arm.com 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', 144711750Snikos.nikoleris@arm.com 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', 144811750Snikos.nikoleris@arm.com 'OUTPUT', 'SIGNED', 'SPLIT', 'TEMPLATE' 144911750Snikos.nikoleris@arm.com ) 145011750Snikos.nikoleris@arm.com 145111750Snikos.nikoleris@arm.com # List of tokens. The lex module requires this. 145211750Snikos.nikoleris@arm.com tokens = reserved + ( 145311750Snikos.nikoleris@arm.com # identifier 145411750Snikos.nikoleris@arm.com 'ID', 145511750Snikos.nikoleris@arm.com 145611750Snikos.nikoleris@arm.com # integer literal 145711750Snikos.nikoleris@arm.com 'INTLIT', 145811051Sandreas.hansson@arm.com 145911051Sandreas.hansson@arm.com # string literal 146011051Sandreas.hansson@arm.com 'STRLIT', 146111051Sandreas.hansson@arm.com 146211051Sandreas.hansson@arm.com # code literal 146311051Sandreas.hansson@arm.com 'CODELIT', 146411051Sandreas.hansson@arm.com 146511051Sandreas.hansson@arm.com # ( ) [ ] { } < > , ; . : :: * 146611051Sandreas.hansson@arm.com 'LPAREN', 'RPAREN', 146711051Sandreas.hansson@arm.com 'LBRACKET', 'RBRACKET', 146811051Sandreas.hansson@arm.com 'LBRACE', 'RBRACE', 146911051Sandreas.hansson@arm.com 'LESS', 'GREATER', 'EQUALS', 147011051Sandreas.hansson@arm.com 'COMMA', 'SEMI', 'DOT', 'COLON', 'DBLCOLON', 147111051Sandreas.hansson@arm.com 'ASTERISK', 147211051Sandreas.hansson@arm.com 147311051Sandreas.hansson@arm.com # C preprocessor directives 147411051Sandreas.hansson@arm.com 'CPPDIRECTIVE' 147511051Sandreas.hansson@arm.com 147611136Sandreas.hansson@arm.com # The following are matched but never returned. commented out to 147711051Sandreas.hansson@arm.com # suppress PLY warning 147811051Sandreas.hansson@arm.com # newfile directive 147911051Sandreas.hansson@arm.com # 'NEWFILE', 148011051Sandreas.hansson@arm.com 148111744Snikos.nikoleris@arm.com # endfile directive 148211744Snikos.nikoleris@arm.com # 'ENDFILE' 148311051Sandreas.hansson@arm.com ) 148411051Sandreas.hansson@arm.com 148511051Sandreas.hansson@arm.com # Regular expressions for token matching 148611194Sali.jafri@arm.com t_LPAREN = r'\(' 148711051Sandreas.hansson@arm.com t_RPAREN = r'\)' 148811051Sandreas.hansson@arm.com t_LBRACKET = r'\[' 148911051Sandreas.hansson@arm.com t_RBRACKET = r'\]' 149011051Sandreas.hansson@arm.com t_LBRACE = r'\{' 149111051Sandreas.hansson@arm.com t_RBRACE = r'\}' 149211051Sandreas.hansson@arm.com t_LESS = r'\<' 149311051Sandreas.hansson@arm.com t_GREATER = r'\>' 149411051Sandreas.hansson@arm.com t_EQUALS = r'=' 149511051Sandreas.hansson@arm.com t_COMMA = r',' 149611051Sandreas.hansson@arm.com t_SEMI = r';' 149711051Sandreas.hansson@arm.com t_DOT = r'\.' 149811051Sandreas.hansson@arm.com t_COLON = r':' 149911051Sandreas.hansson@arm.com t_DBLCOLON = r'::' 150011051Sandreas.hansson@arm.com t_ASTERISK = r'\*' 150111051Sandreas.hansson@arm.com 150211749Snikos.nikoleris@arm.com # Identifiers and reserved words 150311749Snikos.nikoleris@arm.com reserved_map = { } 150411749Snikos.nikoleris@arm.com for r in reserved: 150511749Snikos.nikoleris@arm.com reserved_map[r.lower()] = r 150611749Snikos.nikoleris@arm.com 150711749Snikos.nikoleris@arm.com def t_ID(self, t): 150811749Snikos.nikoleris@arm.com r'[A-Za-z_]\w*' 150911749Snikos.nikoleris@arm.com t.type = self.reserved_map.get(t.value, 'ID') 151011749Snikos.nikoleris@arm.com return t 151111749Snikos.nikoleris@arm.com 151211749Snikos.nikoleris@arm.com # Integer literal 151311749Snikos.nikoleris@arm.com def t_INTLIT(self, t): 151411051Sandreas.hansson@arm.com r'-?(0x[\da-fA-F]+)|\d+' 151511051Sandreas.hansson@arm.com try: 151611051Sandreas.hansson@arm.com t.value = int(t.value,0) 151711051Sandreas.hansson@arm.com except ValueError: 151811742Snikos.nikoleris@arm.com error(t, 'Integer value "%s" too large' % t.value) 151911051Sandreas.hansson@arm.com t.value = 0 152011051Sandreas.hansson@arm.com return t 152111051Sandreas.hansson@arm.com 152211601Sandreas.hansson@arm.com # String literal. Note that these use only single quotes, and 152311601Sandreas.hansson@arm.com # can span multiple lines. 152411051Sandreas.hansson@arm.com def t_STRLIT(self, t): 152511051Sandreas.hansson@arm.com r"(?m)'([^'])+'" 152611051Sandreas.hansson@arm.com # strip off quotes 152711051Sandreas.hansson@arm.com t.value = t.value[1:-1] 152811136Sandreas.hansson@arm.com t.lexer.lineno += t.value.count('\n') 152911197Sandreas.hansson@arm.com return t 153011051Sandreas.hansson@arm.com 153111051Sandreas.hansson@arm.com 153211051Sandreas.hansson@arm.com # "Code literal"... like a string literal, but delimiters are 153311051Sandreas.hansson@arm.com # '{{' and '}}' so they get formatted nicely under emacs c-mode 153411051Sandreas.hansson@arm.com def t_CODELIT(self, t): 153511051Sandreas.hansson@arm.com r"(?m)\{\{([^\}]|}(?!\}))+\}\}" 153611051Sandreas.hansson@arm.com # strip off {{ & }} 153711051Sandreas.hansson@arm.com t.value = t.value[2:-2] 153811051Sandreas.hansson@arm.com t.lexer.lineno += t.value.count('\n') 153911051Sandreas.hansson@arm.com return t 154011051Sandreas.hansson@arm.com 154111375Sandreas.hansson@arm.com def t_CPPDIRECTIVE(self, t): 154211051Sandreas.hansson@arm.com r'^\#[^\#].*\n' 154311051Sandreas.hansson@arm.com t.lexer.lineno += t.value.count('\n') 154411375Sandreas.hansson@arm.com return t 154511375Sandreas.hansson@arm.com 154611375Sandreas.hansson@arm.com def t_NEWFILE(self, t): 154711051Sandreas.hansson@arm.com r'^\#\#newfile\s+"[^"]*"' 154811051Sandreas.hansson@arm.com self.fileNameStack.push((t.value[11:-1], t.lexer.lineno)) 154911051Sandreas.hansson@arm.com t.lexer.lineno = 0 155011051Sandreas.hansson@arm.com 155111375Sandreas.hansson@arm.com def t_ENDFILE(self, t): 155211051Sandreas.hansson@arm.com r'^\#\#endfile' 155311051Sandreas.hansson@arm.com (old_filename, t.lexer.lineno) = self.fileNameStack.pop() 155411051Sandreas.hansson@arm.com 155511051Sandreas.hansson@arm.com # 155611051Sandreas.hansson@arm.com # The functions t_NEWLINE, t_ignore, and t_error are 155711051Sandreas.hansson@arm.com # special for the lex module. 155811051Sandreas.hansson@arm.com # 155911051Sandreas.hansson@arm.com 156011051Sandreas.hansson@arm.com # Newlines 156111051Sandreas.hansson@arm.com def t_NEWLINE(self, t): 156211051Sandreas.hansson@arm.com r'\n+' 156311051Sandreas.hansson@arm.com t.lexer.lineno += t.value.count('\n') 156411051Sandreas.hansson@arm.com 156511051Sandreas.hansson@arm.com # Comments 156611051Sandreas.hansson@arm.com def t_comment(self, t): 156711051Sandreas.hansson@arm.com r'//.*' 156811051Sandreas.hansson@arm.com 156911051Sandreas.hansson@arm.com # Completely ignored characters 157011199Sandreas.hansson@arm.com t_ignore = ' \t\x0c' 157111051Sandreas.hansson@arm.com 157211051Sandreas.hansson@arm.com # Error handler 157311051Sandreas.hansson@arm.com def t_error(self, t): 157411051Sandreas.hansson@arm.com error(t, "illegal character '%s'" % t.value[0]) 157511051Sandreas.hansson@arm.com t.skip(1) 157611051Sandreas.hansson@arm.com 157711051Sandreas.hansson@arm.com ##################################################################### 157811051Sandreas.hansson@arm.com # 157911051Sandreas.hansson@arm.com # Parser 158011051Sandreas.hansson@arm.com # 158111051Sandreas.hansson@arm.com # Every function whose name starts with 'p_' defines a grammar 158211051Sandreas.hansson@arm.com # rule. The rule is encoded in the function's doc string, while 158311051Sandreas.hansson@arm.com # the function body provides the action taken when the rule is 158411051Sandreas.hansson@arm.com # matched. The argument to each function is a list of the values 158511867Snikos.nikoleris@arm.com # of the rule's symbols: t[0] for the LHS, and t[1..n] for the 158611051Sandreas.hansson@arm.com # symbols on the RHS. For tokens, the value is copied from the 158711051Sandreas.hansson@arm.com # t.value attribute provided by the lexer. For non-terminals, the 158811744Snikos.nikoleris@arm.com # value is assigned by the producing rule; i.e., the job of the 158911051Sandreas.hansson@arm.com # grammar rule function is to set the value for the non-terminal 159011051Sandreas.hansson@arm.com # on the LHS (by assigning to t[0]). 159111051Sandreas.hansson@arm.com ##################################################################### 159211051Sandreas.hansson@arm.com 159311051Sandreas.hansson@arm.com # The LHS of the first grammar rule is used as the start symbol 159411051Sandreas.hansson@arm.com # (in this case, 'specification'). Note that this rule enforces 159511199Sandreas.hansson@arm.com # that there will be exactly one namespace declaration, with 0 or 159611199Sandreas.hansson@arm.com # more global defs/decls before and after it. The defs & decls 159711199Sandreas.hansson@arm.com # before the namespace decl will be outside the namespace; those 159811051Sandreas.hansson@arm.com # after will be inside. The decoder function is always inside the 159911051Sandreas.hansson@arm.com # namespace. 160011051Sandreas.hansson@arm.com def p_specification(self, t): 160111199Sandreas.hansson@arm.com 'specification : opt_defs_and_outputs top_level_decode_block' 160211199Sandreas.hansson@arm.com 160311051Sandreas.hansson@arm.com for f in self.splits.iterkeys(): 160411199Sandreas.hansson@arm.com f.write('\n#endif\n') 160511051Sandreas.hansson@arm.com 160611199Sandreas.hansson@arm.com for f in self.files.itervalues(): # close ALL the files; 160711051Sandreas.hansson@arm.com f.close() # not doing so can cause compilation to fail 160811051Sandreas.hansson@arm.com 160911051Sandreas.hansson@arm.com self.write_top_level_files() 161011199Sandreas.hansson@arm.com 161111199Sandreas.hansson@arm.com t[0] = True 161211199Sandreas.hansson@arm.com 161311199Sandreas.hansson@arm.com # 'opt_defs_and_outputs' is a possibly empty sequence of def and/or 161411744Snikos.nikoleris@arm.com # output statements. Its productions do the hard work of eventually 161511744Snikos.nikoleris@arm.com # instantiating a GenCode, which are generally emitted (written to disk) 161611199Sandreas.hansson@arm.com # as soon as possible, except for the decode_block, which has to be 161711051Sandreas.hansson@arm.com # accumulated into one large function of nested switch/case blocks. 161811051Sandreas.hansson@arm.com def p_opt_defs_and_outputs_0(self, t): 161911051Sandreas.hansson@arm.com 'opt_defs_and_outputs : empty' 162011051Sandreas.hansson@arm.com 162111051Sandreas.hansson@arm.com def p_opt_defs_and_outputs_1(self, t): 162211284Sandreas.hansson@arm.com 'opt_defs_and_outputs : defs_and_outputs' 162311284Sandreas.hansson@arm.com 162411051Sandreas.hansson@arm.com def p_defs_and_outputs_0(self, t): 162511051Sandreas.hansson@arm.com 'defs_and_outputs : def_or_output' 162611199Sandreas.hansson@arm.com 162711199Sandreas.hansson@arm.com def p_defs_and_outputs_1(self, t): 162811051Sandreas.hansson@arm.com 'defs_and_outputs : defs_and_outputs def_or_output' 162911199Sandreas.hansson@arm.com 163011199Sandreas.hansson@arm.com # The list of possible definition/output statements. 163111199Sandreas.hansson@arm.com # They are all processed as they are seen. 163211199Sandreas.hansson@arm.com def p_def_or_output(self, t): 163311051Sandreas.hansson@arm.com '''def_or_output : name_decl 163411051Sandreas.hansson@arm.com | def_format 163511051Sandreas.hansson@arm.com | def_bitfield 163612346Snikos.nikoleris@arm.com | def_bitfield_struct 163712345Snikos.nikoleris@arm.com | def_template 163812345Snikos.nikoleris@arm.com | def_operand_types 163912345Snikos.nikoleris@arm.com | def_operands 164012345Snikos.nikoleris@arm.com | output 164112345Snikos.nikoleris@arm.com | global_let 164212345Snikos.nikoleris@arm.com | split''' 164312345Snikos.nikoleris@arm.com 164412345Snikos.nikoleris@arm.com # Utility function used by both invocations of splitting - explicit 164512345Snikos.nikoleris@arm.com # 'split' keyword and split() function inside "let {{ }};" blocks. 164612345Snikos.nikoleris@arm.com def split(self, sec, write=False): 164712345Snikos.nikoleris@arm.com assert(sec != 'header' and "header cannot be split") 164812345Snikos.nikoleris@arm.com 164912345Snikos.nikoleris@arm.com f = self.get_file(sec) 165012345Snikos.nikoleris@arm.com self.splits[f] += 1 165112345Snikos.nikoleris@arm.com s = '\n#endif\n#if __SPLIT == %u\n' % self.splits[f] 165212345Snikos.nikoleris@arm.com if write: 165312345Snikos.nikoleris@arm.com f.write(s) 165412346Snikos.nikoleris@arm.com else: 165512346Snikos.nikoleris@arm.com return s 165612346Snikos.nikoleris@arm.com 165712346Snikos.nikoleris@arm.com # split output file to reduce compilation time 165812345Snikos.nikoleris@arm.com def p_split(self, t): 165912345Snikos.nikoleris@arm.com 'split : SPLIT output_type SEMI' 166012345Snikos.nikoleris@arm.com assert(self.isa_name and "'split' not allowed before namespace decl") 166112345Snikos.nikoleris@arm.com 166212345Snikos.nikoleris@arm.com self.split(t[2], True) 166312345Snikos.nikoleris@arm.com 166411051Sandreas.hansson@arm.com def p_output_type(self, t): 166511051Sandreas.hansson@arm.com '''output_type : DECODER 166611199Sandreas.hansson@arm.com | HEADER 166711051Sandreas.hansson@arm.com | EXEC''' 166811051Sandreas.hansson@arm.com t[0] = t[1] 166911051Sandreas.hansson@arm.com 167011051Sandreas.hansson@arm.com # ISA name declaration looks like "namespace <foo>;" 167111051Sandreas.hansson@arm.com def p_name_decl(self, t): 167211051Sandreas.hansson@arm.com 'name_decl : NAMESPACE ID SEMI' 167311051Sandreas.hansson@arm.com assert(self.isa_name == None and "Only 1 namespace decl permitted") 167411051Sandreas.hansson@arm.com self.isa_name = t[2] 167511051Sandreas.hansson@arm.com self.namespace = t[2] + 'Inst' 167611051Sandreas.hansson@arm.com 167711051Sandreas.hansson@arm.com # Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied 167811051Sandreas.hansson@arm.com # directly to the appropriate output section. 167911051Sandreas.hansson@arm.com 168011051Sandreas.hansson@arm.com # Massage output block by substituting in template definitions and 168111744Snikos.nikoleris@arm.com # bit operators. We handle '%'s embedded in the string that don't 168211051Sandreas.hansson@arm.com # indicate template substitutions (or CPU-specific symbols, which 168311051Sandreas.hansson@arm.com # get handled in GenCode) by doubling them first so that the 168411051Sandreas.hansson@arm.com # format operation will reduce them back to single '%'s. 168511051Sandreas.hansson@arm.com def process_output(self, s): 168611051Sandreas.hansson@arm.com s = self.protectNonSubstPercents(s) 168711051Sandreas.hansson@arm.com # protects cpu-specific symbols too 168811051Sandreas.hansson@arm.com s = self.protectCpuSymbols(s) 168911051Sandreas.hansson@arm.com return substBitOps(s % self.templateMap) 169011051Sandreas.hansson@arm.com 169111051Sandreas.hansson@arm.com def p_output(self, t): 169211051Sandreas.hansson@arm.com 'output : OUTPUT output_type CODELIT SEMI' 169311051Sandreas.hansson@arm.com kwargs = { t[2]+'_output' : self.process_output(t[3]) } 169411051Sandreas.hansson@arm.com GenCode(self, **kwargs).emit() 169511051Sandreas.hansson@arm.com 169611051Sandreas.hansson@arm.com # global let blocks 'let {{...}}' (Python code blocks) are 169711051Sandreas.hansson@arm.com # executed directly when seen. Note that these execute in a 169811051Sandreas.hansson@arm.com # special variable context 'exportContext' to prevent the code 169911051Sandreas.hansson@arm.com # from polluting this script's namespace. 170011051Sandreas.hansson@arm.com def p_global_let(self, t): 170111051Sandreas.hansson@arm.com 'global_let : LET CODELIT SEMI' 170211051Sandreas.hansson@arm.com def _split(sec): 170311051Sandreas.hansson@arm.com return self.split(sec) 170411051Sandreas.hansson@arm.com self.updateExportContext() 170511051Sandreas.hansson@arm.com self.exportContext["header_output"] = '' 170611051Sandreas.hansson@arm.com self.exportContext["decoder_output"] = '' 170711051Sandreas.hansson@arm.com self.exportContext["exec_output"] = '' 170811051Sandreas.hansson@arm.com self.exportContext["decode_block"] = '' 170911051Sandreas.hansson@arm.com self.exportContext["split"] = _split 171011051Sandreas.hansson@arm.com split_setup = ''' 171111051Sandreas.hansson@arm.comdef wrap(func): 171211051Sandreas.hansson@arm.com def split(sec): 171311051Sandreas.hansson@arm.com globals()[sec + '_output'] += func(sec) 171411051Sandreas.hansson@arm.com return split 171511051Sandreas.hansson@arm.comsplit = wrap(split) 171611051Sandreas.hansson@arm.comdel wrap 171711051Sandreas.hansson@arm.com''' 171811865Snikos.nikoleris@arm.com # This tricky setup (immediately above) allows us to just write 171911865Snikos.nikoleris@arm.com # (e.g.) "split('exec')" in the Python code and the split #ifdef's 172011865Snikos.nikoleris@arm.com # will automatically be added to the exec_output variable. The inner 172111051Sandreas.hansson@arm.com # Python execution environment doesn't know about the split points, 172211051Sandreas.hansson@arm.com # so we carefully inject and wrap a closure that can retrieve the 172311051Sandreas.hansson@arm.com # next split's #define from the parser and add it to the current 172411051Sandreas.hansson@arm.com # emission-in-progress. 172511051Sandreas.hansson@arm.com try: 172611051Sandreas.hansson@arm.com exec split_setup+fixPythonIndentation(t[2]) in self.exportContext 172711051Sandreas.hansson@arm.com except Exception, exc: 172811051Sandreas.hansson@arm.com if debug: 172911051Sandreas.hansson@arm.com raise 173011051Sandreas.hansson@arm.com error(t, 'error: %s in global let block "%s".' % (exc, t[2])) 173111051Sandreas.hansson@arm.com GenCode(self, 173211051Sandreas.hansson@arm.com header_output=self.exportContext["header_output"], 173311051Sandreas.hansson@arm.com decoder_output=self.exportContext["decoder_output"], 173411051Sandreas.hansson@arm.com exec_output=self.exportContext["exec_output"], 173511051Sandreas.hansson@arm.com decode_block=self.exportContext["decode_block"]).emit() 173611051Sandreas.hansson@arm.com 173711051Sandreas.hansson@arm.com # Define the mapping from operand type extensions to C++ types and 173811051Sandreas.hansson@arm.com # bit widths (stored in operandTypeMap). 173911051Sandreas.hansson@arm.com def p_def_operand_types(self, t): 174011051Sandreas.hansson@arm.com 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' 174111051Sandreas.hansson@arm.com try: 174211867Snikos.nikoleris@arm.com self.operandTypeMap = eval('{' + t[3] + '}') 174311051Sandreas.hansson@arm.com except Exception, exc: 174411051Sandreas.hansson@arm.com if debug: 174511051Sandreas.hansson@arm.com raise 174611051Sandreas.hansson@arm.com error(t, 174711051Sandreas.hansson@arm.com 'error: %s in def operand_types block "%s".' % (exc, t[3])) 174811051Sandreas.hansson@arm.com 174911051Sandreas.hansson@arm.com # Define the mapping from operand names to operand classes and 175011051Sandreas.hansson@arm.com # other traits. Stored in operandNameMap. 175111051Sandreas.hansson@arm.com def p_def_operands(self, t): 175211051Sandreas.hansson@arm.com 'def_operands : DEF OPERANDS CODELIT SEMI' 175311484Snikos.nikoleris@arm.com if not hasattr(self, 'operandTypeMap'): 175411051Sandreas.hansson@arm.com error(t, 'error: operand types must be defined before operands') 175511051Sandreas.hansson@arm.com try: 175611051Sandreas.hansson@arm.com user_dict = eval('{' + t[3] + '}', self.exportContext) 175711051Sandreas.hansson@arm.com except Exception, exc: 175811051Sandreas.hansson@arm.com if debug: 175911051Sandreas.hansson@arm.com raise 176011051Sandreas.hansson@arm.com error(t, 'error: %s in def operands block "%s".' % (exc, t[3])) 176111051Sandreas.hansson@arm.com self.buildOperandNameMap(user_dict, t.lexer.lineno) 176211051Sandreas.hansson@arm.com 176311051Sandreas.hansson@arm.com # A bitfield definition looks like: 176411284Sandreas.hansson@arm.com # 'def [signed] bitfield <ID> [<first>:<last>]' 176511051Sandreas.hansson@arm.com # This generates a preprocessor macro in the output file. 176611051Sandreas.hansson@arm.com def p_def_bitfield_0(self, t): 176711484Snikos.nikoleris@arm.com 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' 176811051Sandreas.hansson@arm.com expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) 176911483Snikos.nikoleris@arm.com if (t[2] == 'signed'): 177011483Snikos.nikoleris@arm.com expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) 177111051Sandreas.hansson@arm.com hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 177211051Sandreas.hansson@arm.com GenCode(self, header_output=hash_define).emit() 177311051Sandreas.hansson@arm.com 177411436SRekai.GonzalezAlberquilla@arm.com # alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' 177511436SRekai.GonzalezAlberquilla@arm.com def p_def_bitfield_1(self, t): 177611436SRekai.GonzalezAlberquilla@arm.com 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' 177711051Sandreas.hansson@arm.com expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) 177811051Sandreas.hansson@arm.com if (t[2] == 'signed'): 177911199Sandreas.hansson@arm.com expr = 'sext<%d>(%s)' % (1, expr) 178011051Sandreas.hansson@arm.com hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 178111051Sandreas.hansson@arm.com GenCode(self, header_output=hash_define).emit() 178211051Sandreas.hansson@arm.com 178311051Sandreas.hansson@arm.com # alternate form for structure member: 'def bitfield <ID> <ID>' 178411051Sandreas.hansson@arm.com def p_def_bitfield_struct(self, t): 178511051Sandreas.hansson@arm.com 'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI' 178611051Sandreas.hansson@arm.com if (t[2] != ''): 178711051Sandreas.hansson@arm.com error(t, 'error: structure bitfields are always unsigned.') 178811051Sandreas.hansson@arm.com expr = 'machInst.%s' % t[5] 178911051Sandreas.hansson@arm.com hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) 179011051Sandreas.hansson@arm.com GenCode(self, header_output=hash_define).emit() 179111197Sandreas.hansson@arm.com 179211197Sandreas.hansson@arm.com def p_id_with_dot_0(self, t): 179311197Sandreas.hansson@arm.com 'id_with_dot : ID' 179411197Sandreas.hansson@arm.com t[0] = t[1] 179511197Sandreas.hansson@arm.com 179611197Sandreas.hansson@arm.com def p_id_with_dot_1(self, t): 179711197Sandreas.hansson@arm.com 'id_with_dot : ID DOT id_with_dot' 179811051Sandreas.hansson@arm.com t[0] = t[1] + t[2] + t[3] 179911051Sandreas.hansson@arm.com 180011051Sandreas.hansson@arm.com def p_opt_signed_0(self, t): 180111051Sandreas.hansson@arm.com 'opt_signed : SIGNED' 180211051Sandreas.hansson@arm.com t[0] = t[1] 180311051Sandreas.hansson@arm.com 180411051Sandreas.hansson@arm.com def p_opt_signed_1(self, t): 180511197Sandreas.hansson@arm.com 'opt_signed : empty' 180611197Sandreas.hansson@arm.com t[0] = '' 180711051Sandreas.hansson@arm.com 180811051Sandreas.hansson@arm.com def p_def_template(self, t): 180911051Sandreas.hansson@arm.com 'def_template : DEF TEMPLATE ID CODELIT SEMI' 181011051Sandreas.hansson@arm.com if t[3] in self.templateMap: 181111051Sandreas.hansson@arm.com print "warning: template %s already defined" % t[3] 181211051Sandreas.hansson@arm.com self.templateMap[t[3]] = Template(self, t[4]) 181311051Sandreas.hansson@arm.com 181411051Sandreas.hansson@arm.com # An instruction format definition looks like 181511375Sandreas.hansson@arm.com # "def format <fmt>(<params>) {{...}};" 181611892Snikos.nikoleris@arm.com def p_def_format(self, t): 181711375Sandreas.hansson@arm.com 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' 181811051Sandreas.hansson@arm.com (id, params, code) = (t[3], t[5], t[7]) 181911484Snikos.nikoleris@arm.com self.defFormat(id, params, code, t.lexer.lineno) 182011051Sandreas.hansson@arm.com 182111051Sandreas.hansson@arm.com # The formal parameter list for an instruction format is a 182211051Sandreas.hansson@arm.com # possibly empty list of comma-separated parameters. Positional 182311051Sandreas.hansson@arm.com # (standard, non-keyword) parameters must come first, followed by 182411051Sandreas.hansson@arm.com # keyword parameters, followed by a '*foo' parameter that gets 182511601Sandreas.hansson@arm.com # excess positional arguments (as in Python). Each of these three 182611051Sandreas.hansson@arm.com # parameter categories is optional. 182711051Sandreas.hansson@arm.com # 182811197Sandreas.hansson@arm.com # Note that we do not support the '**foo' parameter for collecting 182911197Sandreas.hansson@arm.com # otherwise undefined keyword args. Otherwise the parameter list 183011484Snikos.nikoleris@arm.com # is (I believe) identical to what is supported in Python. 183111197Sandreas.hansson@arm.com # 183211484Snikos.nikoleris@arm.com # The param list generates a tuple, where the first element is a 183311197Sandreas.hansson@arm.com # list of the positional params and the second element is a dict 183411197Sandreas.hansson@arm.com # containing the keyword params. 183511197Sandreas.hansson@arm.com def p_param_list_0(self, t): 183611051Sandreas.hansson@arm.com 'param_list : positional_param_list COMMA nonpositional_param_list' 183711051Sandreas.hansson@arm.com t[0] = t[1] + t[3] 183811051Sandreas.hansson@arm.com 183911051Sandreas.hansson@arm.com def p_param_list_1(self, t): 184011051Sandreas.hansson@arm.com '''param_list : positional_param_list 184111051Sandreas.hansson@arm.com | nonpositional_param_list''' 184211051Sandreas.hansson@arm.com t[0] = t[1] 184311051Sandreas.hansson@arm.com 184411051Sandreas.hansson@arm.com def p_positional_param_list_0(self, t): 184511051Sandreas.hansson@arm.com 'positional_param_list : empty' 184611051Sandreas.hansson@arm.com t[0] = [] 184711051Sandreas.hansson@arm.com 184811051Sandreas.hansson@arm.com def p_positional_param_list_1(self, t): 184911051Sandreas.hansson@arm.com 'positional_param_list : ID' 185011051Sandreas.hansson@arm.com t[0] = [t[1]] 185111051Sandreas.hansson@arm.com 185211051Sandreas.hansson@arm.com def p_positional_param_list_2(self, t): 185311051Sandreas.hansson@arm.com 'positional_param_list : positional_param_list COMMA ID' 185411051Sandreas.hansson@arm.com t[0] = t[1] + [t[3]] 185511051Sandreas.hansson@arm.com 185611051Sandreas.hansson@arm.com def p_nonpositional_param_list_0(self, t): 185711051Sandreas.hansson@arm.com 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' 185811051Sandreas.hansson@arm.com t[0] = t[1] + t[3] 185911051Sandreas.hansson@arm.com 186011051Sandreas.hansson@arm.com def p_nonpositional_param_list_1(self, t): 186111051Sandreas.hansson@arm.com '''nonpositional_param_list : keyword_param_list 186211137Sandreas.hansson@arm.com | excess_args_param''' 186311137Sandreas.hansson@arm.com t[0] = t[1] 186411601Sandreas.hansson@arm.com 186511137Sandreas.hansson@arm.com def p_keyword_param_list_0(self, t): 186611284Sandreas.hansson@arm.com 'keyword_param_list : keyword_param' 186711137Sandreas.hansson@arm.com t[0] = [t[1]] 186811137Sandreas.hansson@arm.com 186911284Sandreas.hansson@arm.com def p_keyword_param_list_1(self, t): 187011284Sandreas.hansson@arm.com 'keyword_param_list : keyword_param_list COMMA keyword_param' 187111284Sandreas.hansson@arm.com t[0] = t[1] + [t[3]] 187211284Sandreas.hansson@arm.com 187311284Sandreas.hansson@arm.com def p_keyword_param(self, t): 187411284Sandreas.hansson@arm.com 'keyword_param : ID EQUALS expr' 187511284Sandreas.hansson@arm.com t[0] = t[1] + ' = ' + t[3].__repr__() 187611284Sandreas.hansson@arm.com 187711284Sandreas.hansson@arm.com def p_excess_args_param(self, t): 187811284Sandreas.hansson@arm.com 'excess_args_param : ASTERISK ID' 187911284Sandreas.hansson@arm.com # Just concatenate them: '*ID'. Wrap in list to be consistent 188011051Sandreas.hansson@arm.com # with positional_param_list and keyword_param_list. 188111051Sandreas.hansson@arm.com t[0] = [t[1] + t[2]] 188211284Sandreas.hansson@arm.com 188311284Sandreas.hansson@arm.com # End of format definition-related rules. 188411284Sandreas.hansson@arm.com ############## 188511284Sandreas.hansson@arm.com 188611284Sandreas.hansson@arm.com # 188711051Sandreas.hansson@arm.com # A decode block looks like: 188811051Sandreas.hansson@arm.com # decode <field1> [, <field2>]* [default <inst>] { ... } 188911051Sandreas.hansson@arm.com # 189011051Sandreas.hansson@arm.com def p_top_level_decode_block(self, t): 189111051Sandreas.hansson@arm.com 'top_level_decode_block : decode_block' 189211051Sandreas.hansson@arm.com codeObj = t[1] 189311051Sandreas.hansson@arm.com codeObj.wrap_decode_block(''' 189411051Sandreas.hansson@arm.comStaticInstPtr 189511051Sandreas.hansson@arm.com%(isa_name)s::Decoder::decodeInst(%(isa_name)s::ExtMachInst machInst) 189611051Sandreas.hansson@arm.com{ 189711051Sandreas.hansson@arm.com using namespace %(namespace)s; 189811051Sandreas.hansson@arm.com''' % self, '}') 189911051Sandreas.hansson@arm.com 190011051Sandreas.hansson@arm.com codeObj.emit() 190111051Sandreas.hansson@arm.com 190211051Sandreas.hansson@arm.com def p_decode_block(self, t): 190311051Sandreas.hansson@arm.com 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' 190411051Sandreas.hansson@arm.com default_defaults = self.defaultStack.pop() 190511051Sandreas.hansson@arm.com codeObj = t[5] 190611051Sandreas.hansson@arm.com # use the "default defaults" only if there was no explicit 190711051Sandreas.hansson@arm.com # default statement in decode_stmt_list 190811051Sandreas.hansson@arm.com if not codeObj.has_decode_default: 190911051Sandreas.hansson@arm.com codeObj += default_defaults 191011051Sandreas.hansson@arm.com codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') 191111051Sandreas.hansson@arm.com t[0] = codeObj 191211051Sandreas.hansson@arm.com 191311051Sandreas.hansson@arm.com # The opt_default statement serves only to push the "default 191411051Sandreas.hansson@arm.com # defaults" onto defaultStack. This value will be used by nested 191511051Sandreas.hansson@arm.com # decode blocks, and used and popped off when the current 191611051Sandreas.hansson@arm.com # decode_block is processed (in p_decode_block() above). 191711051Sandreas.hansson@arm.com def p_opt_default_0(self, t): 191811051Sandreas.hansson@arm.com 'opt_default : empty' 191911051Sandreas.hansson@arm.com # no default specified: reuse the one currently at the top of 192011051Sandreas.hansson@arm.com # the stack 192111051Sandreas.hansson@arm.com self.defaultStack.push(self.defaultStack.top()) 192211051Sandreas.hansson@arm.com # no meaningful value returned 192311051Sandreas.hansson@arm.com t[0] = None 192411051Sandreas.hansson@arm.com 192511051Sandreas.hansson@arm.com def p_opt_default_1(self, t): 192611051Sandreas.hansson@arm.com 'opt_default : DEFAULT inst' 192711051Sandreas.hansson@arm.com # push the new default 192811744Snikos.nikoleris@arm.com codeObj = t[2] 192911051Sandreas.hansson@arm.com codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') 193011051Sandreas.hansson@arm.com self.defaultStack.push(codeObj) 193111051Sandreas.hansson@arm.com # no meaningful value returned 193211051Sandreas.hansson@arm.com t[0] = None 193311051Sandreas.hansson@arm.com 193411051Sandreas.hansson@arm.com def p_decode_stmt_list_0(self, t): 193511051Sandreas.hansson@arm.com 'decode_stmt_list : decode_stmt' 193611051Sandreas.hansson@arm.com t[0] = t[1] 193711051Sandreas.hansson@arm.com 193811051Sandreas.hansson@arm.com def p_decode_stmt_list_1(self, t): 193911284Sandreas.hansson@arm.com 'decode_stmt_list : decode_stmt decode_stmt_list' 194011051Sandreas.hansson@arm.com if (t[1].has_decode_default and t[2].has_decode_default): 194111051Sandreas.hansson@arm.com error(t, 'Two default cases in decode block') 194211051Sandreas.hansson@arm.com t[0] = t[1] + t[2] 194311051Sandreas.hansson@arm.com 194411051Sandreas.hansson@arm.com # 194511051Sandreas.hansson@arm.com # Decode statement rules 194611051Sandreas.hansson@arm.com # 194711284Sandreas.hansson@arm.com # There are four types of statements allowed in a decode block: 194811284Sandreas.hansson@arm.com # 1. Format blocks 'format <foo> { ... }' 194911284Sandreas.hansson@arm.com # 2. Nested decode blocks 195011284Sandreas.hansson@arm.com # 3. Instruction definitions. 195111284Sandreas.hansson@arm.com # 4. C preprocessor directives. 195211051Sandreas.hansson@arm.com 195311051Sandreas.hansson@arm.com 195411051Sandreas.hansson@arm.com # Preprocessor directives found in a decode statement list are 195511051Sandreas.hansson@arm.com # passed through to the output, replicated to all of the output 195611051Sandreas.hansson@arm.com # code streams. This works well for ifdefs, so we can ifdef out 195711051Sandreas.hansson@arm.com # both the declarations and the decode cases generated by an 195811051Sandreas.hansson@arm.com # instruction definition. Handling them as part of the grammar 195911051Sandreas.hansson@arm.com # makes it easy to keep them in the right place with respect to 196011744Snikos.nikoleris@arm.com # the code generated by the other statements. 196111744Snikos.nikoleris@arm.com def p_decode_stmt_cpp(self, t): 196211051Sandreas.hansson@arm.com 'decode_stmt : CPPDIRECTIVE' 196311051Sandreas.hansson@arm.com t[0] = GenCode(self, t[1], t[1], t[1], t[1]) 196411051Sandreas.hansson@arm.com 196511127Sandreas.hansson@arm.com # A format block 'format <foo> { ... }' sets the default 196611051Sandreas.hansson@arm.com # instruction format used to handle instruction definitions inside 196711051Sandreas.hansson@arm.com # the block. This format can be overridden by using an explicit 196811051Sandreas.hansson@arm.com # format on the instruction definition or with a nested format 196911744Snikos.nikoleris@arm.com # block. 197011051Sandreas.hansson@arm.com def p_decode_stmt_format(self, t): 197111051Sandreas.hansson@arm.com 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' 197211051Sandreas.hansson@arm.com # The format will be pushed on the stack when 'push_format_id' 197311051Sandreas.hansson@arm.com # is processed (see below). Once the parser has recognized 197411051Sandreas.hansson@arm.com # the full production (though the right brace), we're done 197511051Sandreas.hansson@arm.com # with the format, so now we can pop it. 197611051Sandreas.hansson@arm.com self.formatStack.pop() 197711051Sandreas.hansson@arm.com t[0] = t[4] 197811051Sandreas.hansson@arm.com 197911051Sandreas.hansson@arm.com # This rule exists so we can set the current format (& push the 198011284Sandreas.hansson@arm.com # stack) when we recognize the format name part of the format 198111051Sandreas.hansson@arm.com # block. 198211285Sandreas.hansson@arm.com def p_push_format_id(self, t): 198311285Sandreas.hansson@arm.com 'push_format_id : ID' 198411285Sandreas.hansson@arm.com try: 198511285Sandreas.hansson@arm.com self.formatStack.push(self.formatMap[t[1]]) 198611744Snikos.nikoleris@arm.com t[0] = ('', '// format %s' % t[1]) 198711744Snikos.nikoleris@arm.com except KeyError: 198811285Sandreas.hansson@arm.com error(t, 'instruction format "%s" not defined.' % t[1]) 198911127Sandreas.hansson@arm.com 199011127Sandreas.hansson@arm.com # Nested decode block: if the value of the current field matches 199111051Sandreas.hansson@arm.com # the specified constant(s), do a nested decode on some other field. 199211051Sandreas.hansson@arm.com def p_decode_stmt_decode(self, t): 199311051Sandreas.hansson@arm.com 'decode_stmt : case_list COLON decode_block' 199411051Sandreas.hansson@arm.com case_list = t[1] 199511284Sandreas.hansson@arm.com codeObj = t[3] 199611051Sandreas.hansson@arm.com # just wrap the decoding code from the block as a case in the 199711051Sandreas.hansson@arm.com # outer switch statement. 199811051Sandreas.hansson@arm.com codeObj.wrap_decode_block('\n%s\n' % ''.join(case_list)) 199911051Sandreas.hansson@arm.com codeObj.has_decode_default = (case_list == ['default:']) 200011051Sandreas.hansson@arm.com t[0] = codeObj 200111051Sandreas.hansson@arm.com 200211051Sandreas.hansson@arm.com # Instruction definition (finally!). 200311051Sandreas.hansson@arm.com def p_decode_stmt_inst(self, t): 200411051Sandreas.hansson@arm.com 'decode_stmt : case_list COLON inst SEMI' 200511051Sandreas.hansson@arm.com case_list = t[1] 200611051Sandreas.hansson@arm.com codeObj = t[3] 200711127Sandreas.hansson@arm.com codeObj.wrap_decode_block('\n%s' % ''.join(case_list), 'break;\n') 200811127Sandreas.hansson@arm.com codeObj.has_decode_default = (case_list == ['default:']) 200911127Sandreas.hansson@arm.com t[0] = codeObj 201011127Sandreas.hansson@arm.com 201111127Sandreas.hansson@arm.com # The constant list for a decode case label must be non-empty, and must 201211127Sandreas.hansson@arm.com # either be the keyword 'default', or made up of one or more 201311284Sandreas.hansson@arm.com # comma-separated integer literals or strings which evaluate to 201411051Sandreas.hansson@arm.com # constants when compiled as C++. 201511051Sandreas.hansson@arm.com def p_case_list_0(self, t): 201611284Sandreas.hansson@arm.com 'case_list : DEFAULT' 201711051Sandreas.hansson@arm.com t[0] = ['default:'] 201811284Sandreas.hansson@arm.com 201911284Sandreas.hansson@arm.com def prep_int_lit_case_label(self, lit): 202011284Sandreas.hansson@arm.com if lit >= 2**32: 202111284Sandreas.hansson@arm.com return 'case ULL(%#x): ' % lit 202211051Sandreas.hansson@arm.com else: 202311051Sandreas.hansson@arm.com return 'case %#x: ' % lit 202411051Sandreas.hansson@arm.com 202511051Sandreas.hansson@arm.com def prep_str_lit_case_label(self, lit): 202611051Sandreas.hansson@arm.com return 'case %s: ' % lit 202711051Sandreas.hansson@arm.com 202811051Sandreas.hansson@arm.com def p_case_list_1(self, t): 202911051Sandreas.hansson@arm.com 'case_list : INTLIT' 203011051Sandreas.hansson@arm.com t[0] = [self.prep_int_lit_case_label(t[1])] 203111284Sandreas.hansson@arm.com 203211051Sandreas.hansson@arm.com def p_case_list_2(self, t): 203311051Sandreas.hansson@arm.com 'case_list : STRLIT' 203411051Sandreas.hansson@arm.com t[0] = [self.prep_str_lit_case_label(t[1])] 203511051Sandreas.hansson@arm.com 203611051Sandreas.hansson@arm.com def p_case_list_3(self, t): 203711051Sandreas.hansson@arm.com 'case_list : case_list COMMA INTLIT' 203811051Sandreas.hansson@arm.com t[0] = t[1] 203911051Sandreas.hansson@arm.com t[0].append(self.prep_int_lit_case_label(t[3])) 204011744Snikos.nikoleris@arm.com 204111744Snikos.nikoleris@arm.com def p_case_list_4(self, t): 204211493Sandreas.hansson@arm.com 'case_list : case_list COMMA STRLIT' 204311493Sandreas.hansson@arm.com t[0] = t[1] 204411493Sandreas.hansson@arm.com t[0].append(self.prep_str_lit_case_label(t[3])) 204511493Sandreas.hansson@arm.com 204611493Sandreas.hansson@arm.com # Define an instruction using the current instruction format 204711493Sandreas.hansson@arm.com # (specified by an enclosing format block). 204811493Sandreas.hansson@arm.com # "<mnemonic>(<args>)" 204911493Sandreas.hansson@arm.com def p_inst_0(self, t): 205011493Sandreas.hansson@arm.com 'inst : ID LPAREN arg_list RPAREN' 205111493Sandreas.hansson@arm.com # Pass the ID and arg list to the current format class to deal with. 205211493Sandreas.hansson@arm.com currentFormat = self.formatStack.top() 205311493Sandreas.hansson@arm.com codeObj = currentFormat.defineInst(self, t[1], t[3], t.lexer.lineno) 205411127Sandreas.hansson@arm.com args = ','.join(map(str, t[3])) 205511051Sandreas.hansson@arm.com args = re.sub('(?m)^', '//', args) 205611744Snikos.nikoleris@arm.com args = re.sub('^//', '', args) 205711744Snikos.nikoleris@arm.com comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) 205811051Sandreas.hansson@arm.com codeObj.prepend_all(comment) 205911051Sandreas.hansson@arm.com t[0] = codeObj 206011051Sandreas.hansson@arm.com 206111051Sandreas.hansson@arm.com # Define an instruction using an explicitly specified format: 206211051Sandreas.hansson@arm.com # "<fmt>::<mnemonic>(<args>)" 206311051Sandreas.hansson@arm.com def p_inst_1(self, t): 206411051Sandreas.hansson@arm.com 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' 206511051Sandreas.hansson@arm.com try: 206611751Snikos.nikoleris@arm.com format = self.formatMap[t[1]] 206711751Snikos.nikoleris@arm.com except KeyError: 206811051Sandreas.hansson@arm.com error(t, 'instruction format "%s" not defined.' % t[1]) 206911751Snikos.nikoleris@arm.com 207011284Sandreas.hansson@arm.com codeObj = format.defineInst(self, t[3], t[5], t.lexer.lineno) 207111051Sandreas.hansson@arm.com comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) 207211051Sandreas.hansson@arm.com codeObj.prepend_all(comment) 207311051Sandreas.hansson@arm.com t[0] = codeObj 207411051Sandreas.hansson@arm.com 207511051Sandreas.hansson@arm.com # The arg list generates a tuple, where the first element is a 207611051Sandreas.hansson@arm.com # list of the positional args and the second element is a dict 207711483Snikos.nikoleris@arm.com # containing the keyword args. 207811744Snikos.nikoleris@arm.com def p_arg_list_0(self, t): 207911051Sandreas.hansson@arm.com 'arg_list : positional_arg_list COMMA keyword_arg_list' 208011127Sandreas.hansson@arm.com t[0] = ( t[1], t[3] ) 208111051Sandreas.hansson@arm.com 208211051Sandreas.hansson@arm.com def p_arg_list_1(self, t): 208311285Sandreas.hansson@arm.com 'arg_list : positional_arg_list' 208411285Sandreas.hansson@arm.com t[0] = ( t[1], {} ) 208511284Sandreas.hansson@arm.com 208611284Sandreas.hansson@arm.com def p_arg_list_2(self, t): 208711285Sandreas.hansson@arm.com 'arg_list : keyword_arg_list' 208811285Sandreas.hansson@arm.com t[0] = ( [], t[1] ) 208911285Sandreas.hansson@arm.com 209011285Sandreas.hansson@arm.com def p_positional_arg_list_0(self, t): 209111285Sandreas.hansson@arm.com 'positional_arg_list : empty' 209211285Sandreas.hansson@arm.com t[0] = [] 209311285Sandreas.hansson@arm.com 209411285Sandreas.hansson@arm.com def p_positional_arg_list_1(self, t): 209511051Sandreas.hansson@arm.com 'positional_arg_list : expr' 209611051Sandreas.hansson@arm.com t[0] = [t[1]] 209711051Sandreas.hansson@arm.com 209811051Sandreas.hansson@arm.com def p_positional_arg_list_2(self, t): 209911051Sandreas.hansson@arm.com 'positional_arg_list : positional_arg_list COMMA expr' 210011284Sandreas.hansson@arm.com t[0] = t[1] + [t[3]] 210111284Sandreas.hansson@arm.com 210211284Sandreas.hansson@arm.com def p_keyword_arg_list_0(self, t): 210311284Sandreas.hansson@arm.com 'keyword_arg_list : keyword_arg' 210411284Sandreas.hansson@arm.com t[0] = t[1] 210511284Sandreas.hansson@arm.com 210611284Sandreas.hansson@arm.com def p_keyword_arg_list_1(self, t): 210711284Sandreas.hansson@arm.com 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' 210811081Sandreas.hansson@arm.com t[0] = t[1] 210911284Sandreas.hansson@arm.com t[0].update(t[3]) 211011284Sandreas.hansson@arm.com 211111284Sandreas.hansson@arm.com def p_keyword_arg(self, t): 211211284Sandreas.hansson@arm.com 'keyword_arg : ID EQUALS expr' 211311284Sandreas.hansson@arm.com t[0] = { t[1] : t[3] } 211411284Sandreas.hansson@arm.com 211511284Sandreas.hansson@arm.com # 211611051Sandreas.hansson@arm.com # Basic expressions. These constitute the argument values of 211711284Sandreas.hansson@arm.com # "function calls" (i.e. instruction definitions in the decode 211811285Sandreas.hansson@arm.com # block) and default values for formal parameters of format 211911285Sandreas.hansson@arm.com # functions. 212011285Sandreas.hansson@arm.com # 212111744Snikos.nikoleris@arm.com # Right now, these are either strings, integers, or (recursively) 212211744Snikos.nikoleris@arm.com # lists of exprs (using Python square-bracket list syntax). Note 212311285Sandreas.hansson@arm.com # that bare identifiers are trated as string constants here (since 212411051Sandreas.hansson@arm.com # there isn't really a variable namespace to refer to). 212511051Sandreas.hansson@arm.com # 212611051Sandreas.hansson@arm.com def p_expr_0(self, t): 212711051Sandreas.hansson@arm.com '''expr : ID 212811286Sandreas.hansson@arm.com | INTLIT 212911286Sandreas.hansson@arm.com | STRLIT 213011286Sandreas.hansson@arm.com | CODELIT''' 213111286Sandreas.hansson@arm.com t[0] = t[1] 213211051Sandreas.hansson@arm.com 213311051Sandreas.hansson@arm.com def p_expr_1(self, t): 213411051Sandreas.hansson@arm.com '''expr : LBRACKET list_expr RBRACKET''' 213511602Sandreas.hansson@arm.com t[0] = t[2] 213611051Sandreas.hansson@arm.com 213711602Sandreas.hansson@arm.com def p_list_expr_0(self, t): 213811602Sandreas.hansson@arm.com 'list_expr : expr' 213911602Sandreas.hansson@arm.com t[0] = [t[1]] 214011602Sandreas.hansson@arm.com 214111602Sandreas.hansson@arm.com def p_list_expr_1(self, t): 214211602Sandreas.hansson@arm.com 'list_expr : list_expr COMMA expr' 214311602Sandreas.hansson@arm.com t[0] = t[1] + [t[3]] 214411602Sandreas.hansson@arm.com 214511602Sandreas.hansson@arm.com def p_list_expr_2(self, t): 214611051Sandreas.hansson@arm.com 'list_expr : empty' 214711051Sandreas.hansson@arm.com t[0] = [] 214811051Sandreas.hansson@arm.com 214911051Sandreas.hansson@arm.com # 215011051Sandreas.hansson@arm.com # Empty production... use in other rules for readability. 215111051Sandreas.hansson@arm.com # 215211197Sandreas.hansson@arm.com def p_empty(self, t): 215311051Sandreas.hansson@arm.com 'empty :' 215411051Sandreas.hansson@arm.com pass 215511051Sandreas.hansson@arm.com 215611127Sandreas.hansson@arm.com # Parse error handler. Note that the argument here is the 215711127Sandreas.hansson@arm.com # offending *token*, not a grammar symbol (hence the need to use 215811051Sandreas.hansson@arm.com # t.value) 215911051Sandreas.hansson@arm.com def p_error(self, t): 216011051Sandreas.hansson@arm.com if t: 216111051Sandreas.hansson@arm.com error(t, "syntax error at '%s'" % t.value) 216211051Sandreas.hansson@arm.com else: 216311051Sandreas.hansson@arm.com error("unknown syntax error") 216411744Snikos.nikoleris@arm.com 216511051Sandreas.hansson@arm.com # END OF GRAMMAR RULES 216611051Sandreas.hansson@arm.com 216711051Sandreas.hansson@arm.com def updateExportContext(self): 216811051Sandreas.hansson@arm.com 216911130Sali.jafri@arm.com # create a continuation that allows us to grab the current parser 217011051Sandreas.hansson@arm.com def wrapInstObjParams(*args): 217111051Sandreas.hansson@arm.com return InstObjParams(self, *args) 217211051Sandreas.hansson@arm.com self.exportContext['InstObjParams'] = wrapInstObjParams 217311051Sandreas.hansson@arm.com self.exportContext.update(self.templateMap) 217411051Sandreas.hansson@arm.com 217511051Sandreas.hansson@arm.com def defFormat(self, id, params, code, lineno): 217611051Sandreas.hansson@arm.com '''Define a new format''' 217711892Snikos.nikoleris@arm.com 217811051Sandreas.hansson@arm.com # make sure we haven't already defined this one 217911051Sandreas.hansson@arm.com if id in self.formatMap: 218011127Sandreas.hansson@arm.com error(lineno, 'format %s redefined.' % id) 218111127Sandreas.hansson@arm.com 218211127Sandreas.hansson@arm.com # create new object and store in global map 218311127Sandreas.hansson@arm.com self.formatMap[id] = Format(id, params, code) 218411127Sandreas.hansson@arm.com 218511127Sandreas.hansson@arm.com def expandCpuSymbolsToDict(self, template): 218611127Sandreas.hansson@arm.com '''Expand template with CPU-specific references into a 218711127Sandreas.hansson@arm.com dictionary with an entry for each CPU model name. The entry 218811051Sandreas.hansson@arm.com key is the model name and the corresponding value is the 218911051Sandreas.hansson@arm.com template with the CPU-specific refs substituted for that 219011051Sandreas.hansson@arm.com model.''' 219111744Snikos.nikoleris@arm.com 219211744Snikos.nikoleris@arm.com # Protect '%'s that don't go with CPU-specific terms 219311051Sandreas.hansson@arm.com t = re.sub(r'%(?!\(CPU_)', '%%', template) 219411051Sandreas.hansson@arm.com result = {} 219511051Sandreas.hansson@arm.com for cpu in self.cpuModels: 219611051Sandreas.hansson@arm.com result[cpu.name] = t % cpu.strings 219711051Sandreas.hansson@arm.com return result 219811051Sandreas.hansson@arm.com 219911051Sandreas.hansson@arm.com def expandCpuSymbolsToString(self, template): 220011051Sandreas.hansson@arm.com '''*If* the template has CPU-specific references, return a 220111051Sandreas.hansson@arm.com single string containing a copy of the template for each CPU 220211051Sandreas.hansson@arm.com model with the corresponding values substituted in. If the 220311051Sandreas.hansson@arm.com template has no CPU-specific references, it is returned 220411051Sandreas.hansson@arm.com unmodified.''' 220511051Sandreas.hansson@arm.com 220611051Sandreas.hansson@arm.com if template.find('%(CPU_') != -1: 220711051Sandreas.hansson@arm.com return reduce(lambda x,y: x+y, 220811051Sandreas.hansson@arm.com self.expandCpuSymbolsToDict(template).values()) 220911051Sandreas.hansson@arm.com else: 221011375Sandreas.hansson@arm.com return template 221111375Sandreas.hansson@arm.com 221211051Sandreas.hansson@arm.com def protectCpuSymbols(self, template): 221311051Sandreas.hansson@arm.com '''Protect CPU-specific references by doubling the 221411051Sandreas.hansson@arm.com corresponding '%'s (in preparation for substituting a different 221511051Sandreas.hansson@arm.com set of references into the template).''' 221611051Sandreas.hansson@arm.com 221711051Sandreas.hansson@arm.com return re.sub(r'%(?=\(CPU_)', '%%', template) 221811051Sandreas.hansson@arm.com 221911051Sandreas.hansson@arm.com def protectNonSubstPercents(self, s): 222011051Sandreas.hansson@arm.com '''Protect any non-dict-substitution '%'s in a format string 222112345Snikos.nikoleris@arm.com (i.e. those not followed by '(')''' 222211051Sandreas.hansson@arm.com 222311199Sandreas.hansson@arm.com return re.sub(r'%(?!\()', '%%', s) 222411051Sandreas.hansson@arm.com 222511051Sandreas.hansson@arm.com def buildOperandNameMap(self, user_dict, lineno): 222611051Sandreas.hansson@arm.com operand_name = {} 222711051Sandreas.hansson@arm.com for op_name, val in user_dict.iteritems(): 222811051Sandreas.hansson@arm.com 222911744Snikos.nikoleris@arm.com # Check if extra attributes have been specified. 223011744Snikos.nikoleris@arm.com if len(val) > 9: 223111051Sandreas.hansson@arm.com error(lineno, 'error: too many attributes for operand "%s"' % 223211051Sandreas.hansson@arm.com base_cls_name) 223311051Sandreas.hansson@arm.com 223411332Sandreas.hansson@arm.com # Pad val with None in case optional args are missing 223511332Sandreas.hansson@arm.com val += (None, None, None, None) 223611332Sandreas.hansson@arm.com base_cls_name, dflt_ext, reg_spec, flags, sort_pri, \ 223711332Sandreas.hansson@arm.com read_code, write_code, read_predicate, write_predicate = val[:9] 223811332Sandreas.hansson@arm.com 223911332Sandreas.hansson@arm.com # Canonical flag structure is a triple of lists, where each list 224011751Snikos.nikoleris@arm.com # indicates the set of flags implied by this operand always, when 224111332Sandreas.hansson@arm.com # used as a source, and when used as a dest, respectively. 224211332Sandreas.hansson@arm.com # For simplicity this can be initialized using a variety of fairly 224311332Sandreas.hansson@arm.com # obvious shortcuts; we convert these to canonical form here. 224411332Sandreas.hansson@arm.com if not flags: 224511332Sandreas.hansson@arm.com # no flags specified (e.g., 'None') 224611332Sandreas.hansson@arm.com flags = ( [], [], [] ) 224711332Sandreas.hansson@arm.com elif isinstance(flags, str): 224811332Sandreas.hansson@arm.com # a single flag: assumed to be unconditional 224911332Sandreas.hansson@arm.com flags = ( [ flags ], [], [] ) 225011332Sandreas.hansson@arm.com elif isinstance(flags, list): 225111284Sandreas.hansson@arm.com # a list of flags: also assumed to be unconditional 225211332Sandreas.hansson@arm.com flags = ( flags, [], [] ) 225311332Sandreas.hansson@arm.com elif isinstance(flags, tuple): 225411332Sandreas.hansson@arm.com # it's a tuple: it should be a triple, 225511051Sandreas.hansson@arm.com # but each item could be a single string or a list 225611332Sandreas.hansson@arm.com (uncond_flags, src_flags, dest_flags) = flags 225711051Sandreas.hansson@arm.com flags = (makeList(uncond_flags), 225811051Sandreas.hansson@arm.com makeList(src_flags), makeList(dest_flags)) 225911051Sandreas.hansson@arm.com 226011051Sandreas.hansson@arm.com # Accumulate attributes of new operand class in tmp_dict 226111332Sandreas.hansson@arm.com tmp_dict = {} 226211051Sandreas.hansson@arm.com attrList = ['reg_spec', 'flags', 'sort_pri', 226311051Sandreas.hansson@arm.com 'read_code', 'write_code', 226411375Sandreas.hansson@arm.com 'read_predicate', 'write_predicate'] 226511051Sandreas.hansson@arm.com if dflt_ext: 226611051Sandreas.hansson@arm.com dflt_ctype = self.operandTypeMap[dflt_ext] 226711051Sandreas.hansson@arm.com attrList.extend(['dflt_ctype', 'dflt_ext']) 226811051Sandreas.hansson@arm.com for attr in attrList: 226911051Sandreas.hansson@arm.com tmp_dict[attr] = eval(attr) 227011051Sandreas.hansson@arm.com tmp_dict['base_name'] = op_name 227111051Sandreas.hansson@arm.com 227211051Sandreas.hansson@arm.com # New class name will be e.g. "IntReg_Ra" 227311051Sandreas.hansson@arm.com cls_name = base_cls_name + '_' + op_name 227411127Sandreas.hansson@arm.com # Evaluate string arg to get class object. Note that the 227511127Sandreas.hansson@arm.com # actual base class for "IntReg" is "IntRegOperand", i.e. we 227611127Sandreas.hansson@arm.com # have to append "Operand". 227711127Sandreas.hansson@arm.com try: 227811127Sandreas.hansson@arm.com base_cls = eval(base_cls_name + 'Operand') 227911127Sandreas.hansson@arm.com except NameError: 228011051Sandreas.hansson@arm.com error(lineno, 228111051Sandreas.hansson@arm.com 'error: unknown operand base class "%s"' % base_cls_name) 228211051Sandreas.hansson@arm.com # The following statement creates a new class called 228311051Sandreas.hansson@arm.com # <cls_name> as a subclass of <base_cls> with the attributes 228411051Sandreas.hansson@arm.com # in tmp_dict, just as if we evaluated a class declaration. 228511051Sandreas.hansson@arm.com operand_name[op_name] = type(cls_name, (base_cls,), tmp_dict) 228611051Sandreas.hansson@arm.com 228711051Sandreas.hansson@arm.com self.operandNameMap = operand_name 228811051Sandreas.hansson@arm.com 228911051Sandreas.hansson@arm.com # Define operand variables. 229011051Sandreas.hansson@arm.com operands = user_dict.keys() 229111051Sandreas.hansson@arm.com extensions = self.operandTypeMap.keys() 229211051Sandreas.hansson@arm.com 229311051Sandreas.hansson@arm.com operandsREString = r''' 229411051Sandreas.hansson@arm.com (?<!\w) # neg. lookbehind assertion: prevent partial matches 229511051Sandreas.hansson@arm.com ((%s)(?:_(%s))?) # match: operand with optional '_' then suffix 229611130Sali.jafri@arm.com (?!\w) # neg. lookahead assertion: prevent partial matches 229711130Sali.jafri@arm.com ''' % (string.join(operands, '|'), string.join(extensions, '|')) 229811051Sandreas.hansson@arm.com 229911051Sandreas.hansson@arm.com self.operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) 230011051Sandreas.hansson@arm.com 230111051Sandreas.hansson@arm.com # Same as operandsREString, but extension is mandatory, and only two 230211127Sandreas.hansson@arm.com # groups are returned (base and ext, not full name as above). 230311127Sandreas.hansson@arm.com # Used for subtituting '_' for '.' to make C++ identifiers. 230411051Sandreas.hansson@arm.com operandsWithExtREString = r'(?<!\w)(%s)_(%s)(?!\w)' \ 230511051Sandreas.hansson@arm.com % (string.join(operands, '|'), string.join(extensions, '|')) 230611051Sandreas.hansson@arm.com 230711375Sandreas.hansson@arm.com self.operandsWithExtRE = \ 230811375Sandreas.hansson@arm.com re.compile(operandsWithExtREString, re.MULTILINE) 230911051Sandreas.hansson@arm.com 231011051Sandreas.hansson@arm.com def substMungedOpNames(self, code): 231111051Sandreas.hansson@arm.com '''Munge operand names in code string to make legal C++ 231211051Sandreas.hansson@arm.com variable names. This means getting rid of the type extension 231311375Sandreas.hansson@arm.com if any. Will match base_name attribute of Operand object.)''' 231411375Sandreas.hansson@arm.com return self.operandsWithExtRE.sub(r'\1', code) 231511051Sandreas.hansson@arm.com 231611051Sandreas.hansson@arm.com def mungeSnippet(self, s): 231711453Sandreas.hansson@arm.com '''Fix up code snippets for final substitution in templates.''' 231811453Sandreas.hansson@arm.com if isinstance(s, str): 231911051Sandreas.hansson@arm.com return self.substMungedOpNames(substBitOps(s)) 232011051Sandreas.hansson@arm.com else: 232111375Sandreas.hansson@arm.com return s 232211375Sandreas.hansson@arm.com 232311375Sandreas.hansson@arm.com def open(self, name, bare=False): 232411375Sandreas.hansson@arm.com '''Open the output file for writing and include scary warning.''' 232511051Sandreas.hansson@arm.com filename = os.path.join(self.output_dir, name) 232611051Sandreas.hansson@arm.com f = open(filename, 'w') 232711051Sandreas.hansson@arm.com if f: 232811051Sandreas.hansson@arm.com if not bare: 232911051Sandreas.hansson@arm.com f.write(ISAParser.scaremonger_template % self) 233011051Sandreas.hansson@arm.com return f 233111051Sandreas.hansson@arm.com 233211375Sandreas.hansson@arm.com def update(self, file, contents): 233311051Sandreas.hansson@arm.com '''Update the output file only. Scons should handle the case when 233411051Sandreas.hansson@arm.com the new contents are unchanged using its built-in hash feature.''' 233511375Sandreas.hansson@arm.com f = self.open(file) 233611051Sandreas.hansson@arm.com f.write(contents) 233711051Sandreas.hansson@arm.com f.close() 233811051Sandreas.hansson@arm.com 233911051Sandreas.hansson@arm.com # This regular expression matches '##include' directives 234011051Sandreas.hansson@arm.com includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[^"]*)".*$', 234111051Sandreas.hansson@arm.com re.MULTILINE) 234211051Sandreas.hansson@arm.com 234311051Sandreas.hansson@arm.com def replace_include(self, matchobj, dirname): 234411051Sandreas.hansson@arm.com """Function to replace a matched '##include' directive with the 234511051Sandreas.hansson@arm.com contents of the specified file (with nested ##includes 234611051Sandreas.hansson@arm.com replaced recursively). 'matchobj' is an re match object 234711051Sandreas.hansson@arm.com (from a match of includeRE) and 'dirname' is the directory 234811375Sandreas.hansson@arm.com relative to which the file path should be resolved.""" 234911051Sandreas.hansson@arm.com 235011051Sandreas.hansson@arm.com fname = matchobj.group('filename') 235111051Sandreas.hansson@arm.com full_fname = os.path.normpath(os.path.join(dirname, fname)) 235211051Sandreas.hansson@arm.com contents = '##newfile "%s"\n%s\n##endfile\n' % \ 235311051Sandreas.hansson@arm.com (full_fname, self.read_and_flatten(full_fname)) 235411051Sandreas.hansson@arm.com return contents 235511051Sandreas.hansson@arm.com 235611051Sandreas.hansson@arm.com def read_and_flatten(self, filename): 235711051Sandreas.hansson@arm.com """Read a file and recursively flatten nested '##include' files.""" 235811051Sandreas.hansson@arm.com 235911051Sandreas.hansson@arm.com current_dir = os.path.dirname(filename) 236011051Sandreas.hansson@arm.com try: 236111375Sandreas.hansson@arm.com contents = open(filename).read() 236211051Sandreas.hansson@arm.com except IOError: 236311051Sandreas.hansson@arm.com error('Error including file "%s"' % filename) 236411051Sandreas.hansson@arm.com 236511051Sandreas.hansson@arm.com self.fileNameStack.push((filename, 0)) 236611892Snikos.nikoleris@arm.com 236711051Sandreas.hansson@arm.com # Find any includes and include them 236811051Sandreas.hansson@arm.com def replace(matchobj): 236911051Sandreas.hansson@arm.com return self.replace_include(matchobj, current_dir) 237011051Sandreas.hansson@arm.com contents = self.includeRE.sub(replace, contents) 237111051Sandreas.hansson@arm.com 237211051Sandreas.hansson@arm.com self.fileNameStack.pop() 237311051Sandreas.hansson@arm.com return contents 237411051Sandreas.hansson@arm.com 237511051Sandreas.hansson@arm.com AlreadyGenerated = {} 237611051Sandreas.hansson@arm.com 237711051Sandreas.hansson@arm.com def _parse_isa_desc(self, isa_desc_file): 237811051Sandreas.hansson@arm.com '''Read in and parse the ISA description.''' 237911051Sandreas.hansson@arm.com 238011051Sandreas.hansson@arm.com # The build system can end up running the ISA parser twice: once to 238111051Sandreas.hansson@arm.com # finalize the build dependencies, and then to actually generate 238211051Sandreas.hansson@arm.com # the files it expects (in src/arch/$ARCH/generated). This code 238311051Sandreas.hansson@arm.com # doesn't do anything different either time, however; the SCons 238411051Sandreas.hansson@arm.com # invocations just expect different things. Since this code runs 238511051Sandreas.hansson@arm.com # within SCons, we can just remember that we've already run and 238611051Sandreas.hansson@arm.com # not perform a completely unnecessary run, since the ISA parser's 238711375Sandreas.hansson@arm.com # effect is idempotent. 238811051Sandreas.hansson@arm.com if isa_desc_file in ISAParser.AlreadyGenerated: 238911051Sandreas.hansson@arm.com return 239011051Sandreas.hansson@arm.com 239111130Sali.jafri@arm.com # grab the last three path components of isa_desc_file 239211051Sandreas.hansson@arm.com self.filename = '/'.join(isa_desc_file.split('/')[-3:]) 239311051Sandreas.hansson@arm.com 239411051Sandreas.hansson@arm.com # Read file and (recursively) all included files into a string. 239511051Sandreas.hansson@arm.com # PLY requires that the input be in a single string so we have to 239611051Sandreas.hansson@arm.com # do this up front. 239711051Sandreas.hansson@arm.com isa_desc = self.read_and_flatten(isa_desc_file) 239811051Sandreas.hansson@arm.com 239911051Sandreas.hansson@arm.com # Initialize filename stack with outer file. 240011130Sali.jafri@arm.com self.fileNameStack.push((isa_desc_file, 0)) 240111130Sali.jafri@arm.com 240211130Sali.jafri@arm.com # Parse. 240311130Sali.jafri@arm.com self.parse_string(isa_desc) 240411130Sali.jafri@arm.com 240511130Sali.jafri@arm.com ISAParser.AlreadyGenerated[isa_desc_file] = None 240612345Snikos.nikoleris@arm.com 240711484Snikos.nikoleris@arm.com def parse_isa_desc(self, *args, **kwargs): 240811130Sali.jafri@arm.com try: 240911130Sali.jafri@arm.com self._parse_isa_desc(*args, **kwargs) 241011284Sandreas.hansson@arm.com except ISAParserError, e: 241111130Sali.jafri@arm.com e.exit(self.fileNameStack) 241211130Sali.jafri@arm.com 241311130Sali.jafri@arm.com# Called as script: get args from command line. 241411130Sali.jafri@arm.com# Args are: <isa desc file> <output dir> 241511130Sali.jafri@arm.comif __name__ == '__main__': 241611051Sandreas.hansson@arm.com ISAParser(sys.argv[2]).parse_isa_desc(sys.argv[1]) 241711051Sandreas.hansson@arm.com