isa_parser.py (10170:7e7cd19c9d9e) isa_parser.py (10196:be0e1724eb39)
1# Copyright (c) 2003-2005 The Regents of The University of Michigan
2# Copyright (c) 2013 Advanced Micro Devices, Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;

--- 13 unchanged lines hidden (view full) ---

22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28# Authors: Steve Reinhardt
29
1# Copyright (c) 2003-2005 The Regents of The University of Michigan
2# Copyright (c) 2013 Advanced Micro Devices, Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;

--- 13 unchanged lines hidden (view full) ---

22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28# Authors: Steve Reinhardt
29
30from __future__ import with_statement
30import os
31import sys
32import re
33import string
34import inspect, traceback
35# get type names
36from types import *
37

--- 270 unchanged lines hidden (view full) ---

308 # dictionary. For all other output types they get collapsed into
309 # a single string.
310 def __init__(self, parser,
311 header_output = '', decoder_output = '', exec_output = '',
312 decode_block = '', has_decode_default = False):
313 self.parser = parser
314 self.header_output = parser.expandCpuSymbolsToString(header_output)
315 self.decoder_output = parser.expandCpuSymbolsToString(decoder_output)
31import os
32import sys
33import re
34import string
35import inspect, traceback
36# get type names
37from types import *
38

--- 270 unchanged lines hidden (view full) ---

309 # dictionary. For all other output types they get collapsed into
310 # a single string.
311 def __init__(self, parser,
312 header_output = '', decoder_output = '', exec_output = '',
313 decode_block = '', has_decode_default = False):
314 self.parser = parser
315 self.header_output = parser.expandCpuSymbolsToString(header_output)
316 self.decoder_output = parser.expandCpuSymbolsToString(decoder_output)
316 if isinstance(exec_output, dict):
317 self.exec_output = exec_output
318 elif isinstance(exec_output, str):
319 # If the exec_output arg is a single string, we replicate
320 # it for each of the CPU models, substituting and
321 # %(CPU_foo)s params appropriately.
322 self.exec_output = parser.expandCpuSymbolsToDict(exec_output)
323 self.decode_block = parser.expandCpuSymbolsToString(decode_block)
317 self.exec_output = exec_output
318 self.decode_block = decode_block
324 self.has_decode_default = has_decode_default
325
319 self.has_decode_default = has_decode_default
320
321 # Write these code chunks out to the filesystem. They will be properly
322 # interwoven by the write_top_level_files().
323 def emit(self):
324 if self.header_output:
325 self.parser.get_file('header').write(self.header_output)
326 if self.decoder_output:
327 self.parser.get_file('decoder').write(self.decoder_output)
328 if self.exec_output:
329 self.parser.get_file('exec').write(self.exec_output)
330 if self.decode_block:
331 self.parser.get_file('decode_block').write(self.decode_block)
332
326 # Override '+' operator: generate a new GenCode object that
327 # concatenates all the individual strings in the operands.
328 def __add__(self, other):
333 # Override '+' operator: generate a new GenCode object that
334 # concatenates all the individual strings in the operands.
335 def __add__(self, other):
329 exec_output = {}
330 for cpu in self.parser.cpuModels:
331 n = cpu.name
332 exec_output[n] = self.exec_output[n] + other.exec_output[n]
333 return GenCode(self.parser,
334 self.header_output + other.header_output,
335 self.decoder_output + other.decoder_output,
336 return GenCode(self.parser,
337 self.header_output + other.header_output,
338 self.decoder_output + other.decoder_output,
336 exec_output,
339 self.exec_output + other.exec_output,
337 self.decode_block + other.decode_block,
338 self.has_decode_default or other.has_decode_default)
339
340 # Prepend a string (typically a comment) to all the strings.
341 def prepend_all(self, pre):
342 self.header_output = pre + self.header_output
343 self.decoder_output = pre + self.decoder_output
344 self.decode_block = pre + self.decode_block
340 self.decode_block + other.decode_block,
341 self.has_decode_default or other.has_decode_default)
342
343 # Prepend a string (typically a comment) to all the strings.
344 def prepend_all(self, pre):
345 self.header_output = pre + self.header_output
346 self.decoder_output = pre + self.decoder_output
347 self.decode_block = pre + self.decode_block
345 for cpu in self.parser.cpuModels:
346 self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]
348 self.exec_output = pre + self.exec_output
347
348 # Wrap the decode block in a pair of strings (e.g., 'case foo:'
349 # and 'break;'). Used to build the big nested switch statement.
350 def wrap_decode_block(self, pre, post = ''):
351 self.decode_block = pre + indent(self.decode_block) + post
352
353#####################################################################
354#

--- 811 unchanged lines hidden (view full) ---

1166 def push(self, item):
1167 self.append(item);
1168
1169 def top(self):
1170 return self[-1]
1171
1172#######################
1173#
349
350 # Wrap the decode block in a pair of strings (e.g., 'case foo:'
351 # and 'break;'). Used to build the big nested switch statement.
352 def wrap_decode_block(self, pre, post = ''):
353 self.decode_block = pre + indent(self.decode_block) + post
354
355#####################################################################
356#

--- 811 unchanged lines hidden (view full) ---

1168 def push(self, item):
1169 self.append(item);
1170
1171 def top(self):
1172 return self[-1]
1173
1174#######################
1175#
1174# Output file template
1176# ISA Parser
1177# parses ISA DSL and emits C++ headers and source
1175#
1176
1178#
1179
1177file_template = '''
1178/*
1179 * DO NOT EDIT THIS FILE!!!
1180 *
1181 * It was automatically generated from the ISA description in %(filename)s
1182 */
1183
1184%(includes)s
1185
1186%(global_output)s
1187
1188namespace %(namespace)s {
1189
1190%(namespace_output)s
1191
1192} // namespace %(namespace)s
1193
1194%(decode_function)s
1195'''
1196
1197max_inst_regs_template = '''
1198/*
1199 * DO NOT EDIT THIS FILE!!!
1200 *
1201 * It was automatically generated from the ISA description in %(filename)s
1202 */
1203
1204namespace %(namespace)s {
1205
1206 const int MaxInstSrcRegs = %(MaxInstSrcRegs)d;
1207 const int MaxInstDestRegs = %(MaxInstDestRegs)d;
1208 const int MaxMiscDestRegs = %(MaxMiscDestRegs)d;
1209
1210} // namespace %(namespace)s
1211
1212'''
1213
1214class ISAParser(Grammar):
1215 def __init__(self, output_dir, cpu_models):
1216 super(ISAParser, self).__init__()
1217 self.output_dir = output_dir
1218
1180class ISAParser(Grammar):
1181 def __init__(self, output_dir, cpu_models):
1182 super(ISAParser, self).__init__()
1183 self.output_dir = output_dir
1184
1185 self.filename = None # for output file watermarking/scaremongering
1186
1219 self.cpuModels = cpu_models
1220
1221 # variable to hold templates
1222 self.templateMap = {}
1223
1224 # This dictionary maps format name strings to Format objects.
1225 self.formatMap = {}
1226
1187 self.cpuModels = cpu_models
1188
1189 # variable to hold templates
1190 self.templateMap = {}
1191
1192 # This dictionary maps format name strings to Format objects.
1193 self.formatMap = {}
1194
1195 # Track open files and, if applicable, how many chunks it has been
1196 # split into so far.
1197 self.files = {}
1198 self.splits = {}
1199
1200 # isa_name / namespace identifier from namespace declaration.
1201 # before the namespace declaration, None.
1202 self.isa_name = None
1203 self.namespace = None
1204
1227 # The format stack.
1228 self.formatStack = Stack(NoFormat())
1229
1230 # The default case stack.
1231 self.defaultStack = Stack(None)
1232
1233 # Stack that tracks current file and line number. Each
1234 # element is a tuple (filename, lineno) that records the
1235 # *current* filename and the line number in the *previous*
1236 # file where it was included.
1237 self.fileNameStack = Stack()
1238
1239 symbols = ('makeList', 're', 'string')
1240 self.exportContext = dict([(s, eval(s)) for s in symbols])
1241
1242 self.maxInstSrcRegs = 0
1243 self.maxInstDestRegs = 0
1244 self.maxMiscDestRegs = 0
1245
1205 # The format stack.
1206 self.formatStack = Stack(NoFormat())
1207
1208 # The default case stack.
1209 self.defaultStack = Stack(None)
1210
1211 # Stack that tracks current file and line number. Each
1212 # element is a tuple (filename, lineno) that records the
1213 # *current* filename and the line number in the *previous*
1214 # file where it was included.
1215 self.fileNameStack = Stack()
1216
1217 symbols = ('makeList', 're', 'string')
1218 self.exportContext = dict([(s, eval(s)) for s in symbols])
1219
1220 self.maxInstSrcRegs = 0
1221 self.maxInstDestRegs = 0
1222 self.maxMiscDestRegs = 0
1223
1224 def __getitem__(self, i): # Allow object (self) to be
1225 return getattr(self, i) # passed to %-substitutions
1226
1227 # Change the file suffix of a base filename:
1228 # (e.g.) decoder.cc -> decoder-g.cc.inc for 'global' outputs
1229 def suffixize(self, s, sec):
1230 extn = re.compile('(\.[^\.]+)$') # isolate extension
1231 if self.namespace:
1232 return extn.sub(r'-ns\1.inc', s) # insert some text on either side
1233 else:
1234 return extn.sub(r'-g\1.inc', s)
1235
1236 # Get the file object for emitting code into the specified section
1237 # (header, decoder, exec, decode_block).
1238 def get_file(self, section):
1239 if section == 'decode_block':
1240 filename = 'decode-method.cc.inc'
1241 else:
1242 if section == 'header':
1243 file = 'decoder.hh'
1244 else:
1245 file = '%s.cc' % section
1246 filename = self.suffixize(file, section)
1247 try:
1248 return self.files[filename]
1249 except KeyError: pass
1250
1251 f = self.open(filename)
1252 self.files[filename] = f
1253
1254 # The splittable files are the ones with many independent
1255 # per-instruction functions - the decoder's instruction constructors
1256 # and the instruction execution (execute()) methods. These both have
1257 # the suffix -ns.cc.inc, meaning they are within the namespace part
1258 # of the ISA, contain object-emitting C++ source, and are included
1259 # into other top-level files. These are the files that need special
1260 # #define's to allow parts of them to be compiled separately. Rather
1261 # than splitting the emissions into separate files, the monolithic
1262 # output of the ISA parser is maintained, but the value (or lack
1263 # thereof) of the __SPLIT definition during C preprocessing will
1264 # select the different chunks. If no 'split' directives are used,
1265 # the cpp emissions have no effect.
1266 if re.search('-ns.cc.inc$', filename):
1267 print >>f, '#if !defined(__SPLIT) || (__SPLIT == 1)'
1268 self.splits[f] = 1
1269 # ensure requisite #include's
1270 elif filename in ['decoder-g.cc.inc', 'exec-g.cc.inc']:
1271 print >>f, '#include "decoder.hh"'
1272 elif filename == 'decoder-g.hh.inc':
1273 print >>f, '#include "base/bitfield.hh"'
1274
1275 return f
1276
1277 # Weave together the parts of the different output sections by
1278 # #include'ing them into some very short top-level .cc/.hh files.
1279 # These small files make it much clearer how this tool works, since
1280 # you directly see the chunks emitted as files that are #include'd.
1281 def write_top_level_files(self):
1282 dep = self.open('inc.d', bare=True)
1283
1284 # decoder header - everything depends on this
1285 file = 'decoder.hh'
1286 with self.open(file) as f:
1287 inc = []
1288
1289 fn = 'decoder-g.hh.inc'
1290 assert(fn in self.files)
1291 f.write('#include "%s"\n' % fn)
1292 inc.append(fn)
1293
1294 fn = 'decoder-ns.hh.inc'
1295 assert(fn in self.files)
1296 f.write('namespace %s {\n#include "%s"\n}\n'
1297 % (self.namespace, fn))
1298 inc.append(fn)
1299
1300 print >>dep, file+':', ' '.join(inc)
1301
1302 # decoder method - cannot be split
1303 file = 'decoder.cc'
1304 with self.open(file) as f:
1305 inc = []
1306
1307 fn = 'decoder-g.cc.inc'
1308 assert(fn in self.files)
1309 f.write('#include "%s"\n' % fn)
1310 inc.append(fn)
1311
1312 fn = 'decode-method.cc.inc'
1313 # is guaranteed to have been written for parse to complete
1314 f.write('#include "%s"\n' % fn)
1315 inc.append(fn)
1316
1317 inc.append("decoder.hh")
1318 print >>dep, file+':', ' '.join(inc)
1319
1320 extn = re.compile('(\.[^\.]+)$')
1321
1322 # instruction constructors
1323 splits = self.splits[self.get_file('decoder')]
1324 file_ = 'inst-constrs.cc'
1325 for i in range(1, splits+1):
1326 if splits > 1:
1327 file = extn.sub(r'-%d\1' % i, file_)
1328 else:
1329 file = file_
1330 with self.open(file) as f:
1331 inc = []
1332
1333 fn = 'decoder-g.cc.inc'
1334 assert(fn in self.files)
1335 f.write('#include "%s"\n' % fn)
1336 inc.append(fn)
1337
1338 fn = 'decoder-ns.cc.inc'
1339 assert(fn in self.files)
1340 print >>f, 'namespace %s {' % self.namespace
1341 if splits > 1:
1342 print >>f, '#define __SPLIT %u' % i
1343 print >>f, '#include "%s"' % fn
1344 print >>f, '}'
1345 inc.append(fn)
1346
1347 inc.append("decoder.hh")
1348 print >>dep, file+':', ' '.join(inc)
1349
1350 # instruction execution per-CPU model
1351 splits = self.splits[self.get_file('exec')]
1352 for cpu in self.cpuModels:
1353 for i in range(1, splits+1):
1354 if splits > 1:
1355 file = extn.sub(r'_%d\1' % i, cpu.filename)
1356 else:
1357 file = cpu.filename
1358 with self.open(file) as f:
1359 inc = []
1360
1361 fn = 'exec-g.cc.inc'
1362 assert(fn in self.files)
1363 f.write('#include "%s"\n' % fn)
1364 inc.append(fn)
1365
1366 f.write(cpu.includes+"\n")
1367
1368 fn = 'exec-ns.cc.inc'
1369 assert(fn in self.files)
1370 print >>f, 'namespace %s {' % self.namespace
1371 print >>f, '#define CPU_EXEC_CONTEXT %s' \
1372 % cpu.strings['CPU_exec_context']
1373 if splits > 1:
1374 print >>f, '#define __SPLIT %u' % i
1375 print >>f, '#include "%s"' % fn
1376 print >>f, '}'
1377 inc.append(fn)
1378
1379 inc.append("decoder.hh")
1380 print >>dep, file+':', ' '.join(inc)
1381
1382 # max_inst_regs.hh
1383 self.update('max_inst_regs.hh',
1384 '''namespace %(namespace)s {
1385 const int MaxInstSrcRegs = %(maxInstSrcRegs)d;
1386 const int MaxInstDestRegs = %(maxInstDestRegs)d;
1387 const int MaxMiscDestRegs = %(maxMiscDestRegs)d;\n}\n''' % self)
1388 print >>dep, 'max_inst_regs.hh:'
1389
1390 dep.close()
1391
1392
1393 scaremonger_template ='''// DO NOT EDIT
1394// This file was automatically generated from an ISA description:
1395// %(filename)s
1396
1397''';
1398
1246 #####################################################################
1247 #
1248 # Lexer
1249 #
1250 # The PLY lexer module takes two things as input:
1251 # - A list of token names (the string list 'tokens')
1252 # - A regular expression describing a match for each token. The
1253 # regexp for token FOO can be provided in two ways:

--- 5 unchanged lines hidden (view full) ---

1259 #####################################################################
1260
1261 # Reserved words. These are listed separately as they are matched
1262 # using the same regexp as generic IDs, but distinguished in the
1263 # t_ID() function. The PLY documentation suggests this approach.
1264 reserved = (
1265 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT',
1266 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS',
1399 #####################################################################
1400 #
1401 # Lexer
1402 #
1403 # The PLY lexer module takes two things as input:
1404 # - A list of token names (the string list 'tokens')
1405 # - A regular expression describing a match for each token. The
1406 # regexp for token FOO can be provided in two ways:

--- 5 unchanged lines hidden (view full) ---

1412 #####################################################################
1413
1414 # Reserved words. These are listed separately as they are matched
1415 # using the same regexp as generic IDs, but distinguished in the
1416 # t_ID() function. The PLY documentation suggests this approach.
1417 reserved = (
1418 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT',
1419 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS',
1267 'OUTPUT', 'SIGNED', 'TEMPLATE'
1420 'OUTPUT', 'SIGNED', 'SPLIT', 'TEMPLATE'
1268 )
1269
1270 # List of tokens. The lex module requires this.
1271 tokens = reserved + (
1272 # identifier
1273 'ID',
1274
1275 # integer literal

--- 136 unchanged lines hidden (view full) ---

1412 # The LHS of the first grammar rule is used as the start symbol
1413 # (in this case, 'specification'). Note that this rule enforces
1414 # that there will be exactly one namespace declaration, with 0 or
1415 # more global defs/decls before and after it. The defs & decls
1416 # before the namespace decl will be outside the namespace; those
1417 # after will be inside. The decoder function is always inside the
1418 # namespace.
1419 def p_specification(self, t):
1421 )
1422
1423 # List of tokens. The lex module requires this.
1424 tokens = reserved + (
1425 # identifier
1426 'ID',
1427
1428 # integer literal

--- 136 unchanged lines hidden (view full) ---

1565 # The LHS of the first grammar rule is used as the start symbol
1566 # (in this case, 'specification'). Note that this rule enforces
1567 # that there will be exactly one namespace declaration, with 0 or
1568 # more global defs/decls before and after it. The defs & decls
1569 # before the namespace decl will be outside the namespace; those
1570 # after will be inside. The decoder function is always inside the
1571 # namespace.
1572 def p_specification(self, t):
1420 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block'
1421 global_code = t[1]
1422 isa_name = t[2]
1423 namespace = isa_name + "Inst"
1424 # wrap the decode block as a function definition
1425 t[4].wrap_decode_block('''
1426StaticInstPtr
1427%(isa_name)s::Decoder::decodeInst(%(isa_name)s::ExtMachInst machInst)
1428{
1429 using namespace %(namespace)s;
1430''' % vars(), '}')
1431 # both the latter output blocks and the decode block are in
1432 # the namespace
1433 namespace_code = t[3] + t[4]
1434 # pass it all back to the caller of yacc.parse()
1435 t[0] = (isa_name, namespace, global_code, namespace_code)
1573 'specification : opt_defs_and_outputs top_level_decode_block'
1436
1574
1437 # ISA name declaration looks like "namespace <foo>;"
1438 def p_name_decl(self, t):
1439 'name_decl : NAMESPACE ID SEMI'
1440 t[0] = t[2]
1575 for f in self.splits.iterkeys():
1576 f.write('\n#endif\n')
1441
1577
1442 # 'opt_defs_and_outputs' is a possibly empty sequence of
1443 # def and/or output statements.
1578 for f in self.files.itervalues(): # close ALL the files;
1579 f.close() # not doing so can cause compilation to fail
1580
1581 self.write_top_level_files()
1582
1583 t[0] = True
1584
1585 # 'opt_defs_and_outputs' is a possibly empty sequence of def and/or
1586 # output statements. Its productions do the hard work of eventually
1587 # instantiating a GenCode, which are generally emitted (written to disk)
1588 # as soon as possible, except for the decode_block, which has to be
1589 # accumulated into one large function of nested switch/case blocks.
1444 def p_opt_defs_and_outputs_0(self, t):
1445 'opt_defs_and_outputs : empty'
1590 def p_opt_defs_and_outputs_0(self, t):
1591 'opt_defs_and_outputs : empty'
1446 t[0] = GenCode(self)
1447
1448 def p_opt_defs_and_outputs_1(self, t):
1449 'opt_defs_and_outputs : defs_and_outputs'
1592
1593 def p_opt_defs_and_outputs_1(self, t):
1594 'opt_defs_and_outputs : defs_and_outputs'
1450 t[0] = t[1]
1451
1452 def p_defs_and_outputs_0(self, t):
1453 'defs_and_outputs : def_or_output'
1595
1596 def p_defs_and_outputs_0(self, t):
1597 'defs_and_outputs : def_or_output'
1454 t[0] = t[1]
1455
1456 def p_defs_and_outputs_1(self, t):
1457 'defs_and_outputs : defs_and_outputs def_or_output'
1598
1599 def p_defs_and_outputs_1(self, t):
1600 'defs_and_outputs : defs_and_outputs def_or_output'
1458 t[0] = t[1] + t[2]
1459
1460 # The list of possible definition/output statements.
1601
1602 # The list of possible definition/output statements.
1603 # They are all processed as they are seen.
1461 def p_def_or_output(self, t):
1604 def p_def_or_output(self, t):
1462 '''def_or_output : def_format
1605 '''def_or_output : name_decl
1606 | def_format
1463 | def_bitfield
1464 | def_bitfield_struct
1465 | def_template
1466 | def_operand_types
1467 | def_operands
1607 | def_bitfield
1608 | def_bitfield_struct
1609 | def_template
1610 | def_operand_types
1611 | def_operands
1468 | output_header
1469 | output_decoder
1470 | output_exec
1471 | global_let'''
1612 | output
1613 | global_let
1614 | split'''
1615
1616 # Utility function used by both invocations of splitting - explicit
1617 # 'split' keyword and split() function inside "let {{ }};" blocks.
1618 def split(self, sec, write=False):
1619 assert(sec != 'header' and "header cannot be split")
1620
1621 f = self.get_file(sec)
1622 self.splits[f] += 1
1623 s = '\n#endif\n#if __SPLIT == %u\n' % self.splits[f]
1624 if write:
1625 f.write(s)
1626 else:
1627 return s
1628
1629 # split output file to reduce compilation time
1630 def p_split(self, t):
1631 'split : SPLIT output_type SEMI'
1632 assert(self.isa_name and "'split' not allowed before namespace decl")
1633
1634 self.split(t[2], True)
1635
1636 def p_output_type(self, t):
1637 '''output_type : DECODER
1638 | HEADER
1639 | EXEC'''
1472 t[0] = t[1]
1473
1640 t[0] = t[1]
1641
1642 # ISA name declaration looks like "namespace <foo>;"
1643 def p_name_decl(self, t):
1644 'name_decl : NAMESPACE ID SEMI'
1645 assert(self.isa_name == None and "Only 1 namespace decl permitted")
1646 self.isa_name = t[2]
1647 self.namespace = t[2] + 'Inst'
1648
1474 # Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
1475 # directly to the appropriate output section.
1476
1477 # Massage output block by substituting in template definitions and
1478 # bit operators. We handle '%'s embedded in the string that don't
1479 # indicate template substitutions (or CPU-specific symbols, which
1480 # get handled in GenCode) by doubling them first so that the
1481 # format operation will reduce them back to single '%'s.
1482 def process_output(self, s):
1483 s = self.protectNonSubstPercents(s)
1484 # protects cpu-specific symbols too
1485 s = self.protectCpuSymbols(s)
1486 return substBitOps(s % self.templateMap)
1487
1649 # Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
1650 # directly to the appropriate output section.
1651
1652 # Massage output block by substituting in template definitions and
1653 # bit operators. We handle '%'s embedded in the string that don't
1654 # indicate template substitutions (or CPU-specific symbols, which
1655 # get handled in GenCode) by doubling them first so that the
1656 # format operation will reduce them back to single '%'s.
1657 def process_output(self, s):
1658 s = self.protectNonSubstPercents(s)
1659 # protects cpu-specific symbols too
1660 s = self.protectCpuSymbols(s)
1661 return substBitOps(s % self.templateMap)
1662
1488 def p_output_header(self, t):
1489 'output_header : OUTPUT HEADER CODELIT SEMI'
1490 t[0] = GenCode(self, header_output = self.process_output(t[3]))
1663 def p_output(self, t):
1664 'output : OUTPUT output_type CODELIT SEMI'
1665 kwargs = { t[2]+'_output' : self.process_output(t[3]) }
1666 GenCode(self, **kwargs).emit()
1491
1667
1492 def p_output_decoder(self, t):
1493 'output_decoder : OUTPUT DECODER CODELIT SEMI'
1494 t[0] = GenCode(self, decoder_output = self.process_output(t[3]))
1495
1496 def p_output_exec(self, t):
1497 'output_exec : OUTPUT EXEC CODELIT SEMI'
1498 t[0] = GenCode(self, exec_output = self.process_output(t[3]))
1499
1500 # global let blocks 'let {{...}}' (Python code blocks) are
1501 # executed directly when seen. Note that these execute in a
1502 # special variable context 'exportContext' to prevent the code
1503 # from polluting this script's namespace.
1504 def p_global_let(self, t):
1505 'global_let : LET CODELIT SEMI'
1668 # global let blocks 'let {{...}}' (Python code blocks) are
1669 # executed directly when seen. Note that these execute in a
1670 # special variable context 'exportContext' to prevent the code
1671 # from polluting this script's namespace.
1672 def p_global_let(self, t):
1673 'global_let : LET CODELIT SEMI'
1674 def _split(sec):
1675 return self.split(sec)
1506 self.updateExportContext()
1507 self.exportContext["header_output"] = ''
1508 self.exportContext["decoder_output"] = ''
1509 self.exportContext["exec_output"] = ''
1510 self.exportContext["decode_block"] = ''
1676 self.updateExportContext()
1677 self.exportContext["header_output"] = ''
1678 self.exportContext["decoder_output"] = ''
1679 self.exportContext["exec_output"] = ''
1680 self.exportContext["decode_block"] = ''
1681 self.exportContext["split"] = _split
1682 split_setup = '''
1683def wrap(func):
1684 def split(sec):
1685 globals()[sec + '_output'] += func(sec)
1686 return split
1687split = wrap(split)
1688del wrap
1689'''
1690 # This tricky setup (immediately above) allows us to just write
1691 # (e.g.) "split('exec')" in the Python code and the split #ifdef's
1692 # will automatically be added to the exec_output variable. The inner
1693 # Python execution environment doesn't know about the split points,
1694 # so we carefully inject and wrap a closure that can retrieve the
1695 # next split's #define from the parser and add it to the current
1696 # emission-in-progress.
1511 try:
1697 try:
1512 exec fixPythonIndentation(t[2]) in self.exportContext
1698 exec split_setup+fixPythonIndentation(t[2]) in self.exportContext
1513 except Exception, exc:
1514 if debug:
1515 raise
1516 error(t, 'error: %s in global let block "%s".' % (exc, t[2]))
1699 except Exception, exc:
1700 if debug:
1701 raise
1702 error(t, 'error: %s in global let block "%s".' % (exc, t[2]))
1517 t[0] = GenCode(self,
1518 header_output=self.exportContext["header_output"],
1519 decoder_output=self.exportContext["decoder_output"],
1520 exec_output=self.exportContext["exec_output"],
1521 decode_block=self.exportContext["decode_block"])
1703 GenCode(self,
1704 header_output=self.exportContext["header_output"],
1705 decoder_output=self.exportContext["decoder_output"],
1706 exec_output=self.exportContext["exec_output"],
1707 decode_block=self.exportContext["decode_block"]).emit()
1522
1523 # Define the mapping from operand type extensions to C++ types and
1524 # bit widths (stored in operandTypeMap).
1525 def p_def_operand_types(self, t):
1526 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI'
1527 try:
1528 self.operandTypeMap = eval('{' + t[3] + '}')
1529 except Exception, exc:
1530 if debug:
1531 raise
1532 error(t,
1533 'error: %s in def operand_types block "%s".' % (exc, t[3]))
1708
1709 # Define the mapping from operand type extensions to C++ types and
1710 # bit widths (stored in operandTypeMap).
1711 def p_def_operand_types(self, t):
1712 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI'
1713 try:
1714 self.operandTypeMap = eval('{' + t[3] + '}')
1715 except Exception, exc:
1716 if debug:
1717 raise
1718 error(t,
1719 'error: %s in def operand_types block "%s".' % (exc, t[3]))
1534 t[0] = GenCode(self) # contributes nothing to the output C++ file
1535
1536 # Define the mapping from operand names to operand classes and
1537 # other traits. Stored in operandNameMap.
1538 def p_def_operands(self, t):
1539 'def_operands : DEF OPERANDS CODELIT SEMI'
1540 if not hasattr(self, 'operandTypeMap'):
1541 error(t, 'error: operand types must be defined before operands')
1542 try:
1543 user_dict = eval('{' + t[3] + '}', self.exportContext)
1544 except Exception, exc:
1545 if debug:
1546 raise
1547 error(t, 'error: %s in def operands block "%s".' % (exc, t[3]))
1548 self.buildOperandNameMap(user_dict, t.lexer.lineno)
1720
1721 # Define the mapping from operand names to operand classes and
1722 # other traits. Stored in operandNameMap.
1723 def p_def_operands(self, t):
1724 'def_operands : DEF OPERANDS CODELIT SEMI'
1725 if not hasattr(self, 'operandTypeMap'):
1726 error(t, 'error: operand types must be defined before operands')
1727 try:
1728 user_dict = eval('{' + t[3] + '}', self.exportContext)
1729 except Exception, exc:
1730 if debug:
1731 raise
1732 error(t, 'error: %s in def operands block "%s".' % (exc, t[3]))
1733 self.buildOperandNameMap(user_dict, t.lexer.lineno)
1549 t[0] = GenCode(self) # contributes nothing to the output C++ file
1550
1551 # A bitfield definition looks like:
1552 # 'def [signed] bitfield <ID> [<first>:<last>]'
1553 # This generates a preprocessor macro in the output file.
1554 def p_def_bitfield_0(self, t):
1555 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI'
1556 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
1557 if (t[2] == 'signed'):
1558 expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
1559 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1734
1735 # A bitfield definition looks like:
1736 # 'def [signed] bitfield <ID> [<first>:<last>]'
1737 # This generates a preprocessor macro in the output file.
1738 def p_def_bitfield_0(self, t):
1739 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI'
1740 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
1741 if (t[2] == 'signed'):
1742 expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
1743 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1560 t[0] = GenCode(self, header_output=hash_define)
1744 GenCode(self, header_output=hash_define).emit()
1561
1562 # alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]'
1563 def p_def_bitfield_1(self, t):
1564 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI'
1565 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
1566 if (t[2] == 'signed'):
1567 expr = 'sext<%d>(%s)' % (1, expr)
1568 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1745
1746 # alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]'
1747 def p_def_bitfield_1(self, t):
1748 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI'
1749 expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
1750 if (t[2] == 'signed'):
1751 expr = 'sext<%d>(%s)' % (1, expr)
1752 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1569 t[0] = GenCode(self, header_output=hash_define)
1753 GenCode(self, header_output=hash_define).emit()
1570
1571 # alternate form for structure member: 'def bitfield <ID> <ID>'
1572 def p_def_bitfield_struct(self, t):
1573 'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
1574 if (t[2] != ''):
1575 error(t, 'error: structure bitfields are always unsigned.')
1576 expr = 'machInst.%s' % t[5]
1577 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1754
1755 # alternate form for structure member: 'def bitfield <ID> <ID>'
1756 def p_def_bitfield_struct(self, t):
1757 'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
1758 if (t[2] != ''):
1759 error(t, 'error: structure bitfields are always unsigned.')
1760 expr = 'machInst.%s' % t[5]
1761 hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
1578 t[0] = GenCode(self, header_output=hash_define)
1762 GenCode(self, header_output=hash_define).emit()
1579
1580 def p_id_with_dot_0(self, t):
1581 'id_with_dot : ID'
1582 t[0] = t[1]
1583
1584 def p_id_with_dot_1(self, t):
1585 'id_with_dot : ID DOT id_with_dot'
1586 t[0] = t[1] + t[2] + t[3]
1587
1588 def p_opt_signed_0(self, t):
1589 'opt_signed : SIGNED'
1590 t[0] = t[1]
1591
1592 def p_opt_signed_1(self, t):
1593 'opt_signed : empty'
1594 t[0] = ''
1595
1596 def p_def_template(self, t):
1597 'def_template : DEF TEMPLATE ID CODELIT SEMI'
1763
1764 def p_id_with_dot_0(self, t):
1765 'id_with_dot : ID'
1766 t[0] = t[1]
1767
1768 def p_id_with_dot_1(self, t):
1769 'id_with_dot : ID DOT id_with_dot'
1770 t[0] = t[1] + t[2] + t[3]
1771
1772 def p_opt_signed_0(self, t):
1773 'opt_signed : SIGNED'
1774 t[0] = t[1]
1775
1776 def p_opt_signed_1(self, t):
1777 'opt_signed : empty'
1778 t[0] = ''
1779
1780 def p_def_template(self, t):
1781 'def_template : DEF TEMPLATE ID CODELIT SEMI'
1782 if t[3] in self.templateMap:
1783 print "warning: template %s already defined" % t[3]
1598 self.templateMap[t[3]] = Template(self, t[4])
1784 self.templateMap[t[3]] = Template(self, t[4])
1599 t[0] = GenCode(self)
1600
1601 # An instruction format definition looks like
1602 # "def format <fmt>(<params>) {{...}};"
1603 def p_def_format(self, t):
1604 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
1605 (id, params, code) = (t[3], t[5], t[7])
1606 self.defFormat(id, params, code, t.lexer.lineno)
1785
1786 # An instruction format definition looks like
1787 # "def format <fmt>(<params>) {{...}};"
1788 def p_def_format(self, t):
1789 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
1790 (id, params, code) = (t[3], t[5], t[7])
1791 self.defFormat(id, params, code, t.lexer.lineno)
1607 t[0] = GenCode(self)
1608
1609 # The formal parameter list for an instruction format is a
1610 # possibly empty list of comma-separated parameters. Positional
1611 # (standard, non-keyword) parameters must come first, followed by
1612 # keyword parameters, followed by a '*foo' parameter that gets
1613 # excess positional arguments (as in Python). Each of these three
1614 # parameter categories is optional.
1615 #

--- 54 unchanged lines hidden (view full) ---

1670
1671 # End of format definition-related rules.
1672 ##############
1673
1674 #
1675 # A decode block looks like:
1676 # decode <field1> [, <field2>]* [default <inst>] { ... }
1677 #
1792
1793 # The formal parameter list for an instruction format is a
1794 # possibly empty list of comma-separated parameters. Positional
1795 # (standard, non-keyword) parameters must come first, followed by
1796 # keyword parameters, followed by a '*foo' parameter that gets
1797 # excess positional arguments (as in Python). Each of these three
1798 # parameter categories is optional.
1799 #

--- 54 unchanged lines hidden (view full) ---

1854
1855 # End of format definition-related rules.
1856 ##############
1857
1858 #
1859 # A decode block looks like:
1860 # decode <field1> [, <field2>]* [default <inst>] { ... }
1861 #
1862 def p_top_level_decode_block(self, t):
1863 'top_level_decode_block : decode_block'
1864 codeObj = t[1]
1865 codeObj.wrap_decode_block('''
1866StaticInstPtr
1867%(isa_name)s::Decoder::decodeInst(%(isa_name)s::ExtMachInst machInst)
1868{
1869 using namespace %(namespace)s;
1870''' % self, '}')
1871
1872 codeObj.emit()
1873
1678 def p_decode_block(self, t):
1679 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
1680 default_defaults = self.defaultStack.pop()
1681 codeObj = t[5]
1682 # use the "default defaults" only if there was no explicit
1683 # default statement in decode_stmt_list
1684 if not codeObj.has_decode_default:
1685 codeObj += default_defaults

--- 398 unchanged lines hidden (view full) ---

2084
2085 def mungeSnippet(self, s):
2086 '''Fix up code snippets for final substitution in templates.'''
2087 if isinstance(s, str):
2088 return self.substMungedOpNames(substBitOps(s))
2089 else:
2090 return s
2091
1874 def p_decode_block(self, t):
1875 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
1876 default_defaults = self.defaultStack.pop()
1877 codeObj = t[5]
1878 # use the "default defaults" only if there was no explicit
1879 # default statement in decode_stmt_list
1880 if not codeObj.has_decode_default:
1881 codeObj += default_defaults

--- 398 unchanged lines hidden (view full) ---

2280
2281 def mungeSnippet(self, s):
2282 '''Fix up code snippets for final substitution in templates.'''
2283 if isinstance(s, str):
2284 return self.substMungedOpNames(substBitOps(s))
2285 else:
2286 return s
2287
2288 def open(self, name, bare=False):
2289 '''Open the output file for writing and include scary warning.'''
2290 filename = os.path.join(self.output_dir, name)
2291 f = open(filename, 'w')
2292 if f:
2293 if not bare:
2294 f.write(ISAParser.scaremonger_template % self)
2295 return f
2296
2092 def update(self, file, contents):
2297 def update(self, file, contents):
2093 '''Update the output file. If the contents are unchanged,
2094 the scons hash feature will avoid recompilation.'''
2095 file = os.path.join(self.output_dir, file)
2096 f = open(file, 'w')
2298 '''Update the output file only. Scons should handle the case when
2299 the new contents are unchanged using its built-in hash feature.'''
2300 f = self.open(file)
2097 f.write(contents)
2098 f.close()
2099
2100 # This regular expression matches '##include' directives
2101 includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[^"]*)".*$',
2102 re.MULTILINE)
2103
2104 def replace_include(self, matchobj, dirname):

--- 23 unchanged lines hidden (view full) ---

2128 # Find any includes and include them
2129 def replace(matchobj):
2130 return self.replace_include(matchobj, current_dir)
2131 contents = self.includeRE.sub(replace, contents)
2132
2133 self.fileNameStack.pop()
2134 return contents
2135
2301 f.write(contents)
2302 f.close()
2303
2304 # This regular expression matches '##include' directives
2305 includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[^"]*)".*$',
2306 re.MULTILINE)
2307
2308 def replace_include(self, matchobj, dirname):

--- 23 unchanged lines hidden (view full) ---

2332 # Find any includes and include them
2333 def replace(matchobj):
2334 return self.replace_include(matchobj, current_dir)
2335 contents = self.includeRE.sub(replace, contents)
2336
2337 self.fileNameStack.pop()
2338 return contents
2339
2340 AlreadyGenerated = {}
2341
2136 def _parse_isa_desc(self, isa_desc_file):
2137 '''Read in and parse the ISA description.'''
2138
2342 def _parse_isa_desc(self, isa_desc_file):
2343 '''Read in and parse the ISA description.'''
2344
2345 # The build system can end up running the ISA parser twice: once to
2346 # finalize the build dependencies, and then to actually generate
2347 # the files it expects (in src/arch/$ARCH/generated). This code
2348 # doesn't do anything different either time, however; the SCons
2349 # invocations just expect different things. Since this code runs
2350 # within SCons, we can just remember that we've already run and
2351 # not perform a completely unnecessary run, since the ISA parser's
2352 # effect is idempotent.
2353 if isa_desc_file in ISAParser.AlreadyGenerated:
2354 return
2355
2356 # grab the last three path components of isa_desc_file
2357 self.filename = '/'.join(isa_desc_file.split('/')[-3:])
2358
2139 # Read file and (recursively) all included files into a string.
2140 # PLY requires that the input be in a single string so we have to
2141 # do this up front.
2142 isa_desc = self.read_and_flatten(isa_desc_file)
2143
2144 # Initialize filename stack with outer file.
2145 self.fileNameStack.push((isa_desc_file, 0))
2146
2359 # Read file and (recursively) all included files into a string.
2360 # PLY requires that the input be in a single string so we have to
2361 # do this up front.
2362 isa_desc = self.read_and_flatten(isa_desc_file)
2363
2364 # Initialize filename stack with outer file.
2365 self.fileNameStack.push((isa_desc_file, 0))
2366
2147 # Parse it.
2148 (isa_name, namespace, global_code, namespace_code) = \
2149 self.parse_string(isa_desc)
2367 # Parse.
2368 self.parse_string(isa_desc)
2150
2369
2151 # grab the last three path components of isa_desc_file to put in
2152 # the output
2153 filename = '/'.join(isa_desc_file.split('/')[-3:])
2370 ISAParser.AlreadyGenerated[isa_desc_file] = None
2154
2371
2155 # generate decoder.hh
2156 includes = '#include "base/bitfield.hh" // for bitfield support'
2157 global_output = global_code.header_output
2158 namespace_output = namespace_code.header_output
2159 decode_function = ''
2160 self.update('decoder.hh', file_template % vars())
2161
2162 # generate decoder.cc
2163 includes = '#include "decoder.hh"'
2164 global_output = global_code.decoder_output
2165 namespace_output = namespace_code.decoder_output
2166 # namespace_output += namespace_code.decode_block
2167 decode_function = namespace_code.decode_block
2168 self.update('decoder.cc', file_template % vars())
2169
2170 # generate per-cpu exec files
2171 for cpu in self.cpuModels:
2172 includes = '#include "decoder.hh"\n'
2173 includes += cpu.includes
2174 global_output = global_code.exec_output[cpu.name]
2175 namespace_output = namespace_code.exec_output[cpu.name]
2176 decode_function = ''
2177 self.update(cpu.filename, file_template % vars())
2178
2179 # The variable names here are hacky, but this will creat local
2180 # variables which will be referenced in vars() which have the
2181 # value of the globals.
2182 MaxInstSrcRegs = self.maxInstSrcRegs
2183 MaxInstDestRegs = self.maxInstDestRegs
2184 MaxMiscDestRegs = self.maxMiscDestRegs
2185 # max_inst_regs.hh
2186 self.update('max_inst_regs.hh',
2187 max_inst_regs_template % vars())
2188
2189 def parse_isa_desc(self, *args, **kwargs):
2190 try:
2191 self._parse_isa_desc(*args, **kwargs)
2192 except ISAParserError, e:
2193 e.exit(self.fileNameStack)
2194
2195# Called as script: get args from command line.
2196# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models>
2197if __name__ == '__main__':
2198 execfile(sys.argv[1]) # read in CpuModel definitions
2199 cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]]
2200 ISAParser(sys.argv[3], cpu_models).parse_isa_desc(sys.argv[2])
2372 def parse_isa_desc(self, *args, **kwargs):
2373 try:
2374 self._parse_isa_desc(*args, **kwargs)
2375 except ISAParserError, e:
2376 e.exit(self.fileNameStack)
2377
2378# Called as script: get args from command line.
2379# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models>
2380if __name__ == '__main__':
2381 execfile(sys.argv[1]) # read in CpuModel definitions
2382 cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]]
2383 ISAParser(sys.argv[3], cpu_models).parse_isa_desc(sys.argv[2])