Add keyword parameters and list-valued arguments to

instruction format functions in ISA description language.

Take advantage of these features to clean up memory
instruction definitions in Alpha.

arch/alpha/isa/decoder.isa:
arch/alpha/isa/mem.isa:
arch/alpha/isa/pal.isa:
    Take advantage of new keyword parameters to disambiguate
    instruction vs. memory-request flags, and to provide
    a default EA calculation for memory ops (since 99% of them
    are the same).
arch/isa_parser.py:
    Add two new features to instruction format functions:
    - Keyword parameters, a la Python.
    - List-valued arguments.

    Also export makeList() function to Python code blocks,
    as this is handy for dealing with flags.

--HG--
extra : convert_revision : 99bbbaa2e765230aa96b6a06ed193793325f9fb0
This commit is contained in:
Steve Reinhardt 2006-02-11 15:11:00 -05:00
parent 59ba3d463c
commit 3cc6c59582
4 changed files with 199 additions and 98 deletions

View file

@ -34,47 +34,47 @@ decode OPCODE default Unknown::unknown() {
} }
format LoadOrNop { format LoadOrNop {
0x0a: ldbu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.ub; }}); 0x0a: ldbu({{ Ra.uq = Mem.ub; }});
0x0c: ldwu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uw; }}); 0x0c: ldwu({{ Ra.uq = Mem.uw; }});
0x0b: ldq_u({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}); 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }});
0x23: ldt({{ EA = Rb + disp; }}, {{ Fa = Mem.df; }}); 0x23: ldt({{ Fa = Mem.df; }});
0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED); 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED);
0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED); 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED);
0x20: MiscPrefetch::copy_load({{ EA = Ra; }}, 0x20: MiscPrefetch::copy_load({{ EA = Ra; }},
{{ fault = xc->copySrcTranslate(EA); }}, {{ fault = xc->copySrcTranslate(EA); }},
IsMemRef, IsLoad, IsCopy); inst_flags = [IsMemRef, IsLoad, IsCopy]);
} }
format LoadOrPrefetch { format LoadOrPrefetch {
0x28: ldl({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}); 0x28: ldl({{ Ra.sl = Mem.sl; }});
0x29: ldq({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, EVICT_NEXT); 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT);
// IsFloating flag on lds gets the prefetch to disassemble // IsFloating flag on lds gets the prefetch to disassemble
// using f31 instead of r31... funcitonally it's unnecessary // using f31 instead of r31... funcitonally it's unnecessary
0x22: lds({{ EA = Rb + disp; }}, {{ Fa.uq = s_to_t(Mem.ul); }}, 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }},
PF_EXCLUSIVE, IsFloating); pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating);
} }
format Store { format Store {
0x0e: stb({{ EA = Rb + disp; }}, {{ Mem.ub = Ra<7:0>; }}); 0x0e: stb({{ Mem.ub = Ra<7:0>; }});
0x0d: stw({{ EA = Rb + disp; }}, {{ Mem.uw = Ra<15:0>; }}); 0x0d: stw({{ Mem.uw = Ra<15:0>; }});
0x2c: stl({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }}); 0x2c: stl({{ Mem.ul = Ra<31:0>; }});
0x2d: stq({{ EA = Rb + disp; }}, {{ Mem.uq = Ra.uq; }}); 0x2d: stq({{ Mem.uq = Ra.uq; }});
0x0f: stq_u({{ EA = (Rb + disp) & ~7; }}, {{ Mem.uq = Ra.uq; }}); 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }});
0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }}); 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }});
0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }}); 0x27: stt({{ Mem.df = Fa; }});
0x24: MiscPrefetch::copy_store({{ EA = Rb; }}, 0x24: MiscPrefetch::copy_store({{ EA = Rb; }},
{{ fault = xc->copy(EA); }}, {{ fault = xc->copy(EA); }},
IsMemRef, IsStore, IsCopy); inst_flags = [IsMemRef, IsStore, IsCopy]);
} }
format StoreCond { format StoreCond {
0x2e: stl_c({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }}, 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }},
{{ {{
uint64_t tmp = write_result; uint64_t tmp = write_result;
// see stq_c // see stq_c
Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
}}, LOCKED); }}, mem_flags = LOCKED);
0x2f: stq_c({{ EA = Rb + disp; }}, {{ Mem.uq = Ra; }}, 0x2f: stq_c({{ Mem.uq = Ra; }},
{{ {{
uint64_t tmp = write_result; uint64_t tmp = write_result;
// If the write operation returns 0 or 1, then // If the write operation returns 0 or 1, then
@ -85,7 +85,7 @@ decode OPCODE default Unknown::unknown() {
// mailbox access, and we don't update the // mailbox access, and we don't update the
// result register at all. // result register at all.
Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
}}, LOCKED); }}, mem_flags = LOCKED);
} }
format IntegerOperate { format IntegerOperate {
@ -607,8 +607,9 @@ decode OPCODE default Unknown::unknown() {
format MiscPrefetch { format MiscPrefetch {
0xf800: wh64({{ EA = Rb & ~ULL(63); }}, 0xf800: wh64({{ EA = Rb & ~ULL(63); }},
{{ xc->writeHint(EA, 64, memAccessFlags); }}, {{ xc->writeHint(EA, 64, memAccessFlags); }},
IsMemRef, IsDataPrefetch, IsStore, MemWriteOp, mem_flags = NO_FAULT,
NO_FAULT); inst_flags = [IsMemRef, IsDataPrefetch,
IsStore, MemWriteOp]);
} }
format BasicOperate { format BasicOperate {

View file

@ -407,16 +407,12 @@ def template LoadPrefetchCheckDecode {{
let {{ let {{
def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
base_class = 'MemoryDisp32', flags = [], postacc_code = '', base_class = 'MemoryDisp32',
decode_template = BasicDecode, exec_template_base = ''): decode_template = BasicDecode, exec_template_base = ''):
# Segregate flags into instruction flags (handled by InstObjParams) # Make sure flags are in lists (convert to lists if not).
# and memory access flags (handled here). mem_flags = makeList(mem_flags)
inst_flags = makeList(inst_flags)
# Would be nice to autogenerate this list, but oh well.
valid_mem_flags = ['LOCKED', 'NO_FAULT', 'EVICT_NEXT', 'PF_EXCLUSIVE']
mem_flags = [f for f in flags if f in valid_mem_flags]
inst_flags = [f for f in flags if f not in valid_mem_flags]
# add hook to get effective addresses into execution trace output. # add hook to get effective addresses into execution trace output.
ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
@ -469,31 +465,39 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
}}; }};
def format LoadOrNop(ea_code, memacc_code, *flags) {{ def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags, LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
decode_template = LoadNopCheckDecode, decode_template = LoadNopCheckDecode,
exec_template_base = 'Load') exec_template_base = 'Load')
}}; }};
// Note that the flags passed in apply only to the prefetch version // Note that the flags passed in apply only to the prefetch version
def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{ def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }},
mem_flags = [], pf_flags = [], inst_flags = []) {{
# declare the load instruction object and generate the decode block # declare the load instruction object and generate the decode block
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
decode_template = LoadPrefetchCheckDecode, decode_template = LoadPrefetchCheckDecode,
exec_template_base = 'Load') exec_template_base = 'Load')
# Declare the prefetch instruction object. # Declare the prefetch instruction object.
# convert flags from tuple to list to make them mutable # Make sure flag args are lists so we can mess with them.
pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'MemReadOp', 'NO_FAULT'] mem_flags = makeList(mem_flags)
pf_flags = makeList(pf_flags)
inst_flags = makeList(inst_flags)
pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT']
pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad',
'IsDataPrefetch', 'MemReadOp']
(pf_header_output, pf_decoder_output, _, pf_exec_output) = \ (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
LoadStoreBase(name, Name + 'Prefetch', ea_code, LoadStoreBase(name, Name + 'Prefetch', ea_code,
'xc->prefetch(EA, memAccessFlags);', 'xc->prefetch(EA, memAccessFlags);',
flags = pf_flags, exec_template_base = 'Misc') pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
header_output += pf_header_output header_output += pf_header_output
decoder_output += pf_decoder_output decoder_output += pf_decoder_output
@ -501,24 +505,28 @@ def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{
}}; }};
def format Store(ea_code, memacc_code, *flags) {{ def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags, LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
exec_template_base = 'Store') exec_template_base = 'Store')
}}; }};
def format StoreCond(ea_code, memacc_code, postacc_code, *flags) {{ def format StoreCond(memacc_code, postacc_code,
ea_code = {{ EA = Rb + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code, LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
flags = flags, exec_template_base = 'Store') postacc_code, exec_template_base = 'Store')
}}; }};
// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb // Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
def format MiscPrefetch(ea_code, memacc_code, *flags) {{ def format MiscPrefetch(ea_code, memacc_code,
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags, LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
base_class = 'MemoryNoDisp', exec_template_base = 'Misc') base_class = 'MemoryNoDisp', exec_template_base = 'Misc')
}}; }};

View file

@ -198,23 +198,25 @@ output decoder {{
def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{ def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
flags = flags, base_class = 'HwLoadStore', mem_flags = [], inst_flags = flags,
exec_template_base = 'Load') base_class = 'HwLoadStore', exec_template_base = 'Load')
}}; }};
def format HwStore(ea_code, memacc_code, class_ext, *flags) {{ def format HwStore(ea_code, memacc_code, class_ext, *flags) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
flags = flags, base_class = 'HwLoadStore', mem_flags = [], inst_flags = flags,
exec_template_base = 'Store') base_class = 'HwLoadStore', exec_template_base = 'Store')
}}; }};
def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, *flags) {{ def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext,
*flags) {{
(header_output, decoder_output, decode_block, exec_output) = \ (header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
postacc_code, flags = flags, base_class = 'HwLoadStore') postacc_code, mem_flags = [], inst_flags = flags,
base_class = 'HwLoadStore')
}}; }};

View file

@ -82,10 +82,9 @@ tokens = reserved + (
# ( ) [ ] { } < > , ; : :: * # ( ) [ ] { } < > , ; : :: *
'LPAREN', 'RPAREN', 'LPAREN', 'RPAREN',
# not used any more... commented out to suppress PLY warning 'LBRACKET', 'RBRACKET',
# 'LBRACKET', 'RBRACKET',
'LBRACE', 'RBRACE', 'LBRACE', 'RBRACE',
'LESS', 'GREATER', 'LESS', 'GREATER', 'EQUALS',
'COMMA', 'SEMI', 'COLON', 'DBLCOLON', 'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
'ASTERISK', 'ASTERISK',
@ -104,13 +103,13 @@ tokens = reserved + (
# Regular expressions for token matching # Regular expressions for token matching
t_LPAREN = r'\(' t_LPAREN = r'\('
t_RPAREN = r'\)' t_RPAREN = r'\)'
# not used any more... commented out to suppress PLY warning t_LBRACKET = r'\['
# t_LBRACKET = r'\[' t_RBRACKET = r'\]'
# t_RBRACKET = r'\]'
t_LBRACE = r'\{' t_LBRACE = r'\{'
t_RBRACE = r'\}' t_RBRACE = r'\}'
t_LESS = r'\<' t_LESS = r'\<'
t_GREATER = r'\>' t_GREATER = r'\>'
t_EQUALS = r'='
t_COMMA = r',' t_COMMA = r','
t_SEMI = r';' t_SEMI = r';'
t_COLON = r':' t_COLON = r':'
@ -387,32 +386,66 @@ def p_def_format(t):
t[0] = GenCode() t[0] = GenCode()
# 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. Positional (standard,
# non-keyword) parameters must come first, followed by keyword
# parameters, followed by a '*foo' parameter that gets excess
# positional arguments (as in Python). Each of these three parameter
# categories is optional.
#
# Note that we do not support the '**foo' parameter for collecting
# otherwise undefined keyword args. Otherwise the parameter list is
# (I believe) identical to what is supported in Python.
#
# The param list generates a tuple, where the first element is a list of
# the positional params and the second element is a dict containing the
# keyword params.
def p_param_list_0(t): def p_param_list_0(t):
'param_list : empty' 'param_list : positional_param_list COMMA nonpositional_param_list'
t[0] = [ ] t[0] = t[1] + t[3]
def p_param_list_1(t): def p_param_list_1(t):
'param_list : param' '''param_list : positional_param_list
| nonpositional_param_list'''
t[0] = t[1]
def p_positional_param_list_0(t):
'positional_param_list : empty'
t[0] = []
def p_positional_param_list_1(t):
'positional_param_list : ID'
t[0] = [t[1]] t[0] = [t[1]]
def p_param_list_2(t): def p_positional_param_list_2(t):
'param_list : param_list COMMA param' 'positional_param_list : positional_param_list COMMA ID'
t[0] = t[1] t[0] = t[1] + [t[3]]
t[0].append(t[3])
# Each formal parameter is either an identifier or an identifier def p_nonpositional_param_list_0(t):
# preceded by an asterisk. As in Python, the latter (if present) gets 'nonpositional_param_list : keyword_param_list COMMA excess_args_param'
# a tuple containing all the excess positional arguments, allowing t[0] = t[1] + t[3]
# varargs functions.
def p_param_0(t): def p_nonpositional_param_list_1(t):
'param : ID' '''nonpositional_param_list : keyword_param_list
| excess_args_param'''
t[0] = t[1] t[0] = t[1]
def p_param_1(t): def p_keyword_param_list_0(t):
'param : ASTERISK ID' 'keyword_param_list : keyword_param'
# just concatenate them: '*ID' t[0] = [t[1]]
t[0] = t[1] + t[2]
def p_keyword_param_list_1(t):
'keyword_param_list : keyword_param_list COMMA keyword_param'
t[0] = t[1] + [t[3]]
def p_keyword_param(t):
'keyword_param : ID EQUALS expr'
t[0] = t[1] + ' = ' + t[3].__repr__()
def p_excess_args_param(t):
'excess_args_param : ASTERISK ID'
# Just concatenate them: '*ID'. Wrap in list to be consistent
# with positional_param_list and keyword_param_list.
t[0] = [t[1] + t[2]]
# End of format definition-related rules. # End of format definition-related rules.
############## ##############
@ -577,26 +610,79 @@ def p_inst_1(t):
codeObj.prepend_all(comment) codeObj.prepend_all(comment)
t[0] = codeObj t[0] = codeObj
# The arg list generates a tuple, where the first element is a list of
# the positional args and the second element is a dict containing the
# keyword args.
def p_arg_list_0(t): def p_arg_list_0(t):
'arg_list : empty' 'arg_list : positional_arg_list COMMA keyword_arg_list'
t[0] = [ ] t[0] = ( t[1], t[3] )
def p_arg_list_1(t): def p_arg_list_1(t):
'arg_list : arg' 'arg_list : positional_arg_list'
t[0] = [t[1]] t[0] = ( t[1], {} )
def p_arg_list_2(t): def p_arg_list_2(t):
'arg_list : arg_list COMMA arg' 'arg_list : keyword_arg_list'
t[0] = t[1] t[0] = ( [], t[1] )
t[0].append(t[3])
def p_arg(t): def p_positional_arg_list_0(t):
'''arg : ID 'positional_arg_list : empty'
| INTLIT t[0] = []
| STRLIT
| CODELIT''' def p_positional_arg_list_1(t):
'positional_arg_list : expr'
t[0] = [t[1]]
def p_positional_arg_list_2(t):
'positional_arg_list : positional_arg_list COMMA expr'
t[0] = t[1] + [t[3]]
def p_keyword_arg_list_0(t):
'keyword_arg_list : keyword_arg'
t[0] = t[1] t[0] = t[1]
def p_keyword_arg_list_1(t):
'keyword_arg_list : keyword_arg_list COMMA keyword_arg'
t[0] = t[1]
t[0].update(t[3])
def p_keyword_arg(t):
'keyword_arg : ID EQUALS expr'
t[0] = { t[1] : t[3] }
#
# Basic expressions. These constitute the argument values of
# "function calls" (i.e. instruction definitions in the decode block)
# and default values for formal parameters of format functions.
#
# Right now, these are either strings, integers, or (recursively)
# lists of exprs (using Python square-bracket list syntax). Note that
# bare identifiers are trated as string constants here (since there
# isn't really a variable namespace to refer to).
#
def p_expr_0(t):
'''expr : ID
| INTLIT
| STRLIT
| CODELIT'''
t[0] = t[1]
def p_expr_1(t):
'''expr : LBRACKET list_expr RBRACKET'''
t[0] = t[2]
def p_list_expr_0(t):
'list_expr : expr'
t[0] = [t[1]]
def p_list_expr_1(t):
'list_expr : list_expr COMMA expr'
t[0] = t[1] + [t[3]]
def p_list_expr_2(t):
'list_expr : empty'
t[0] = []
# #
# Empty production... use in other rules for readability. # Empty production... use in other rules for readability.
# #
@ -779,7 +865,7 @@ class Format:
context.update(exportContext) context.update(exportContext)
context.update({ 'name': name, 'Name': string.capitalize(name) }) context.update({ 'name': name, 'Name': string.capitalize(name) })
try: try:
vars = self.func(self.user_code, context, *args) vars = self.func(self.user_code, context, *args[0], **args[1])
except Exception, exc: except Exception, exc:
error(lineno, 'error defining "%s": %s.' % (name, exc)) error(lineno, 'error defining "%s": %s.' % (name, exc))
for k in vars.keys(): for k in vars.keys():
@ -974,14 +1060,18 @@ class Template:
# #
##################################################################### #####################################################################
# Force the argument to be a list # Force the argument to be a list. Useful for flags, where a caller
def makeList(list_or_item): # can specify a singleton flag or a list of flags. Also usful for
if not list_or_item: # converting tuples to lists so they can be modified.
def makeList(arg):
if isinstance(arg, list):
return arg
elif isinstance(arg, tuple):
return list(arg)
elif not arg:
return [] return []
elif type(list_or_item) == ListType:
return list_or_item
else: else:
return [ list_or_item ] return [ arg ]
# generate operandSizeMap based on provided operandTypeMap: # generate operandSizeMap based on provided operandTypeMap:
# basically generate equiv. C++ type and make is_signed flag # basically generate equiv. C++ type and make is_signed flag
@ -1253,7 +1343,7 @@ class NPCOperandTraits(OperandTraits):
exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits', exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits',
'ControlRegOperandTraits', 'MemOperandTraits', 'ControlRegOperandTraits', 'MemOperandTraits',
'NPCOperandTraits', 'InstObjParams', 'CodeBlock', 'NPCOperandTraits', 'InstObjParams', 'CodeBlock',
're', 'string') 'makeList', 're', 'string')
exportContext = {} exportContext = {}