Add keyword parameters and list-valued arguments to
authorSteve Reinhardt <stever@eecs.umich.edu>
Sat, 11 Feb 2006 20:11:00 +0000 (15:11 -0500)
committerSteve Reinhardt <stever@eecs.umich.edu>
Sat, 11 Feb 2006 20:11:00 +0000 (15:11 -0500)
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

arch/alpha/isa/decoder.isa
arch/alpha/isa/mem.isa
arch/alpha/isa/pal.isa
arch/isa_parser.py

index c21465928216f11594d65f4462a4d294eea01ad9..29124f191042480d6ffbf8247a7e2c10816747ef 100644 (file)
@@ -34,47 +34,47 @@ decode OPCODE default Unknown::unknown() {
     }
 
     format LoadOrNop {
-        0x0a: ldbu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.ub; }});
-        0x0c: ldwu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uw; }});
-        0x0b: ldq_u({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }});
-        0x23: ldt({{ EA = Rb + disp; }}, {{ Fa = Mem.df; }});
-        0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED);
-        0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED);
+        0x0a: ldbu({{ Ra.uq = Mem.ub; }});
+        0x0c: ldwu({{ Ra.uq = Mem.uw; }});
+        0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }});
+        0x23: ldt({{ Fa = Mem.df; }});
+        0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED);
+        0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED);
         0x20: MiscPrefetch::copy_load({{ EA = Ra; }},
                                       {{ fault = xc->copySrcTranslate(EA); }},
-                                      IsMemRef, IsLoad, IsCopy);
+                                      inst_flags = [IsMemRef, IsLoad, IsCopy]);
     }
 
     format LoadOrPrefetch {
-        0x28: ldl({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }});
-        0x29: ldq({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, EVICT_NEXT);
+        0x28: ldl({{ Ra.sl = Mem.sl; }});
+        0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT);
         // IsFloating flag on lds gets the prefetch to disassemble
         // using f31 instead of r31... funcitonally it's unnecessary
-        0x22: lds({{ EA = Rb + disp; }}, {{ Fa.uq = s_to_t(Mem.ul); }},
-                  PF_EXCLUSIVE, IsFloating);
+        0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }},
+                  pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating);
     }
 
     format Store {
-        0x0e: stb({{ EA = Rb + disp; }}, {{ Mem.ub = Ra<7:0>; }});
-        0x0d: stw({{ EA = Rb + disp; }}, {{ Mem.uw = Ra<15:0>; }});
-        0x2c: stl({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }});
-        0x2d: stq({{ EA = Rb + disp; }}, {{ Mem.uq = Ra.uq; }});
-        0x0f: stq_u({{ EA = (Rb + disp) & ~7; }}, {{ Mem.uq = Ra.uq; }});
-        0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }});
-        0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }});
+        0x0e: stb({{ Mem.ub = Ra<7:0>; }});
+        0x0d: stw({{ Mem.uw = Ra<15:0>; }});
+        0x2c: stl({{ Mem.ul = Ra<31:0>; }});
+        0x2d: stq({{ Mem.uq = Ra.uq; }});
+        0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }});
+        0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }});
+        0x27: stt({{ Mem.df = Fa; }});
         0x24: MiscPrefetch::copy_store({{ EA = Rb; }},
                                        {{ fault = xc->copy(EA); }},
-                                       IsMemRef, IsStore, IsCopy);
+                                       inst_flags = [IsMemRef, IsStore, IsCopy]);
     }
 
     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;
                         // see stq_c
                         Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
-                    }}, LOCKED);
-        0x2f: stq_c({{ EA = Rb + disp; }}, {{ Mem.uq = Ra; }},
+                    }}, mem_flags = LOCKED);
+        0x2f: stq_c({{ Mem.uq = Ra; }},
                     {{
                         uint64_t tmp = write_result;
                         // 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
                         // result register at all.
                         Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
-                    }}, LOCKED);
+                    }}, mem_flags = LOCKED);
     }
 
     format IntegerOperate {
@@ -607,8 +607,9 @@ decode OPCODE default Unknown::unknown() {
         format MiscPrefetch {
             0xf800: wh64({{ EA = Rb & ~ULL(63); }},
                          {{ xc->writeHint(EA, 64, memAccessFlags); }},
-                         IsMemRef, IsDataPrefetch, IsStore, MemWriteOp,
-                         NO_FAULT);
+                         mem_flags = NO_FAULT,
+                         inst_flags = [IsMemRef, IsDataPrefetch,
+                                       IsStore, MemWriteOp]);
         }
 
         format BasicOperate {
index 0d9d59cee7c4cd5bf9df7aa7b27b92971d813fe6..45afd378c5767ea42eadde710f57e099fb22044f 100644 (file)
@@ -407,16 +407,12 @@ def template LoadPrefetchCheckDecode {{
 
 
 let {{
-def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
-                  base_class = 'MemoryDisp32', flags = [],
+def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+                  postacc_code = '', base_class = 'MemoryDisp32',
                   decode_template = BasicDecode, exec_template_base = ''):
-    # Segregate flags into instruction flags (handled by InstObjParams)
-    # and memory access flags (handled here).
-
-    # 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]
+    # Make sure flags are in lists (convert to lists if not).
+    mem_flags = makeList(mem_flags)
+    inst_flags = makeList(inst_flags)
 
     # add hook to get effective addresses into execution trace output.
     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) = \
-        LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags,
+        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
                       decode_template = LoadNopCheckDecode,
                       exec_template_base = 'Load')
 }};
 
 
 // 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
     (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,
                       exec_template_base = 'Load')
 
     # Declare the prefetch instruction object.
 
-    # convert flags from tuple to list to make them mutable
-    pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'MemReadOp', 'NO_FAULT']
+    # Make sure flag args are lists so we can mess with them.
+    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) = \
         LoadStoreBase(name, Name + 'Prefetch', ea_code,
                       '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
     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) = \
-        LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags,
+        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
                       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) = \
-        LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code,
-                      flags = flags, exec_template_base = 'Store')
+        LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+                      postacc_code, exec_template_base = 'Store')
 }};
 
 
 // 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) = \
-        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')
 }};
 
index 552dde2d7c73d85f489924c95ccd9b501dee0b6b..b68a7c19fcfdc83abec5a98a2d5050a0834bd79b 100644 (file)
@@ -198,23 +198,25 @@ output decoder {{
 def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{
     (header_output, decoder_output, decode_block, exec_output) = \
         LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
-                      flags = flags, base_class = 'HwLoadStore',
-                      exec_template_base = 'Load')
+                      mem_flags = [], inst_flags = flags,
+                      base_class = 'HwLoadStore', exec_template_base = 'Load')
 }};
 
 
 def format HwStore(ea_code, memacc_code, class_ext, *flags) {{
     (header_output, decoder_output, decode_block, exec_output) = \
         LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
-                      flags = flags, base_class = 'HwLoadStore',
-                      exec_template_base = 'Store')
+                      mem_flags = [], inst_flags = flags,
+                      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) = \
         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')
 }};
 
 
index fffcc33e5edb7732a19752b5cb0153b4689e5265..e7f7a897c73ddcd7637d825e48350987765883c6 100755 (executable)
@@ -82,10 +82,9 @@ tokens = reserved + (
 
     # ( ) [ ] { } < > , ; : :: *
     'LPAREN', 'RPAREN',
-# not used any more... commented out to suppress PLY warning
-#    'LBRACKET', 'RBRACKET',
+    'LBRACKET', 'RBRACKET',
     'LBRACE', 'RBRACE',
-    'LESS', 'GREATER',
+    'LESS', 'GREATER', 'EQUALS',
     'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
     'ASTERISK',
 
@@ -104,13 +103,13 @@ tokens = reserved + (
 # Regular expressions for token matching
 t_LPAREN           = r'\('
 t_RPAREN           = r'\)'
-# not used any more... commented out to suppress PLY warning
-# t_LBRACKET         = r'\['
-# t_RBRACKET         = r'\]'
+t_LBRACKET         = r'\['
+t_RBRACKET         = r'\]'
 t_LBRACE           = r'\{'
 t_RBRACE           = r'\}'
 t_LESS             = r'\<'
 t_GREATER          = r'\>'
+t_EQUALS           = r'='
 t_COMMA            = r','
 t_SEMI             = r';'
 t_COLON            = r':'
@@ -387,32 +386,66 @@ def p_def_format(t):
     t[0] = GenCode()
 
 # 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):
-    'param_list : empty'
-    t[0] = ]
+    'param_list : positional_param_list COMMA nonpositional_param_list'
+    t[0] = t[1] + t[3]
 
 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]]
 
-def p_param_list_2(t):
-    'param_list : param_list COMMA param'
-    t[0] = t[1]
-    t[0].append(t[3])
+def p_positional_param_list_2(t):
+    'positional_param_list : positional_param_list COMMA ID'
+    t[0] = t[1] + [t[3]]
+
+def p_nonpositional_param_list_0(t):
+    'nonpositional_param_list : keyword_param_list COMMA excess_args_param'
+    t[0] = t[1] + t[3]
 
-# Each formal parameter is either an identifier or an identifier
-# preceded by an asterisk.  As in Python, the latter (if present) gets
-# a tuple containing all the excess positional arguments, allowing
-# varargs functions.
-def p_param_0(t):
-    'param : ID'
+def p_nonpositional_param_list_1(t):
+    '''nonpositional_param_list : keyword_param_list
+                                | excess_args_param'''
     t[0] = t[1]
 
-def p_param_1(t):
-    'param : ASTERISK ID'
-    # just concatenate them: '*ID'
-    t[0] = t[1] + t[2]
+def p_keyword_param_list_0(t):
+    'keyword_param_list : keyword_param'
+    t[0] = [t[1]]
+
+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.
 ##############
@@ -577,26 +610,79 @@ def p_inst_1(t):
     codeObj.prepend_all(comment)
     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):
-    'arg_list : empty'
-    t[0] = [ ]
+    'arg_list : positional_arg_list COMMA keyword_arg_list'
+    t[0] = ( t[1], t[3] )
 
 def p_arg_list_1(t):
-    'arg_list : arg'
-    t[0] = [t[1]]
+    'arg_list : positional_arg_list'
+    t[0] = ( t[1], {} )
 
 def p_arg_list_2(t):
-    'arg_list : arg_list COMMA arg'
+    'arg_list : keyword_arg_list'
+    t[0] = ( [], t[1] )
+
+def p_positional_arg_list_0(t):
+    'positional_arg_list : empty'
+    t[0] = []
+
+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].append(t[3])
 
-def p_arg(t):
-    '''arg : ID
-           | INTLIT
-           | STRLIT
-           | CODELIT'''
+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.
 #
@@ -779,7 +865,7 @@ class Format:
         context.update(exportContext)
         context.update({ 'name': name, 'Name': string.capitalize(name) })
         try:
-            vars = self.func(self.user_code, context, *args)
+            vars = self.func(self.user_code, context, *args[0], **args[1])
         except Exception, exc:
             error(lineno, 'error defining "%s": %s.' % (name, exc))
         for k in vars.keys():
@@ -974,14 +1060,18 @@ class Template:
 #
 #####################################################################
 
-# Force the argument to be a list
-def makeList(list_or_item):
-    if not list_or_item:
+# Force the argument to be a list.  Useful for flags, where a caller
+# can specify a singleton flag or a list of flags.  Also usful for
+# 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 []
-    elif type(list_or_item) == ListType:
-        return list_or_item
     else:
-        return [ list_or_item ]
+        return [ arg ]
 
 # generate operandSizeMap based on provided operandTypeMap:
 # basically generate equiv. C++ type and make is_signed flag
@@ -1253,7 +1343,7 @@ class NPCOperandTraits(OperandTraits):
 exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits',
                         'ControlRegOperandTraits', 'MemOperandTraits',
                         'NPCOperandTraits', 'InstObjParams', 'CodeBlock',
-                        're', 'string')
+                        'makeList', 're', 'string')
 
 exportContext = {}