+ def __getitem__(self, i): # Allow object (self) to be
+ return getattr(self, i) # passed to %-substitutions
+
+ # Change the file suffix of a base filename:
+ # (e.g.) decoder.cc -> decoder-g.cc.inc for 'global' outputs
+ def suffixize(self, s, sec):
+ extn = re.compile('(\.[^\.]+)$') # isolate extension
+ if self.namespace:
+ return extn.sub(r'-ns\1.inc', s) # insert some text on either side
+ else:
+ return extn.sub(r'-g\1.inc', s)
+
+ # Get the file object for emitting code into the specified section
+ # (header, decoder, exec, decode_block).
+ def get_file(self, section):
+ if section == 'decode_block':
+ filename = 'decode-method.cc.inc'
+ else:
+ if section == 'header':
+ file = 'decoder.hh'
+ else:
+ file = '%s.cc' % section
+ filename = self.suffixize(file, section)
+ try:
+ return self.files[filename]
+ except KeyError: pass
+
+ f = self.open(filename)
+ self.files[filename] = f
+
+ # The splittable files are the ones with many independent
+ # per-instruction functions - the decoder's instruction constructors
+ # and the instruction execution (execute()) methods. These both have
+ # the suffix -ns.cc.inc, meaning they are within the namespace part
+ # of the ISA, contain object-emitting C++ source, and are included
+ # into other top-level files. These are the files that need special
+ # #define's to allow parts of them to be compiled separately. Rather
+ # than splitting the emissions into separate files, the monolithic
+ # output of the ISA parser is maintained, but the value (or lack
+ # thereof) of the __SPLIT definition during C preprocessing will
+ # select the different chunks. If no 'split' directives are used,
+ # the cpp emissions have no effect.
+ if re.search('-ns.cc.inc$', filename):
+ print >>f, '#if !defined(__SPLIT) || (__SPLIT == 1)'
+ self.splits[f] = 1
+ # ensure requisite #include's
+ elif filename in ['decoder-g.cc.inc', 'exec-g.cc.inc']:
+ print >>f, '#include "decoder.hh"'
+ elif filename == 'decoder-g.hh.inc':
+ print >>f, '#include "base/bitfield.hh"'
+
+ return f
+
+ # Weave together the parts of the different output sections by
+ # #include'ing them into some very short top-level .cc/.hh files.
+ # These small files make it much clearer how this tool works, since
+ # you directly see the chunks emitted as files that are #include'd.
+ def write_top_level_files(self):
+ dep = self.open('inc.d', bare=True)
+
+ # decoder header - everything depends on this
+ file = 'decoder.hh'
+ with self.open(file) as f:
+ inc = []
+
+ fn = 'decoder-g.hh.inc'
+ assert(fn in self.files)
+ f.write('#include "%s"\n' % fn)
+ inc.append(fn)
+
+ fn = 'decoder-ns.hh.inc'
+ assert(fn in self.files)
+ f.write('namespace %s {\n#include "%s"\n}\n'
+ % (self.namespace, fn))
+ inc.append(fn)
+
+ print >>dep, file+':', ' '.join(inc)
+
+ # decoder method - cannot be split
+ file = 'decoder.cc'
+ with self.open(file) as f:
+ inc = []
+
+ fn = 'decoder-g.cc.inc'
+ assert(fn in self.files)
+ f.write('#include "%s"\n' % fn)
+ inc.append(fn)
+
+ fn = 'decode-method.cc.inc'
+ # is guaranteed to have been written for parse to complete
+ f.write('#include "%s"\n' % fn)
+ inc.append(fn)
+
+ inc.append("decoder.hh")
+ print >>dep, file+':', ' '.join(inc)
+
+ extn = re.compile('(\.[^\.]+)$')
+
+ # instruction constructors
+ splits = self.splits[self.get_file('decoder')]
+ file_ = 'inst-constrs.cc'
+ for i in range(1, splits+1):
+ if splits > 1:
+ file = extn.sub(r'-%d\1' % i, file_)
+ else:
+ file = file_
+ with self.open(file) as f:
+ inc = []
+
+ fn = 'decoder-g.cc.inc'
+ assert(fn in self.files)
+ f.write('#include "%s"\n' % fn)
+ inc.append(fn)
+
+ fn = 'decoder-ns.cc.inc'
+ assert(fn in self.files)
+ print >>f, 'namespace %s {' % self.namespace
+ if splits > 1:
+ print >>f, '#define __SPLIT %u' % i
+ print >>f, '#include "%s"' % fn
+ print >>f, '}'
+ inc.append(fn)
+
+ inc.append("decoder.hh")
+ print >>dep, file+':', ' '.join(inc)
+
+ # instruction execution per-CPU model
+ splits = self.splits[self.get_file('exec')]
+ for cpu in self.cpuModels:
+ for i in range(1, splits+1):
+ if splits > 1:
+ file = extn.sub(r'_%d\1' % i, cpu.filename)
+ else:
+ file = cpu.filename
+ with self.open(file) as f:
+ inc = []
+
+ fn = 'exec-g.cc.inc'
+ assert(fn in self.files)
+ f.write('#include "%s"\n' % fn)
+ inc.append(fn)
+
+ f.write(cpu.includes+"\n")
+
+ fn = 'exec-ns.cc.inc'
+ assert(fn in self.files)
+ print >>f, 'namespace %s {' % self.namespace
+ print >>f, '#define CPU_EXEC_CONTEXT %s' \
+ % cpu.strings['CPU_exec_context']
+ if splits > 1:
+ print >>f, '#define __SPLIT %u' % i
+ print >>f, '#include "%s"' % fn
+ print >>f, '}'
+ inc.append(fn)
+
+ inc.append("decoder.hh")
+ print >>dep, file+':', ' '.join(inc)
+
+ # max_inst_regs.hh
+ self.update('max_inst_regs.hh',
+ '''namespace %(namespace)s {
+ const int MaxInstSrcRegs = %(maxInstSrcRegs)d;
+ const int MaxInstDestRegs = %(maxInstDestRegs)d;
+ const int MaxMiscDestRegs = %(maxMiscDestRegs)d;\n}\n''' % self)
+ print >>dep, 'max_inst_regs.hh:'
+
+ dep.close()
+
+
+ scaremonger_template ='''// DO NOT EDIT
+// This file was automatically generated from an ISA description:
+// %(filename)s
+
+''';
+