summaryrefslogtreecommitdiff
path: root/arch/isa_parser.py
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2004-05-10 16:10:47 -0700
committerSteve Reinhardt <stever@eecs.umich.edu>2004-05-10 16:10:47 -0700
commit7cab07268ff6cf1b4ecb59c0e6a377f8bb1ea24a (patch)
tree11a637240b40b749d8e7e74ddffd46e22ebe152a /arch/isa_parser.py
parentd66ae60f6b32b05af4c8f1e3f73360478fe9663d (diff)
downloadgem5-7cab07268ff6cf1b4ecb59c0e6a377f8bb1ea24a.tar.xz
Do a better job of factoring out CPU model in ISA description.
(Still not perfect though.) arch/alpha/isa_desc: Do a better job of factoring out CPU model. (Still not perfect though.) Pull execute() methods out of class declarations into separate section of file, allowing (1) easier replication for different CPU models and (2) a path to putting them all in a separate file. Force all instruction execution context into a single model-dependent class (SimpleCPU itself for SimpleCPU, DynInst for FullCPU). arch/isa_parser.py: Do a better job of factoring out CPU model. (Still not perfect though.) Pull execute() methods out of class declarations into separate section of file, allowing (1) easier replication for different CPU models and (2) a path to putting them all in a separate file. Also restructure top level to allow parser to run under interactive interpreter session for easier debugging. cpu/exec_context.hh: Add a few new methods to clean up isa_desc. cpu/simple_cpu/simple_cpu.cc: cpu/static_inst.hh: StaticInst::execute no longer takes a CPU and an ExecContext, just a unified FooCPUExecContext. cpu/simple_cpu/simple_cpu.hh: Add methods to redirect calls to ExecContext so SimpleCPU can act as sole instruction execution context for itself. Typedef SimpleCPU to SimpleCPUExecContext. --HG-- extra : convert_revision : ecc445503bc585585da5663fe61796580e744da6
Diffstat (limited to 'arch/isa_parser.py')
-rwxr-xr-xarch/isa_parser.py186
1 files changed, 101 insertions, 85 deletions
diff --git a/arch/isa_parser.py b/arch/isa_parser.py
index 2e3c0df35..0ee9e2e2d 100755
--- a/arch/isa_parser.py
+++ b/arch/isa_parser.py
@@ -32,20 +32,10 @@ import os
import sys
import re
import string
+import traceback
# get type names
from types import *
-# Check arguments. Right now there are only two: the name of the ISA
-# description (input) file and the name of the C++ decoder (output) file.
-isa_desc_filename = sys.argv[1]
-decoder_filename = sys.argv[2]
-
-# Might as well suck the file in while we're here. This way if it's a
-# bad filename we don't waste a lot of time building the parser :-).
-input = open(isa_desc_filename)
-isa_desc = input.read()
-input.close()
-
# Prepend the directory where the PLY lex & yacc modules are found
# to the search path. Assumes we're compiling in a subdirectory
# of 'build' in the current tree.
@@ -225,8 +215,8 @@ def p_specification(t):
isa_name = t[2]
namespace = isa_name + "Inst"
global_decls2 = t[3]
- (inst_decls, code) = t[4]
- code = indent(code)
+ (inst_decls, decode_code, exec_code) = t[4]
+ 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,
@@ -306,6 +296,8 @@ namespace %(namespace)s
%(inst_decls)s
+%(exec_code)s
+
} // namespace %(namespace)s
//////////////////////
@@ -316,7 +308,7 @@ StaticInstPtr<%(isa_name)s>
%(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
{
using namespace %(namespace)s;
-%(code)s
+%(decode_code)s
} // decodeInst
''' % vars()
output.close()
@@ -461,18 +453,19 @@ def p_param_1(t):
def p_decode_block(t):
'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
default_defaults = defaultStack.pop()
- (decls, code, has_default) = t[5]
+ (decls, decode_code, exec_code, has_default) = t[5]
# use the "default defaults" only if there was no explicit
# default statement in decode_stmt_list
if not has_default:
- (default_decls, default_code) = default_defaults
+ (default_decls, default_decode, default_exec) = default_defaults
decls += default_decls
- code += default_code
+ decode_code += default_decode
+ exec_code += default_exec
t[0] = (decls, '''
switch (%s) {
%s
}
-''' % (t[2], indent(code)))
+''' % (t[2], indent(decode_code)), exec_code)
# The opt_default statement serves only to push the "default defaults"
# onto defaultStack. This value will be used by nested decode blocks,
@@ -488,8 +481,8 @@ def p_opt_default_0(t):
def p_opt_default_1(t):
'opt_default : DEFAULT inst'
# push the new default
- (decls, code) = t[2]
- defaultStack.push((decls, '\ndefault:\n%sbreak;' % code))
+ (decls, decode_code, exec_code) = t[2]
+ defaultStack.push((decls, '\ndefault:\n%sbreak;' % decode_code, exec_code))
# no meaningful value returned
t[0] = None
@@ -499,12 +492,12 @@ def p_decode_stmt_list_0(t):
def p_decode_stmt_list_1(t):
'decode_stmt_list : decode_stmt decode_stmt_list'
- (decls1, code1, has_default1) = t[1]
- (decls2, code2, has_default2) = t[2]
+ (decls1, decode_code1, exec_code1, has_default1) = t[1]
+ (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')
- t[0] = (decls1 + '\n' + decls2, code1 + '\n' + code2,
- has_default1 or has_default2)
+ t[0] = (decls1 + '\n' + decls2, decode_code1 + '\n' + decode_code2,
+ exec_code1 + '\n' + exec_code2, has_default1 or has_default2)
#
# Decode statement rules
@@ -525,7 +518,7 @@ def p_decode_stmt_list_1(t):
# the other statements.
def p_decode_stmt_cpp(t):
'decode_stmt : CPPDIRECTIVE'
- t[0] = (t[1], t[1], 0)
+ t[0] = (t[1], t[1], t[1], 0)
# A format block 'format <foo> { ... }' sets the default instruction
# format used to handle instruction definitions inside the block.
@@ -555,17 +548,19 @@ def p_push_format_id(t):
def p_decode_stmt_decode(t):
'decode_stmt : case_label COLON decode_block'
(label, is_default) = t[1]
- (decls, code) = t[3]
+ (decls, decode_code, exec_code) = t[3]
# just wrap the decoding code from the block as a case in the
# outer switch statement.
- t[0] = (decls, '\n%s:\n%s' % (label, indent(code)), is_default)
+ t[0] = (decls, '\n%s:\n%s' % (label, indent(decode_code)),
+ exec_code, is_default)
# Instruction definition (finally!).
def p_decode_stmt_inst(t):
'decode_stmt : case_label COLON inst SEMI'
(label, is_default) = t[1]
- (decls, code) = t[3]
- t[0] = (decls, '\n%s:%sbreak;' % (label, indent(code)), is_default)
+ (decls, decode_code, exec_code) = t[3]
+ t[0] = (decls, '\n%s:%sbreak;' % (label, indent(decode_code)),
+ exec_code, is_default)
# The case label is either a list of one or more constants or 'default'
def p_case_label_0(t):
@@ -596,12 +591,13 @@ def p_inst_0(t):
'inst : ID LPAREN arg_list RPAREN'
# Pass the ID and arg list to the current format class to deal with.
currentFormat = formatStack.top()
- (decls, code) = currentFormat.defineInst(t[1], t[3], t.lineno(1))
+ (decls, decode_code, exec_code) = \
+ currentFormat.defineInst(t[1], t[3], t.lineno(1))
args = ','.join(map(str, t[3]))
args = re.sub('(?m)^', '//', args)
args = re.sub('^//', '', args)
comment = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
- t[0] = (comment + decls, comment + code)
+ t[0] = (comment + decls, comment + decode_code, comment + exec_code)
# Define an instruction using an explicitly specified format:
# "<fmt>::<mnemonic>(<args>)"
@@ -611,9 +607,10 @@ def p_inst_1(t):
format = formatMap[t[1]]
except KeyError:
error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
- (decls, code) = format.defineInst(t[3], t[5], t.lineno(1))
+ (decls, decode_code, exec_code) = \
+ format.defineInst(t[3], t[5], t.lineno(1))
comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5])
- t[0] = (comment + decls, comment + code)
+ t[0] = (comment + decls, comment + decode_code, comment + exec_code)
def p_arg_list_0(t):
'arg_list : empty'
@@ -673,7 +670,8 @@ class Format:
code = ' pass\n'
param_list = string.join(params, ", ")
f = 'def defInst(name, Name, ' + param_list + '):\n' + code
- exec(f)
+ c = compile(f, 'def format ' + id, 'exec')
+ exec(c)
self.func = defInst
def defineInst(self, name, args, lineno):
@@ -773,8 +771,9 @@ def error(lineno, string):
# Like error(), but include a Python stack backtrace (for processing
# Python exceptions).
def error_bt(lineno, string):
+ traceback.print_exc()
print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string)
- raise
+ sys.exit(1)
#####################################################################
@@ -944,7 +943,7 @@ class IntRegOperandTraits(OperandTraits):
(op_desc.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc, cpu_model):
+ def makeRead(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
if (type == 'float' or type == 'double'):
error(0, 'Attempt to read integer register as FP')
@@ -955,7 +954,7 @@ class IntRegOperandTraits(OperandTraits):
return '%s = bits(xc->readIntReg(_srcRegIdx[%d]), %d, 0);\n' % \
(op_desc.munged_name, op_desc.src_reg_idx, size-1)
- def makeWrite(self, op_desc, cpu_model):
+ def makeWrite(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
if (type == 'float' or type == 'double'):
error(0, 'Attempt to write integer register as FP')
@@ -988,7 +987,7 @@ class FloatRegOperandTraits(OperandTraits):
(op_desc.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc, cpu_model):
+ def makeRead(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
bit_select = 0
if (type == 'float'):
@@ -1007,7 +1006,7 @@ class FloatRegOperandTraits(OperandTraits):
else:
return '%s = %s;\n' % (op_desc.munged_name, base)
- def makeWrite(self, op_desc, cpu_model):
+ def makeWrite(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
final_val = op_desc.munged_name
if (type == 'float'):
@@ -1044,7 +1043,7 @@ class ControlRegOperandTraits(OperandTraits):
(op_desc.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc, cpu_model):
+ def makeRead(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
bit_select = 0
if (type == 'float' or type == 'double'):
@@ -1056,7 +1055,7 @@ class ControlRegOperandTraits(OperandTraits):
return '%s = bits(%s, %d, 0);\n' % \
(op_desc.munged_name, base, size-1)
- def makeWrite(self, op_desc, cpu_model):
+ def makeWrite(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
if (type == 'float' or type == 'double'):
error(0, 'Attempt to write control register as FP')
@@ -1087,16 +1086,16 @@ class MemOperandTraits(OperandTraits):
c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name
return c
- def makeRead(self, op_desc, cpu_model):
+ def makeRead(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
eff_type = 'uint%d_t' % size
- return 'fault = memAccessObj->read(EA, (%s&)%s, %s_flags);\n' \
+ return 'fault = xc->read(EA, (%s&)%s, %s_flags);\n' \
% (eff_type, op_desc.munged_name, op_desc.base_name)
- def makeWrite(self, op_desc, cpu_model):
+ def makeWrite(self, op_desc):
(size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
eff_type = 'uint%d_t' % size
- return 'fault = memAccessObj->write((%s&)%s, EA, %s_flags,' \
+ return 'fault = xc->write((%s&)%s, EA, %s_flags,' \
' &%s_write_result);\n' \
% (eff_type, op_desc.munged_name, op_desc.base_name,
op_desc.base_name)
@@ -1105,10 +1104,10 @@ class NPCOperandTraits(OperandTraits):
def makeConstructor(self, op_desc):
return ''
- def makeRead(self, op_desc, cpu_model):
+ def makeRead(self, op_desc):
return '%s = xc->readPC() + 4;\n' % op_desc.munged_name
- def makeWrite(self, op_desc, cpu_model):
+ def makeWrite(self, op_desc):
return 'xc->setNextPC(%s);\n' % op_desc.munged_name
@@ -1172,21 +1171,17 @@ class OperandDescriptor:
def finalize(self):
self.flags = self.traits.getFlags(self)
self.constructor = self.traits.makeConstructor(self)
- self.exec_decl = self.traits.makeDecl(self)
+ self.op_decl = self.traits.makeDecl(self)
if self.is_src:
- self.simple_rd = self.traits.makeRead(self, 'simple')
- self.dtld_rd = self.traits.makeRead(self, 'dtld')
+ self.op_rd = self.traits.makeRead(self)
else:
- self.simple_rd = ''
- self.dtld_rd = ''
+ self.op_rd = ''
if self.is_dest:
- self.simple_wb = self.traits.makeWrite(self, 'simple')
- self.dtld_wb = self.traits.makeWrite(self, 'dtld')
+ self.op_wb = self.traits.makeWrite(self)
else:
- self.simple_wb = ''
- self.dtld_wb = ''
+ self.op_wb = ''
class OperandDescriptorList:
def __init__(self):
@@ -1348,32 +1343,21 @@ class CodeBlock:
self.constructor += \
'\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs
- self.exec_decl = self.operands.concatAttrStrings('exec_decl')
+ self.op_decl = self.operands.concatAttrStrings('op_decl')
is_mem = lambda op: op.traits.isMem()
not_mem = lambda op: not op.traits.isMem()
- self.simple_rd = self.operands.concatAttrStrings('simple_rd')
- self.simple_wb = self.operands.concatAttrStrings('simple_wb')
- self.simple_mem_rd = \
- self.operands.concatSomeAttrStrings(is_mem, 'simple_rd')
- self.simple_mem_wb = \
- self.operands.concatSomeAttrStrings(is_mem, 'simple_wb')
- self.simple_nonmem_rd = \
- self.operands.concatSomeAttrStrings(not_mem, 'simple_rd')
- self.simple_nonmem_wb = \
- self.operands.concatSomeAttrStrings(not_mem, 'simple_wb')
-
- self.dtld_rd = self.operands.concatAttrStrings('dtld_rd')
- self.dtld_wb = self.operands.concatAttrStrings('dtld_wb')
- self.dtld_mem_rd = \
- self.operands.concatSomeAttrStrings(is_mem, 'dtld_rd')
- self.dtld_mem_wb = \
- self.operands.concatSomeAttrStrings(is_mem, 'dtld_wb')
- self.dtld_nonmem_rd = \
- self.operands.concatSomeAttrStrings(not_mem, 'dtld_rd')
- self.dtld_nonmem_wb = \
- self.operands.concatSomeAttrStrings(not_mem, 'dtld_wb')
+ self.op_rd = self.operands.concatAttrStrings('op_rd')
+ self.op_wb = self.operands.concatAttrStrings('op_wb')
+ self.op_mem_rd = \
+ self.operands.concatSomeAttrStrings(is_mem, 'op_rd')
+ self.op_mem_wb = \
+ self.operands.concatSomeAttrStrings(is_mem, 'op_wb')
+ self.op_nonmem_rd = \
+ self.operands.concatSomeAttrStrings(not_mem, 'op_rd')
+ self.op_nonmem_wb = \
+ self.operands.concatSomeAttrStrings(not_mem, 'op_wb')
self.flags = self.operands.concatAttrLists('flags')
@@ -1401,6 +1385,10 @@ class InstObjParams:
self.mnemonic = mnem
self.class_name = class_name
self.base_class = base_class
+ self.exec_func_declarations = '''
+ Fault execute(SimpleCPUExecContext *, Trace::InstRecord *);
+ Fault execute(FullCPUExecContext *, Trace::InstRecord *);
+'''
if code_block:
for code_attr in code_block.__dict__.keys():
setattr(self, code_attr, getattr(code_block, code_attr))
@@ -1431,20 +1419,48 @@ class InstObjParams:
else:
self.fp_enable_check = ''
+ def _subst(self, template):
+ try:
+ return template % self.__dict__
+ except KeyError, key:
+ raise KeyError, 'InstObjParams.subst: no definition for %s' % key
+
def subst(self, *args):
result = []
for t in args:
- if not templateMap.has_key(t):
+ try: template = templateMap[t]
+ except KeyError:
error(0, 'InstObjParams::subst: undefined template "%s"' % t)
- try:
- result.append(templateMap[t] % self.__dict__)
- except KeyError, key:
- error(0, 'InstObjParams::subst: no definition for "%s"' % key)
+ if template.find('%(cpu_model)') != -1:
+ tmp = ''
+ for cpu_model in ('SimpleCPUExecContext', 'FullCPUExecContext'):
+ self.cpu_model = cpu_model
+ tmp += self._subst(template)
+ result.append(tmp)
+ else:
+ result.append(self._subst(template))
if len(args) == 1:
result = result[0]
return result
#
-# All set... read in and parse the ISA description.
+# Read in and parse the ISA description.
#
-yacc.parse(isa_desc)
+def parse_isa_desc(isa_desc_file, decoder_file):
+ # Arguments are the name of the ISA description (input) file and
+ # the name of the C++ decoder (output) file.
+ global isa_desc_filename, decoder_filename
+ isa_desc_filename = isa_desc_file
+ decoder_filename = decoder_file
+
+ # Suck the ISA description file in.
+ input = open(isa_desc_filename)
+ isa_desc = input.read()
+ input.close()
+
+ # Parse it.
+ yacc.parse(isa_desc)
+
+# Called as script: get args from command line.
+if __name__ == '__main__':
+ parse_isa_desc(sys.argv[1], sys.argv[2])