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]) |