Merge zizzer:/bk/m5 into isabel.reinhardt.house:/z/stever/bk/m5
--HG-- extra : convert_revision : 266d03e82a04cca07f669f778ad11907f2f003d2
This commit is contained in:
commit
9ca875f189
4 changed files with 1244 additions and 885 deletions
File diff suppressed because it is too large
Load diff
|
@ -63,8 +63,9 @@ import yacc
|
||||||
# using the same regexp as generic IDs, but distinguished in the
|
# using the same regexp as generic IDs, but distinguished in the
|
||||||
# t_ID() function. The PLY documentation suggests this approach.
|
# t_ID() function. The PLY documentation suggests this approach.
|
||||||
reserved = (
|
reserved = (
|
||||||
'BITFIELD', 'DECLARE', 'DECODE', 'DEFAULT', 'DEF', 'FORMAT',
|
'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT',
|
||||||
'LET', 'NAMESPACE', 'SIGNED', 'TEMPLATE'
|
'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS',
|
||||||
|
'OUTPUT', 'SIGNED', 'TEMPLATE'
|
||||||
)
|
)
|
||||||
|
|
||||||
# List of tokens. The lex module requires this.
|
# List of tokens. The lex module requires this.
|
||||||
|
@ -195,14 +196,6 @@ lex.lex()
|
||||||
# (by assigning to t[0]).
|
# (by assigning to t[0]).
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
# Not sure why, but we get a handful of shift/reduce conflicts on DECLARE.
|
|
||||||
# By default these get resolved as shifts, which is correct, but
|
|
||||||
# warnings are printed. Explicitly marking DECLARE as right-associative
|
|
||||||
# suppresses the warnings.
|
|
||||||
precedence = (
|
|
||||||
('right', 'DECLARE'),
|
|
||||||
)
|
|
||||||
|
|
||||||
# The LHS of the first grammar rule is used as the start symbol
|
# The LHS of the first grammar rule is used as the start symbol
|
||||||
# (in this case, 'specification'). Note that this rule enforces
|
# (in this case, 'specification'). Note that this rule enforces
|
||||||
# that there will be exactly one namespace declaration, with 0 or more
|
# that there will be exactly one namespace declaration, with 0 or more
|
||||||
|
@ -210,163 +203,123 @@ precedence = (
|
||||||
# the namespace decl will be outside the namespace; those after
|
# the namespace decl will be outside the namespace; those after
|
||||||
# will be inside. The decoder function is always inside the namespace.
|
# will be inside. The decoder function is always inside the namespace.
|
||||||
def p_specification(t):
|
def p_specification(t):
|
||||||
'specification : opt_defs_and_declares name_decl opt_defs_and_declares decode_block'
|
'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block'
|
||||||
global_decls1 = t[1]
|
global_code = t[1]
|
||||||
isa_name = t[2]
|
isa_name = t[2]
|
||||||
namespace = isa_name + "Inst"
|
namespace = isa_name + "Inst"
|
||||||
global_decls2 = t[3]
|
# wrap the decode block as a function definition
|
||||||
(inst_decls, decode_code, exec_code) = t[4]
|
t[4].wrap_decode_block('''
|
||||||
decode_code = indent(decode_code)
|
|
||||||
# grab the last three path components of isa_desc_filename
|
|
||||||
filename = '/'.join(isa_desc_filename.split('/')[-3:])
|
|
||||||
# if the isa_desc file defines a 'rcs_id' string,
|
|
||||||
# echo that into the output too
|
|
||||||
try:
|
|
||||||
local_rcs_id = rcs_id
|
|
||||||
# strip $s out of ID so it doesn't get re-substituted
|
|
||||||
local_rcs_id = re.sub(r'\$', '', local_rcs_id)
|
|
||||||
except NameError:
|
|
||||||
local_rcs_id = 'Id: no RCS id found'
|
|
||||||
output = open(decoder_filename, 'w')
|
|
||||||
# split string to keep rcs from substituting this file's RCS id in
|
|
||||||
print >> output, '/* $Id' + '''$ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2003
|
|
||||||
* The Regents of The University of Michigan
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This code is part of the M5 simulator, developed by Nathan Binkert,
|
|
||||||
* Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
|
|
||||||
* from Ron Dreslinski, Dave Greene, and Lisa Hsu.
|
|
||||||
*
|
|
||||||
* Permission is granted to use, copy, create derivative works and
|
|
||||||
* redistribute this software and such derivative works for any
|
|
||||||
* purpose, so long as the copyright notice above, this grant of
|
|
||||||
* permission, and the disclaimer below appear in all copies made; and
|
|
||||||
* so long as the name of The University of Michigan is not used in
|
|
||||||
* any advertising or publicity pertaining to the use or distribution
|
|
||||||
* of this software without specific, written prior authorization.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
|
|
||||||
* UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
|
|
||||||
* WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
|
|
||||||
* LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
|
|
||||||
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
|
|
||||||
* ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
|
|
||||||
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
* DAMAGES.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DO NOT EDIT THIS FILE!!!
|
|
||||||
*
|
|
||||||
* It was automatically generated from this ISA description:
|
|
||||||
* Filename: %(filename)s
|
|
||||||
* RCS %(local_rcs_id)s
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "base/bitfield.hh" // required for bitfield support
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////
|
|
||||||
// Global defs (outside namespace) //
|
|
||||||
/////////////////////////////////////
|
|
||||||
|
|
||||||
%(global_decls1)s
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for %(isa_name)s static instruction objects.
|
|
||||||
*/
|
|
||||||
namespace %(namespace)s
|
|
||||||
{
|
|
||||||
|
|
||||||
/////////////////////////////////////
|
|
||||||
// Global defs (within namespace) //
|
|
||||||
/////////////////////////////////////
|
|
||||||
|
|
||||||
%(global_decls2)s
|
|
||||||
|
|
||||||
////////////////////////////////////
|
|
||||||
// Declares from inst definitions //
|
|
||||||
////////////////////////////////////
|
|
||||||
|
|
||||||
%(inst_decls)s
|
|
||||||
|
|
||||||
%(exec_code)s
|
|
||||||
|
|
||||||
} // namespace %(namespace)s
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// Decoder function //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
StaticInstPtr<%(isa_name)s>
|
StaticInstPtr<%(isa_name)s>
|
||||||
%(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
|
%(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
|
||||||
{
|
{
|
||||||
using namespace %(namespace)s;
|
using namespace %(namespace)s;
|
||||||
%(decode_code)s
|
''' % vars(), '}')
|
||||||
} // decodeInst
|
# both the latter output blocks and the decode block are in the namespace
|
||||||
''' % vars()
|
namespace_code = t[3] + t[4]
|
||||||
output.close()
|
# pass it all back to the caller of yacc.parse()
|
||||||
|
t[0] = (isa_name, namespace, global_code, namespace_code)
|
||||||
|
|
||||||
# ISA name declaration looks like "namespace <foo>;"
|
# ISA name declaration looks like "namespace <foo>;"
|
||||||
def p_name_decl(t):
|
def p_name_decl(t):
|
||||||
'name_decl : NAMESPACE ID SEMI'
|
'name_decl : NAMESPACE ID SEMI'
|
||||||
t[0] = t[2]
|
t[0] = t[2]
|
||||||
|
|
||||||
# 'opt_defs_and_declares' is a possibly empty sequence of
|
# 'opt_defs_and_outputs' is a possibly empty sequence of
|
||||||
# defs and/or declares.
|
# def and/or output statements.
|
||||||
def p_opt_defs_and_declares_0(t):
|
def p_opt_defs_and_outputs_0(t):
|
||||||
'opt_defs_and_declares : empty'
|
'opt_defs_and_outputs : empty'
|
||||||
t[0] = ''
|
t[0] = GenCode()
|
||||||
|
|
||||||
def p_opt_defs_and_declares_1(t):
|
def p_opt_defs_and_outputs_1(t):
|
||||||
'opt_defs_and_declares : defs_and_declares'
|
'opt_defs_and_outputs : defs_and_outputs'
|
||||||
t[0] = t[1]
|
t[0] = t[1]
|
||||||
|
|
||||||
def p_defs_and_declares_0(t):
|
def p_defs_and_outputs_0(t):
|
||||||
'defs_and_declares : def_or_declare'
|
'defs_and_outputs : def_or_output'
|
||||||
t[0] = t[1]
|
t[0] = t[1]
|
||||||
|
|
||||||
def p_defs_and_declares_1(t):
|
def p_defs_and_outputs_1(t):
|
||||||
'defs_and_declares : defs_and_declares def_or_declare'
|
'defs_and_outputs : defs_and_outputs def_or_output'
|
||||||
t[0] = t[1] + t[2]
|
t[0] = t[1] + t[2]
|
||||||
|
|
||||||
# The list of possible definition/declaration statements.
|
# The list of possible definition/output statements.
|
||||||
def p_def_or_declare(t):
|
def p_def_or_output(t):
|
||||||
'''def_or_declare : def_format
|
'''def_or_output : def_format
|
||||||
| def_bitfield
|
| def_bitfield
|
||||||
| def_template
|
| def_template
|
||||||
| global_declare
|
| def_operand_types
|
||||||
| global_let
|
| def_operands
|
||||||
| cpp_directive'''
|
| output_header
|
||||||
|
| output_decoder
|
||||||
|
| output_exec
|
||||||
|
| global_let'''
|
||||||
t[0] = t[1]
|
t[0] = t[1]
|
||||||
|
|
||||||
# preprocessor directives are copied directly to the output.
|
# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
|
||||||
def p_cpp_directive(t):
|
# directly to the appropriate output section.
|
||||||
'''cpp_directive : CPPDIRECTIVE'''
|
|
||||||
t[0] = t[1]
|
|
||||||
|
|
||||||
# Global declares 'declare {{...}}' (C++ code blocks) are copied
|
# Massage output block by substituting in template definitions and bit
|
||||||
# directly to the output.
|
# operators. We handle '%'s embedded in the string that don't
|
||||||
def p_global_declare(t):
|
# indicate template substitutions (or CPU-specific symbols, which get
|
||||||
'global_declare : DECLARE CODELIT SEMI'
|
# handled in GenCode) by doubling them first so that the format
|
||||||
t[0] = substBitOps(t[2])
|
# operation will reduce them back to single '%'s.
|
||||||
|
def process_output(s):
|
||||||
|
# protect any non-substitution '%'s (not followed by '(')
|
||||||
|
s = re.sub(r'%(?!\()', '%%', s)
|
||||||
|
# protects cpu-specific symbols too
|
||||||
|
s = protect_cpu_symbols(s)
|
||||||
|
return substBitOps(s % templateMap)
|
||||||
|
|
||||||
|
def p_output_header(t):
|
||||||
|
'output_header : OUTPUT HEADER CODELIT SEMI'
|
||||||
|
t[0] = GenCode(header_output = process_output(t[3]))
|
||||||
|
|
||||||
|
def p_output_decoder(t):
|
||||||
|
'output_decoder : OUTPUT DECODER CODELIT SEMI'
|
||||||
|
t[0] = GenCode(decoder_output = process_output(t[3]))
|
||||||
|
|
||||||
|
def p_output_exec(t):
|
||||||
|
'output_exec : OUTPUT EXEC CODELIT SEMI'
|
||||||
|
t[0] = GenCode(exec_output = process_output(t[3]))
|
||||||
|
|
||||||
# global let blocks 'let {{...}}' (Python code blocks) are executed
|
# global let blocks 'let {{...}}' (Python code blocks) are executed
|
||||||
# directly when seen. These are typically used to initialize global
|
# directly when seen. Note that these execute in a special variable
|
||||||
# Python variables used in later format definitions.
|
# context 'exportContext' to prevent the code from polluting this
|
||||||
|
# script's namespace.
|
||||||
def p_global_let(t):
|
def p_global_let(t):
|
||||||
'global_let : LET CODELIT SEMI'
|
'global_let : LET CODELIT SEMI'
|
||||||
|
updateExportContext()
|
||||||
try:
|
try:
|
||||||
exec(fixPythonIndentation(t[2]))
|
exec fixPythonIndentation(t[2]) in exportContext
|
||||||
except:
|
except Exception, exc:
|
||||||
error_bt(t.lineno(1), 'error in global let block "%s".' % t[2])
|
error(t.lineno(1),
|
||||||
t[0] = '' # contributes nothing to the output C++ file
|
'error: %s in global let block "%s".' % (exc, t[2]))
|
||||||
|
t[0] = GenCode() # contributes nothing to the output C++ file
|
||||||
|
|
||||||
|
# Define the mapping from operand type extensions to C++ types and bit
|
||||||
|
# widths (stored in operandTypeMap).
|
||||||
|
def p_def_operand_types(t):
|
||||||
|
'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI'
|
||||||
|
s = 'global operandTypeMap; operandTypeMap = {' + t[3] + '}'
|
||||||
|
try:
|
||||||
|
exec s
|
||||||
|
except Exception, exc:
|
||||||
|
error(t.lineno(1),
|
||||||
|
'error: %s in def operand_types block "%s".' % (exc, t[3]))
|
||||||
|
t[0] = GenCode() # contributes nothing to the output C++ file
|
||||||
|
|
||||||
|
# Define the mapping from operand names to operand classes and other
|
||||||
|
# traits. Stored in operandTraitsMap.
|
||||||
|
def p_def_operands(t):
|
||||||
|
'def_operands : DEF OPERANDS CODELIT SEMI'
|
||||||
|
s = 'global operandTraitsMap; operandTraitsMap = {' + t[3] + '}'
|
||||||
|
try:
|
||||||
|
exec s
|
||||||
|
except Exception, exc:
|
||||||
|
error(t.lineno(1),
|
||||||
|
'error: %s in def operands block "%s".' % (exc, t[3]))
|
||||||
|
defineDerivedOperandVars()
|
||||||
|
t[0] = GenCode() # contributes nothing to the output C++ file
|
||||||
|
|
||||||
# A bitfield definition looks like:
|
# A bitfield definition looks like:
|
||||||
# 'def [signed] bitfield <ID> [<first>:<last>]'
|
# 'def [signed] bitfield <ID> [<first>:<last>]'
|
||||||
|
@ -376,7 +329,8 @@ def p_def_bitfield_0(t):
|
||||||
expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
|
expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
|
||||||
if (t[2] == 'signed'):
|
if (t[2] == 'signed'):
|
||||||
expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
|
expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
|
||||||
t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
|
hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
|
||||||
|
t[0] = GenCode(header_output = hash_define)
|
||||||
|
|
||||||
# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]'
|
# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]'
|
||||||
def p_def_bitfield_1(t):
|
def p_def_bitfield_1(t):
|
||||||
|
@ -384,7 +338,8 @@ def p_def_bitfield_1(t):
|
||||||
expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
|
expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
|
||||||
if (t[2] == 'signed'):
|
if (t[2] == 'signed'):
|
||||||
expr = 'sext<%d>(%s)' % (1, expr)
|
expr = 'sext<%d>(%s)' % (1, expr)
|
||||||
t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
|
hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
|
||||||
|
t[0] = GenCode(header_output = hash_define)
|
||||||
|
|
||||||
def p_opt_signed_0(t):
|
def p_opt_signed_0(t):
|
||||||
'opt_signed : SIGNED'
|
'opt_signed : SIGNED'
|
||||||
|
@ -399,8 +354,8 @@ templateMap = {}
|
||||||
|
|
||||||
def p_def_template(t):
|
def p_def_template(t):
|
||||||
'def_template : DEF TEMPLATE ID CODELIT SEMI'
|
'def_template : DEF TEMPLATE ID CODELIT SEMI'
|
||||||
templateMap[t[3]] = t[4]
|
templateMap[t[3]] = Template(t[4])
|
||||||
t[0] = ''
|
t[0] = GenCode()
|
||||||
|
|
||||||
# An instruction format definition looks like
|
# An instruction format definition looks like
|
||||||
# "def format <fmt>(<params>) {{...}};"
|
# "def format <fmt>(<params>) {{...}};"
|
||||||
|
@ -408,12 +363,7 @@ def p_def_format(t):
|
||||||
'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
|
'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
|
||||||
(id, params, code) = (t[3], t[5], t[7])
|
(id, params, code) = (t[3], t[5], t[7])
|
||||||
defFormat(id, params, code, t.lineno(1))
|
defFormat(id, params, code, t.lineno(1))
|
||||||
# insert a comment into the output to note that the def was processed
|
t[0] = GenCode()
|
||||||
t[0] = '''
|
|
||||||
//
|
|
||||||
// parser: format %s defined
|
|
||||||
//
|
|
||||||
''' % id
|
|
||||||
|
|
||||||
# The formal parameter list for an instruction format is a possibly
|
# The formal parameter list for an instruction format is a possibly
|
||||||
# empty list of comma-separated parameters.
|
# empty list of comma-separated parameters.
|
||||||
|
@ -453,19 +403,13 @@ def p_param_1(t):
|
||||||
def p_decode_block(t):
|
def p_decode_block(t):
|
||||||
'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
|
'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
|
||||||
default_defaults = defaultStack.pop()
|
default_defaults = defaultStack.pop()
|
||||||
(decls, decode_code, exec_code, has_default) = t[5]
|
codeObj = t[5]
|
||||||
# use the "default defaults" only if there was no explicit
|
# use the "default defaults" only if there was no explicit
|
||||||
# default statement in decode_stmt_list
|
# default statement in decode_stmt_list
|
||||||
if not has_default:
|
if not codeObj.has_decode_default:
|
||||||
(default_decls, default_decode, default_exec) = default_defaults
|
codeObj += default_defaults
|
||||||
decls += default_decls
|
codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n')
|
||||||
decode_code += default_decode
|
t[0] = codeObj
|
||||||
exec_code += default_exec
|
|
||||||
t[0] = (decls, '''
|
|
||||||
switch (%s) {
|
|
||||||
%s
|
|
||||||
}
|
|
||||||
''' % (t[2], indent(decode_code)), exec_code)
|
|
||||||
|
|
||||||
# The opt_default statement serves only to push the "default defaults"
|
# The opt_default statement serves only to push the "default defaults"
|
||||||
# onto defaultStack. This value will be used by nested decode blocks,
|
# onto defaultStack. This value will be used by nested decode blocks,
|
||||||
|
@ -481,8 +425,9 @@ def p_opt_default_0(t):
|
||||||
def p_opt_default_1(t):
|
def p_opt_default_1(t):
|
||||||
'opt_default : DEFAULT inst'
|
'opt_default : DEFAULT inst'
|
||||||
# push the new default
|
# push the new default
|
||||||
(decls, decode_code, exec_code) = t[2]
|
codeObj = t[2]
|
||||||
defaultStack.push((decls, '\ndefault:\n%sbreak;' % decode_code, exec_code))
|
codeObj.wrap_decode_block('\ndefault:\n', 'break;\n')
|
||||||
|
defaultStack.push(codeObj)
|
||||||
# no meaningful value returned
|
# no meaningful value returned
|
||||||
t[0] = None
|
t[0] = None
|
||||||
|
|
||||||
|
@ -492,12 +437,9 @@ def p_decode_stmt_list_0(t):
|
||||||
|
|
||||||
def p_decode_stmt_list_1(t):
|
def p_decode_stmt_list_1(t):
|
||||||
'decode_stmt_list : decode_stmt decode_stmt_list'
|
'decode_stmt_list : decode_stmt decode_stmt_list'
|
||||||
(decls1, decode_code1, exec_code1, has_default1) = t[1]
|
if (t[1].has_decode_default and t[2].has_decode_default):
|
||||||
(decls2, decode_code2, exec_code2, has_default2) = t[2]
|
|
||||||
if (has_default1 and has_default2):
|
|
||||||
error(t.lineno(1), 'Two default cases in decode block')
|
error(t.lineno(1), 'Two default cases in decode block')
|
||||||
t[0] = (decls1 + '\n' + decls2, decode_code1 + '\n' + decode_code2,
|
t[0] = t[1] + t[2]
|
||||||
exec_code1 + '\n' + exec_code2, has_default1 or has_default2)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Decode statement rules
|
# Decode statement rules
|
||||||
|
@ -510,7 +452,7 @@ def p_decode_stmt_list_1(t):
|
||||||
|
|
||||||
|
|
||||||
# Preprocessor directives found in a decode statement list are passed
|
# Preprocessor directives found in a decode statement list are passed
|
||||||
# through to the output, replicated to both the declaration and decode
|
# through to the output, replicated to all of the output code
|
||||||
# streams. This works well for ifdefs, so we can ifdef out both the
|
# streams. This works well for ifdefs, so we can ifdef out both the
|
||||||
# declarations and the decode cases generated by an instruction
|
# declarations and the decode cases generated by an instruction
|
||||||
# definition. Handling them as part of the grammar makes it easy to
|
# definition. Handling them as part of the grammar makes it easy to
|
||||||
|
@ -518,7 +460,7 @@ def p_decode_stmt_list_1(t):
|
||||||
# the other statements.
|
# the other statements.
|
||||||
def p_decode_stmt_cpp(t):
|
def p_decode_stmt_cpp(t):
|
||||||
'decode_stmt : CPPDIRECTIVE'
|
'decode_stmt : CPPDIRECTIVE'
|
||||||
t[0] = (t[1], t[1], t[1], 0)
|
t[0] = GenCode(t[1], t[1], t[1], t[1])
|
||||||
|
|
||||||
# A format block 'format <foo> { ... }' sets the default instruction
|
# A format block 'format <foo> { ... }' sets the default instruction
|
||||||
# format used to handle instruction definitions inside the block.
|
# format used to handle instruction definitions inside the block.
|
||||||
|
@ -547,29 +489,31 @@ def p_push_format_id(t):
|
||||||
# specified constant, do a nested decode on some other field.
|
# specified constant, do a nested decode on some other field.
|
||||||
def p_decode_stmt_decode(t):
|
def p_decode_stmt_decode(t):
|
||||||
'decode_stmt : case_label COLON decode_block'
|
'decode_stmt : case_label COLON decode_block'
|
||||||
(label, is_default) = t[1]
|
label = t[1]
|
||||||
(decls, decode_code, exec_code) = t[3]
|
codeObj = t[3]
|
||||||
# just wrap the decoding code from the block as a case in the
|
# just wrap the decoding code from the block as a case in the
|
||||||
# outer switch statement.
|
# outer switch statement.
|
||||||
t[0] = (decls, '\n%s:\n%s' % (label, indent(decode_code)),
|
codeObj.wrap_decode_block('\n%s:\n' % label)
|
||||||
exec_code, is_default)
|
codeObj.has_decode_default = (label == 'default')
|
||||||
|
t[0] = codeObj
|
||||||
|
|
||||||
# Instruction definition (finally!).
|
# Instruction definition (finally!).
|
||||||
def p_decode_stmt_inst(t):
|
def p_decode_stmt_inst(t):
|
||||||
'decode_stmt : case_label COLON inst SEMI'
|
'decode_stmt : case_label COLON inst SEMI'
|
||||||
(label, is_default) = t[1]
|
label = t[1]
|
||||||
(decls, decode_code, exec_code) = t[3]
|
codeObj = t[3]
|
||||||
t[0] = (decls, '\n%s:%sbreak;' % (label, indent(decode_code)),
|
codeObj.wrap_decode_block('\n%s:' % label, 'break;\n')
|
||||||
exec_code, is_default)
|
codeObj.has_decode_default = (label == 'default')
|
||||||
|
t[0] = codeObj
|
||||||
|
|
||||||
# The case label is either a list of one or more constants or 'default'
|
# The case label is either a list of one or more constants or 'default'
|
||||||
def p_case_label_0(t):
|
def p_case_label_0(t):
|
||||||
'case_label : intlit_list'
|
'case_label : intlit_list'
|
||||||
t[0] = (': '.join(map(lambda a: 'case %#x' % a, t[1])), 0)
|
t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1]))
|
||||||
|
|
||||||
def p_case_label_1(t):
|
def p_case_label_1(t):
|
||||||
'case_label : DEFAULT'
|
'case_label : DEFAULT'
|
||||||
t[0] = ('default', 1)
|
t[0] = 'default'
|
||||||
|
|
||||||
#
|
#
|
||||||
# The constant list for a decode case label must be non-empty, but may have
|
# The constant list for a decode case label must be non-empty, but may have
|
||||||
|
@ -591,13 +535,13 @@ def p_inst_0(t):
|
||||||
'inst : ID LPAREN arg_list RPAREN'
|
'inst : ID LPAREN arg_list RPAREN'
|
||||||
# Pass the ID and arg list to the current format class to deal with.
|
# Pass the ID and arg list to the current format class to deal with.
|
||||||
currentFormat = formatStack.top()
|
currentFormat = formatStack.top()
|
||||||
(decls, decode_code, exec_code) = \
|
codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
|
||||||
currentFormat.defineInst(t[1], t[3], t.lineno(1))
|
|
||||||
args = ','.join(map(str, t[3]))
|
args = ','.join(map(str, t[3]))
|
||||||
args = re.sub('(?m)^', '//', args)
|
args = re.sub('(?m)^', '//', args)
|
||||||
args = re.sub('^//', '', args)
|
args = re.sub('^//', '', args)
|
||||||
comment = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
|
comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
|
||||||
t[0] = (comment + decls, comment + decode_code, comment + exec_code)
|
codeObj.prepend_all(comment)
|
||||||
|
t[0] = codeObj
|
||||||
|
|
||||||
# Define an instruction using an explicitly specified format:
|
# Define an instruction using an explicitly specified format:
|
||||||
# "<fmt>::<mnemonic>(<args>)"
|
# "<fmt>::<mnemonic>(<args>)"
|
||||||
|
@ -607,10 +551,10 @@ def p_inst_1(t):
|
||||||
format = formatMap[t[1]]
|
format = formatMap[t[1]]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
|
error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
|
||||||
(decls, decode_code, exec_code) = \
|
codeObj = format.defineInst(t[3], t[5], t.lineno(1))
|
||||||
format.defineInst(t[3], t[5], t.lineno(1))
|
comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
|
||||||
comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5])
|
codeObj.prepend_all(comment)
|
||||||
t[0] = (comment + decls, comment + decode_code, comment + exec_code)
|
t[0] = codeObj
|
||||||
|
|
||||||
def p_arg_list_0(t):
|
def p_arg_list_0(t):
|
||||||
'arg_list : empty'
|
'arg_list : empty'
|
||||||
|
@ -652,6 +596,133 @@ def p_error(t):
|
||||||
# Now build the parser.
|
# Now build the parser.
|
||||||
yacc.yacc()
|
yacc.yacc()
|
||||||
|
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
#
|
||||||
|
# Support Classes
|
||||||
|
#
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
################
|
||||||
|
# CpuModel class
|
||||||
|
#
|
||||||
|
# The CpuModel class encapsulates everything we need to know about a
|
||||||
|
# particular CPU model.
|
||||||
|
|
||||||
|
class CpuModel:
|
||||||
|
# List of all CPU models. Accessible as CpuModel.list.
|
||||||
|
list = []
|
||||||
|
|
||||||
|
# Constructor. Automatically adds models to CpuModel.list.
|
||||||
|
def __init__(self, name, filename, includes, strings):
|
||||||
|
self.name = name
|
||||||
|
self.filename = filename # filename for output exec code
|
||||||
|
self.includes = includes # include files needed in exec file
|
||||||
|
# The 'strings' dict holds all the per-CPU symbols we can
|
||||||
|
# substitute into templates etc.
|
||||||
|
self.strings = strings
|
||||||
|
# Add self to list.
|
||||||
|
CpuModel.list.append(self)
|
||||||
|
|
||||||
|
# Define CPU models. The following lines should contain the only
|
||||||
|
# CPU-model-specific information in this file. Note that the ISA
|
||||||
|
# description itself should have *no* CPU-model-specific content.
|
||||||
|
CpuModel('SimpleCPU', 'simple_cpu_exec.cc',
|
||||||
|
'#include "cpu/simple_cpu/simple_cpu.hh"',
|
||||||
|
{ 'CPU_exec_context': 'SimpleCPU' })
|
||||||
|
CpuModel('FullCPU', 'full_cpu_exec.cc',
|
||||||
|
'#include "cpu/full_cpu/dyn_inst.hh"',
|
||||||
|
{ 'CPU_exec_context': 'DynInst' })
|
||||||
|
|
||||||
|
# Expand template with CPU-specific references into a dictionary with
|
||||||
|
# an entry for each CPU model name. The entry key is the model name
|
||||||
|
# and the corresponding value is the template with the CPU-specific
|
||||||
|
# refs substituted for that model.
|
||||||
|
def expand_cpu_symbols_to_dict(template):
|
||||||
|
# Protect '%'s that don't go with CPU-specific terms
|
||||||
|
t = re.sub(r'%(?!\(CPU_)', '%%', template)
|
||||||
|
result = {}
|
||||||
|
for cpu in CpuModel.list:
|
||||||
|
result[cpu.name] = t % cpu.strings
|
||||||
|
return result
|
||||||
|
|
||||||
|
# *If* the template has CPU-specific references, return a single
|
||||||
|
# string containing a copy of the template for each CPU model with the
|
||||||
|
# corresponding values substituted in. If the template has no
|
||||||
|
# CPU-specific references, it is returned unmodified.
|
||||||
|
def expand_cpu_symbols_to_string(template):
|
||||||
|
if template.find('%(CPU_') != -1:
|
||||||
|
return reduce(lambda x,y: x+y,
|
||||||
|
expand_cpu_symbols_to_dict(template).values())
|
||||||
|
else:
|
||||||
|
return template
|
||||||
|
|
||||||
|
# Protect CPU-specific references by doubling the corresponding '%'s
|
||||||
|
# (in preparation for substituting a different set of references into
|
||||||
|
# the template).
|
||||||
|
def protect_cpu_symbols(template):
|
||||||
|
return re.sub(r'%(?=\(CPU_)', '%%', template)
|
||||||
|
|
||||||
|
###############
|
||||||
|
# GenCode class
|
||||||
|
#
|
||||||
|
# The GenCode class encapsulates generated code destined for various
|
||||||
|
# output files. The header_output and decoder_output attributes are
|
||||||
|
# strings containing code destined for decoder.hh and decoder.cc
|
||||||
|
# respectively. The decode_block attribute contains code to be
|
||||||
|
# incorporated in the decode function itself (that will also end up in
|
||||||
|
# decoder.cc). The exec_output attribute is a dictionary with a key
|
||||||
|
# for each CPU model name; the value associated with a particular key
|
||||||
|
# is the string of code for that CPU model's exec.cc file. The
|
||||||
|
# has_decode_default attribute is used in the decode block to allow
|
||||||
|
# explicit default clauses to override default default clauses.
|
||||||
|
|
||||||
|
class GenCode:
|
||||||
|
# Constructor. At this point we substitute out all CPU-specific
|
||||||
|
# symbols. For the exec output, these go into the per-model
|
||||||
|
# dictionary. For all other output types they get collapsed into
|
||||||
|
# a single string.
|
||||||
|
def __init__(self,
|
||||||
|
header_output = '', decoder_output = '', exec_output = '',
|
||||||
|
decode_block = '', has_decode_default = False):
|
||||||
|
self.header_output = expand_cpu_symbols_to_string(header_output)
|
||||||
|
self.decoder_output = expand_cpu_symbols_to_string(decoder_output)
|
||||||
|
if isinstance(exec_output, dict):
|
||||||
|
self.exec_output = exec_output
|
||||||
|
elif isinstance(exec_output, str):
|
||||||
|
# If the exec_output arg is a single string, we replicate
|
||||||
|
# it for each of the CPU models, substituting and
|
||||||
|
# %(CPU_foo)s params appropriately.
|
||||||
|
self.exec_output = expand_cpu_symbols_to_dict(exec_output)
|
||||||
|
self.decode_block = expand_cpu_symbols_to_string(decode_block)
|
||||||
|
self.has_decode_default = has_decode_default
|
||||||
|
|
||||||
|
# Override '+' operator: generate a new GenCode object that
|
||||||
|
# concatenates all the individual strings in the operands.
|
||||||
|
def __add__(self, other):
|
||||||
|
exec_output = {}
|
||||||
|
for cpu in CpuModel.list:
|
||||||
|
n = cpu.name
|
||||||
|
exec_output[n] = self.exec_output[n] + other.exec_output[n]
|
||||||
|
return GenCode(self.header_output + other.header_output,
|
||||||
|
self.decoder_output + other.decoder_output,
|
||||||
|
exec_output,
|
||||||
|
self.decode_block + other.decode_block,
|
||||||
|
self.has_decode_default or other.has_decode_default)
|
||||||
|
|
||||||
|
# Prepend a string (typically a comment) to all the strings.
|
||||||
|
def prepend_all(self, pre):
|
||||||
|
self.header_output = pre + self.header_output
|
||||||
|
self.decoder_output = pre + self.decoder_output
|
||||||
|
self.decode_block = pre + self.decode_block
|
||||||
|
for cpu in CpuModel.list:
|
||||||
|
self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]
|
||||||
|
|
||||||
|
# Wrap the decode block in a pair of strings (e.g., 'case foo:'
|
||||||
|
# and 'break;'). Used to build the big nested switch statement.
|
||||||
|
def wrap_decode_block(self, pre, post = ''):
|
||||||
|
self.decode_block = pre + indent(self.decode_block) + post
|
||||||
|
|
||||||
################
|
################
|
||||||
# Format object.
|
# Format object.
|
||||||
#
|
#
|
||||||
|
@ -664,24 +735,31 @@ class Format:
|
||||||
# constructor: just save away arguments
|
# constructor: just save away arguments
|
||||||
self.id = id
|
self.id = id
|
||||||
self.params = params
|
self.params = params
|
||||||
# strip blank lines from code (ones at the end are troublesome)
|
label = 'def format ' + id
|
||||||
code = re.sub(r'(?m)^\s*$', '', code);
|
self.user_code = compile(fixPythonIndentation(code), label, 'exec')
|
||||||
if code == '':
|
|
||||||
code = ' pass\n'
|
|
||||||
param_list = string.join(params, ", ")
|
param_list = string.join(params, ", ")
|
||||||
f = 'def defInst(name, Name, ' + param_list + '):\n' + code
|
f = '''def defInst(_code, _context, %s):
|
||||||
c = compile(f, 'def format ' + id, 'exec')
|
my_locals = vars().copy()
|
||||||
exec(c)
|
exec _code in _context, my_locals
|
||||||
|
return my_locals\n''' % param_list
|
||||||
|
c = compile(f, label + ' wrapper', 'exec')
|
||||||
|
exec c
|
||||||
self.func = defInst
|
self.func = defInst
|
||||||
|
|
||||||
def defineInst(self, name, args, lineno):
|
def defineInst(self, name, args, lineno):
|
||||||
# automatically provide a capitalized version of mnemonic
|
context = {}
|
||||||
Name = string.capitalize(name)
|
updateExportContext()
|
||||||
|
context.update(exportContext)
|
||||||
|
context.update({ 'name': name, 'Name': string.capitalize(name) })
|
||||||
try:
|
try:
|
||||||
retval = self.func(name, Name, *args)
|
vars = self.func(self.user_code, context, *args)
|
||||||
except:
|
except Exception, exc:
|
||||||
error_bt(lineno, 'error defining "%s".' % name)
|
error(lineno, 'error defining "%s": %s.' % (name, exc))
|
||||||
return retval
|
for k in vars.keys():
|
||||||
|
if k not in ('header_output', 'decoder_output',
|
||||||
|
'exec_output', 'decode_block'):
|
||||||
|
del vars[k]
|
||||||
|
return GenCode(**vars)
|
||||||
|
|
||||||
# Special null format to catch an implicit-format instruction
|
# Special null format to catch an implicit-format instruction
|
||||||
# definition outside of any format block.
|
# definition outside of any format block.
|
||||||
|
@ -766,13 +844,13 @@ def fixPythonIndentation(s):
|
||||||
# Error handler. Just call exit. Output formatted to work under
|
# Error handler. Just call exit. Output formatted to work under
|
||||||
# Emacs compile-mode.
|
# Emacs compile-mode.
|
||||||
def error(lineno, string):
|
def error(lineno, string):
|
||||||
sys.exit("%s:%d: %s" % (isa_desc_filename, lineno, string))
|
sys.exit("%s:%d: %s" % (input_filename, lineno, string))
|
||||||
|
|
||||||
# Like error(), but include a Python stack backtrace (for processing
|
# Like error(), but include a Python stack backtrace (for processing
|
||||||
# Python exceptions).
|
# Python exceptions).
|
||||||
def error_bt(lineno, string):
|
def error_bt(lineno, string):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string)
|
print >> sys.stderr, "%s:%d: %s" % (input_filename, lineno, string)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -817,6 +895,37 @@ def substBitOps(code):
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Template objects.
|
||||||
|
#
|
||||||
|
# Template objects are format strings that allow substitution from
|
||||||
|
# the attribute spaces of other objects (e.g. InstObjParams instances).
|
||||||
|
|
||||||
|
class Template:
|
||||||
|
def __init__(self, t):
|
||||||
|
self.template = t
|
||||||
|
|
||||||
|
def subst(self, d):
|
||||||
|
# Start with the template namespace. Make a copy since we're
|
||||||
|
# going to modify it.
|
||||||
|
myDict = templateMap.copy()
|
||||||
|
# if the argument is a dictionary, we just use it.
|
||||||
|
if isinstance(d, dict):
|
||||||
|
myDict.update(d)
|
||||||
|
# if the argument is an object, we use its attribute map.
|
||||||
|
elif hasattr(d, '__dict__'):
|
||||||
|
myDict.update(d.__dict__)
|
||||||
|
else:
|
||||||
|
raise TypeError, "Template.subst() arg must be or have dictionary"
|
||||||
|
# CPU-model-specific substitutions are handled later (in GenCode).
|
||||||
|
return protect_cpu_symbols(self.template) % myDict
|
||||||
|
|
||||||
|
# Convert to string. This handles the case when a template with a
|
||||||
|
# CPU-specific term gets interpolated into another template or into
|
||||||
|
# an output block.
|
||||||
|
def __str__(self):
|
||||||
|
return expand_cpu_symbols_to_string(self.template)
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
#
|
#
|
||||||
# Code Parser
|
# Code Parser
|
||||||
|
@ -1111,6 +1220,22 @@ class NPCOperandTraits(OperandTraits):
|
||||||
return 'xc->setNextPC(%s);\n' % op_desc.munged_name
|
return 'xc->setNextPC(%s);\n' % op_desc.munged_name
|
||||||
|
|
||||||
|
|
||||||
|
exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits',
|
||||||
|
'ControlRegOperandTraits', 'MemOperandTraits',
|
||||||
|
'NPCOperandTraits', 'InstObjParams', 'CodeBlock',
|
||||||
|
're', 'string')
|
||||||
|
|
||||||
|
exportContext = {}
|
||||||
|
|
||||||
|
def updateExportContext():
|
||||||
|
exportContext.update(exportDict(*exportContextSymbols))
|
||||||
|
exportContext.update(templateMap)
|
||||||
|
|
||||||
|
|
||||||
|
def exportDict(*symNames):
|
||||||
|
return dict([(s, eval(s)) for s in symNames])
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Define operand variables that get derived from the basic declaration
|
# Define operand variables that get derived from the basic declaration
|
||||||
# of ISA-specific operands in operandTraitsMap. This function must be
|
# of ISA-specific operands in operandTraitsMap. This function must be
|
||||||
|
@ -1385,10 +1510,6 @@ class InstObjParams:
|
||||||
self.mnemonic = mnem
|
self.mnemonic = mnem
|
||||||
self.class_name = class_name
|
self.class_name = class_name
|
||||||
self.base_class = base_class
|
self.base_class = base_class
|
||||||
self.exec_func_declarations = '''
|
|
||||||
Fault execute(SimpleCPUExecContext *, Trace::InstRecord *);
|
|
||||||
Fault execute(FullCPUExecContext *, Trace::InstRecord *);
|
|
||||||
'''
|
|
||||||
if code_block:
|
if code_block:
|
||||||
for code_attr in code_block.__dict__.keys():
|
for code_attr in code_block.__dict__.keys():
|
||||||
setattr(self, code_attr, getattr(code_block, code_attr))
|
setattr(self, code_attr, getattr(code_block, code_attr))
|
||||||
|
@ -1419,48 +1540,125 @@ class InstObjParams:
|
||||||
else:
|
else:
|
||||||
self.fp_enable_check = ''
|
self.fp_enable_check = ''
|
||||||
|
|
||||||
def _subst(self, template):
|
#######################
|
||||||
try:
|
#
|
||||||
return template % self.__dict__
|
# Output file template
|
||||||
except KeyError, key:
|
#
|
||||||
raise KeyError, 'InstObjParams.subst: no definition for %s' % key
|
|
||||||
|
|
||||||
def subst(self, *args):
|
file_template = '''
|
||||||
result = []
|
/*
|
||||||
for t in args:
|
* Copyright (c) 2003
|
||||||
try: template = templateMap[t]
|
* The Regents of The University of Michigan
|
||||||
except KeyError:
|
* All Rights Reserved
|
||||||
error(0, 'InstObjParams::subst: undefined template "%s"' % t)
|
*
|
||||||
if template.find('%(cpu_model)') != -1:
|
* This code is part of the M5 simulator, developed by Nathan Binkert,
|
||||||
tmp = ''
|
* Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
|
||||||
for cpu_model in ('SimpleCPUExecContext', 'FullCPUExecContext'):
|
* from Ron Dreslinski, Dave Greene, and Lisa Hsu.
|
||||||
self.cpu_model = cpu_model
|
*
|
||||||
tmp += self._subst(template)
|
* Permission is granted to use, copy, create derivative works and
|
||||||
result.append(tmp)
|
* redistribute this software and such derivative works for any
|
||||||
|
* purpose, so long as the copyright notice above, this grant of
|
||||||
|
* permission, and the disclaimer below appear in all copies made; and
|
||||||
|
* so long as the name of The University of Michigan is not used in
|
||||||
|
* any advertising or publicity pertaining to the use or distribution
|
||||||
|
* of this software without specific, written prior authorization.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
|
||||||
|
* UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
|
||||||
|
* WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
|
||||||
|
* LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
|
||||||
|
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
|
||||||
|
* ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
|
||||||
|
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGES.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DO NOT EDIT THIS FILE!!!
|
||||||
|
*
|
||||||
|
* It was automatically generated from the ISA description in %(filename)s
|
||||||
|
*/
|
||||||
|
|
||||||
|
%(includes)s
|
||||||
|
|
||||||
|
%(global_output)s
|
||||||
|
|
||||||
|
namespace %(namespace)s {
|
||||||
|
|
||||||
|
%(namespace_output)s
|
||||||
|
|
||||||
|
} // namespace %(namespace)s
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# Update the output file only if the new contents are different from
|
||||||
|
# the current contents. Minimizes the files that need to be rebuilt
|
||||||
|
# after minor changes.
|
||||||
|
def update_if_needed(file, contents):
|
||||||
|
update = False
|
||||||
|
if os.access(file, os.R_OK):
|
||||||
|
f = open(file, 'r')
|
||||||
|
old_contents = f.read()
|
||||||
|
f.close()
|
||||||
|
if contents != old_contents:
|
||||||
|
print 'Updating', file
|
||||||
|
os.remove(file) # in case it's write-protected
|
||||||
|
update = True
|
||||||
else:
|
else:
|
||||||
result.append(self._subst(template))
|
print 'File', file, 'is unchanged'
|
||||||
if len(args) == 1:
|
else:
|
||||||
result = result[0]
|
print 'Generating', file
|
||||||
return result
|
update = True
|
||||||
|
if update:
|
||||||
|
f = open(file, 'w')
|
||||||
|
f.write(contents)
|
||||||
|
f.close()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Read in and parse the ISA description.
|
# Read in and parse the ISA description.
|
||||||
#
|
#
|
||||||
def parse_isa_desc(isa_desc_file, decoder_file):
|
def parse_isa_desc(isa_desc_file, output_dir, include_path):
|
||||||
# Arguments are the name of the ISA description (input) file and
|
# set a global var for the input filename... used in error messages
|
||||||
# the name of the C++ decoder (output) file.
|
global input_filename
|
||||||
global isa_desc_filename, decoder_filename
|
input_filename = isa_desc_file
|
||||||
isa_desc_filename = isa_desc_file
|
|
||||||
decoder_filename = decoder_file
|
|
||||||
|
|
||||||
# Suck the ISA description file in.
|
# Suck the ISA description file in.
|
||||||
input = open(isa_desc_filename)
|
input = open(isa_desc_file)
|
||||||
isa_desc = input.read()
|
isa_desc = input.read()
|
||||||
input.close()
|
input.close()
|
||||||
|
|
||||||
# Parse it.
|
# Parse it.
|
||||||
yacc.parse(isa_desc)
|
(isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
|
||||||
|
|
||||||
|
# grab the last three path components of isa_desc_file to put in
|
||||||
|
# the output
|
||||||
|
filename = '/'.join(isa_desc_file.split('/')[-3:])
|
||||||
|
|
||||||
|
# generate decoder.hh
|
||||||
|
includes = '#include "base/bitfield.hh" // for bitfield support'
|
||||||
|
global_output = global_code.header_output
|
||||||
|
namespace_output = namespace_code.header_output
|
||||||
|
update_if_needed(output_dir + '/decoder.hh', file_template % vars())
|
||||||
|
|
||||||
|
# generate decoder.cc
|
||||||
|
includes = '#include "%s/decoder.hh"' % include_path
|
||||||
|
global_output = global_code.decoder_output
|
||||||
|
namespace_output = namespace_code.decoder_output
|
||||||
|
namespace_output += namespace_code.decode_block
|
||||||
|
update_if_needed(output_dir + '/decoder.cc', file_template % vars())
|
||||||
|
|
||||||
|
# generate per-cpu exec files
|
||||||
|
for cpu in CpuModel.list:
|
||||||
|
includes = '#include "%s/decoder.hh"\n' % include_path
|
||||||
|
includes += cpu.includes
|
||||||
|
global_output = global_code.exec_output[cpu.name]
|
||||||
|
namespace_output = namespace_code.exec_output[cpu.name]
|
||||||
|
update_if_needed(output_dir + '/' + cpu.filename,
|
||||||
|
file_template % vars())
|
||||||
|
|
||||||
# Called as script: get args from command line.
|
# Called as script: get args from command line.
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parse_isa_desc(sys.argv[1], sys.argv[2])
|
parse_isa_desc(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include "base/loader/symtab.hh"
|
#include "base/loader/symtab.hh"
|
||||||
#include "cpu/pc_event.hh"
|
#include "cpu/pc_event.hh"
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
|
#include "cpu/exec_context.hh"
|
||||||
|
|
||||||
// forward declarations
|
// forward declarations
|
||||||
#ifdef FULL_SYSTEM
|
#ifdef FULL_SYSTEM
|
||||||
|
@ -46,6 +46,11 @@ class PhysicalMemory;
|
||||||
|
|
||||||
class RemoteGDB;
|
class RemoteGDB;
|
||||||
class GDBListener;
|
class GDBListener;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
|
||||||
#endif // FULL_SYSTEM
|
#endif // FULL_SYSTEM
|
||||||
|
|
||||||
class MemInterface;
|
class MemInterface;
|
||||||
|
@ -305,6 +310,4 @@ class SimpleCPU : public BaseCPU
|
||||||
ExecContext *xcBase() { return xc; }
|
ExecContext *xcBase() { return xc; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SimpleCPU SimpleCPUExecContext;
|
|
||||||
|
|
||||||
#endif // __SIMPLE_CPU_HH__
|
#endif // __SIMPLE_CPU_HH__
|
||||||
|
|
|
@ -42,9 +42,7 @@
|
||||||
// forward declarations
|
// forward declarations
|
||||||
class ExecContext;
|
class ExecContext;
|
||||||
class DynInst;
|
class DynInst;
|
||||||
typedef DynInst FullCPUExecContext;
|
|
||||||
class SimpleCPU;
|
class SimpleCPU;
|
||||||
typedef SimpleCPU SimpleCPUExecContext;
|
|
||||||
class SymbolTable;
|
class SymbolTable;
|
||||||
|
|
||||||
namespace Trace {
|
namespace Trace {
|
||||||
|
@ -249,7 +247,8 @@ class StaticInst : public StaticInstBase
|
||||||
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for
|
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for
|
||||||
* just the EA computation.
|
* just the EA computation.
|
||||||
*/
|
*/
|
||||||
virtual StaticInstPtr<ISA> eaCompInst() { return nullStaticInstPtr; }
|
virtual const
|
||||||
|
StaticInstPtr<ISA> &eaCompInst() const { return nullStaticInstPtr; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory references only: returns "fake" instruction representing
|
* Memory references only: returns "fake" instruction representing
|
||||||
|
@ -257,7 +256,8 @@ class StaticInst : public StaticInstBase
|
||||||
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for
|
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for
|
||||||
* just the memory access (not the EA computation).
|
* just the memory access (not the EA computation).
|
||||||
*/
|
*/
|
||||||
virtual StaticInstPtr<ISA> memAccInst() { return nullStaticInstPtr; }
|
virtual const
|
||||||
|
StaticInstPtr<ISA> &memAccInst() const { return nullStaticInstPtr; }
|
||||||
|
|
||||||
/// The binary machine instruction.
|
/// The binary machine instruction.
|
||||||
const MachInst machInst;
|
const MachInst machInst;
|
||||||
|
@ -307,14 +307,12 @@ class StaticInst : public StaticInstBase
|
||||||
/**
|
/**
|
||||||
* Execute this instruction under SimpleCPU model.
|
* Execute this instruction under SimpleCPU model.
|
||||||
*/
|
*/
|
||||||
virtual Fault execute(SimpleCPUExecContext *xc,
|
virtual Fault execute(SimpleCPU *xc, Trace::InstRecord *traceData) = 0;
|
||||||
Trace::InstRecord *traceData) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute this instruction under detailed FullCPU model.
|
* Execute this instruction under detailed FullCPU model.
|
||||||
*/
|
*/
|
||||||
virtual Fault execute(FullCPUExecContext *xc,
|
virtual Fault execute(DynInst *xc, Trace::InstRecord *traceData) = 0;
|
||||||
Trace::InstRecord *traceData) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the target address for a PC-relative branch.
|
* Return the target address for a PC-relative branch.
|
||||||
|
|
Loading…
Reference in a new issue