comparison cpu_dsl.py @ 1749:e4fe5a450d05

Added option to CPU DSL to produce a threaded interpreter using computed goto
author Michael Pavone <pavone@retrodev.com>
date Fri, 08 Feb 2019 23:09:58 -0800
parents 48a43dff4dc0
children 01236179fc71
comparison
equal deleted inserted replaced
1748:48a43dff4dc0 1749:e4fe5a450d05
128 for var in self.locals: 128 for var in self.locals:
129 output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)) 129 output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var))
130 self.newLocals = [] 130 self.newLocals = []
131 fieldVals,_ = self.getFieldVals(value) 131 fieldVals,_ = self.getFieldVals(value)
132 self.processOps(prog, fieldVals, output, otype, self.implementation) 132 self.processOps(prog, fieldVals, output, otype, self.implementation)
133 begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{' 133
134 if prog.dispatch == 'call':
135 begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{'
136 elif prog.dispatch == 'goto':
137 begin = '\n' + self.generateName(value) + ': {'
138 else:
139 raise Exception('Unsupported dispatch type ' + prog.dispatch)
134 if prog.needFlagCoalesce: 140 if prog.needFlagCoalesce:
135 begin += prog.flags.coalesceFlags(prog, otype) 141 begin += prog.flags.coalesceFlags(prog, otype)
136 if prog.needFlagDisperse: 142 if prog.needFlagDisperse:
137 output.append(prog.flags.disperseFlags(prog, otype)) 143 output.append(prog.flags.disperseFlags(prog, otype))
138 for var in self.newLocals: 144 for var in self.newLocals:
139 begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var) 145 begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)
140 prog.popScope() 146 prog.popScope()
147 if prog.dispatch == 'goto':
148 output += prog.nextInstruction(otype)
141 return begin + ''.join(output) + '\n}' 149 return begin + ''.join(output) + '\n}'
142 150
143 def __str__(self): 151 def __str__(self):
144 pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)] 152 pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)]
145 for name in self.locals: 153 for name in self.locals:
325 def _dispatchCImpl(prog, params): 333 def _dispatchCImpl(prog, params):
326 if len(params) == 1: 334 if len(params) == 1:
327 table = 'main' 335 table = 'main'
328 else: 336 else:
329 table = params[1] 337 table = params[1]
330 return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0]) 338 if prog.dispatch == 'call':
339 return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0])
340 elif prog.dispatch == 'goto':
341 return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0])
342 else:
343 raise Exception('Unsupported dispatch type ' + prog.dispatch)
331 344
332 def _updateFlagsCImpl(prog, params, rawParams): 345 def _updateFlagsCImpl(prog, params, rawParams):
333 autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0]) 346 autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0])
334 output = [] 347 output = []
335 parity = None 348 parity = None
1313 hFile.write('\n' + decl) 1326 hFile.write('\n' + decl)
1314 hFile.write('\n#endif //{0}_'.format(macro)) 1327 hFile.write('\n#endif //{0}_'.format(macro))
1315 hFile.write('\n') 1328 hFile.write('\n')
1316 hFile.close() 1329 hFile.close()
1317 1330
1318 def _buildTable(self, otype, table, body): 1331 def _buildTable(self, otype, table, body, lateBody):
1319 pieces = [] 1332 pieces = []
1320 opmap = [None] * (1 << self.opsize) 1333 opmap = [None] * (1 << self.opsize)
1321 bodymap = {} 1334 bodymap = {}
1322 if table in self.instructions: 1335 if table in self.instructions:
1323 instructions = self.instructions[table] 1336 instructions = self.instructions[table]
1331 self.needFlagDisperse = False 1344 self.needFlagDisperse = False
1332 self.lastOp = None 1345 self.lastOp = None
1333 opmap[val] = inst.generateName(val) 1346 opmap[val] = inst.generateName(val)
1334 bodymap[val] = inst.generateBody(val, self, otype) 1347 bodymap[val] = inst.generateBody(val, self, otype)
1335 1348
1336 pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) 1349 if self.dispatch == 'call':
1337 for inst in range(0, len(opmap)): 1350 pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
1338 op = opmap[inst] 1351 for inst in range(0, len(opmap)):
1339 if op is None: 1352 op = opmap[inst]
1340 pieces.append('\n\tunimplemented,') 1353 if op is None:
1341 else: 1354 pieces.append('\n\tunimplemented,')
1342 pieces.append('\n\t' + op + ',') 1355 else:
1343 body.append(bodymap[inst]) 1356 pieces.append('\n\t' + op + ',')
1344 pieces.append('\n};') 1357 body.append(bodymap[inst])
1358 pieces.append('\n};')
1359 elif self.dispatch == 'goto':
1360 body.append('\n\tstatic void *impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
1361 for inst in range(0, len(opmap)):
1362 op = opmap[inst]
1363 if op is None:
1364 body.append('\n\t\t&&unimplemented,')
1365 else:
1366 body.append('\n\t\t&&' + op + ',')
1367 lateBody.append(bodymap[inst])
1368 body.append('\n\t};')
1369 else:
1370 raise Exception("unimplmeneted dispatch type " + self.dispatch)
1345 body.extend(pieces) 1371 body.extend(pieces)
1372
1373 def nextInstruction(self, otype):
1374 output = []
1375 if self.dispatch == 'goto':
1376 output.append('\n\tif (context->cycles >= target_cycle) { return; }')
1377 self.meta = {}
1378 self.temp = {}
1379 self.subroutines[self.body].inline(self, [], output, otype, None)
1380 return output
1346 1381
1347 def build(self, otype): 1382 def build(self, otype):
1348 body = [] 1383 body = []
1349 pieces = [] 1384 pieces = []
1350 for include in self.includes: 1385 for include in self.includes:
1351 body.append('#include "{0}"\n'.format(include)) 1386 body.append('#include "{0}"\n'.format(include))
1352 body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix)) 1387 if self.dispatch == 'call':
1353 body.append('\n{') 1388 body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix))
1354 body.append('\n\tfatal_error("Unimplemented instruction\\n");') 1389 body.append('\n{')
1355 body.append('\n}\n') 1390 body.append('\n\tfatal_error("Unimplemented instruction\\n");')
1356 body.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix)) 1391 body.append('\n}\n')
1392 body.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix))
1393 for table in self.extra_tables:
1394 body.append('\nstatic impl_fun impl_{name}[{sz}];'.format(name = table, sz=(1 << self.opsize)))
1395 body.append('\nstatic impl_fun impl_main[{sz}];'.format(sz=(1 << self.opsize)))
1396 elif self.dispatch == 'goto':
1397 body.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
1398 body.append('\n{')
1399
1357 for table in self.extra_tables: 1400 for table in self.extra_tables:
1358 body.append('\nstatic impl_fun impl_{name}[{sz}];'.format(name = table, sz=(1 << self.opsize))) 1401 self._buildTable(otype, table, body, pieces)
1359 body.append('\nstatic impl_fun impl_main[{sz}];'.format(sz=(1 << self.opsize))) 1402 self._buildTable(otype, 'main', body, pieces)
1360 for table in self.extra_tables: 1403 if self.dispatch == 'call' and self.body in self.subroutines:
1361 self._buildTable(otype, table, body)
1362 self._buildTable(otype, 'main', body)
1363 if self.body in self.subroutines:
1364 pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type)) 1404 pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
1365 pieces.append('\n{') 1405 pieces.append('\n{')
1366 pieces.append('\n\twhile (context->cycles < target_cycle)') 1406 pieces.append('\n\twhile (context->cycles < target_cycle)')
1367 pieces.append('\n\t{') 1407 pieces.append('\n\t{')
1368 self.meta = {} 1408 self.meta = {}
1369 self.temp = {} 1409 self.temp = {}
1370 self.subroutines[self.body].inline(self, [], pieces, otype, None) 1410 self.subroutines[self.body].inline(self, [], pieces, otype, None)
1371 pieces.append('\n\t}') 1411 pieces.append('\n\t}')
1412 pieces.append('\n}')
1413 elif self.dispatch == 'goto':
1414 body += self.nextInstruction(otype)
1415 pieces.append('\nunimplemented:')
1416 pieces.append('\n\tfatal_error("Unimplemented instruction\\n");')
1372 pieces.append('\n}') 1417 pieces.append('\n}')
1373 return ''.join(body) + ''.join(pieces) 1418 return ''.join(body) + ''.join(pieces)
1374 1419
1375 def checkBool(self, name): 1420 def checkBool(self, name):
1376 if not name in self.booleans: 1421 if not name in self.booleans:
1487 return ret 1532 return ret
1488 1533
1489 def getRootScope(self): 1534 def getRootScope(self):
1490 return self.scopes[0] 1535 return self.scopes[0]
1491 1536
1492 def parse(f): 1537 def parse(args):
1538 f = args.source
1493 instructions = {} 1539 instructions = {}
1494 subroutines = {} 1540 subroutines = {}
1495 registers = None 1541 registers = None
1496 flags = None 1542 flags = None
1497 declares = [] 1543 declares = []
1575 subroutines[cur_object.name] = cur_object 1621 subroutines[cur_object.name] = cur_object
1576 if errors: 1622 if errors:
1577 print(errors) 1623 print(errors)
1578 else: 1624 else:
1579 p = Program(registers, instructions, subroutines, info, flags) 1625 p = Program(registers, instructions, subroutines, info, flags)
1626 p.dispatch = args.dispatch
1580 p.declares = declares 1627 p.declares = declares
1581 p.booleans['dynarec'] = False 1628 p.booleans['dynarec'] = False
1582 p.booleans['interp'] = True 1629 p.booleans['interp'] = True
1630 if args.define:
1631 for define in args.define:
1632 name,sep,val = define.partition('=')
1633 name = name.strip()
1634 val = val.strip()
1635 if sep:
1636 p.booleans[name] = bool(val)
1637 else:
1638 p.booleans[name] = True
1583 1639
1584 if 'header' in info: 1640 if 'header' in info:
1585 print('#include "{0}"'.format(info['header'][0])) 1641 print('#include "{0}"'.format(info['header'][0]))
1586 p.writeHeader('c', info['header'][0]) 1642 p.writeHeader('c', info['header'][0])
1587 print('#include "util.h"') 1643 print('#include "util.h"')
1588 print('#include <stdlib.h>') 1644 print('#include <stdlib.h>')
1589 print(p.build('c')) 1645 print(p.build('c'))
1590 1646
1591 def main(argv): 1647 def main(argv):
1592 f = open(argv[1]) 1648 from argparse import ArgumentParser, FileType
1593 parse(f) 1649 argParser = ArgumentParser(description='CPU emulator DSL compiler')
1650 argParser.add_argument('source', type=FileType('r'))
1651 argParser.add_argument('-D', '--define', action='append')
1652 argParser.add_argument('-d', '--dispatch', choices=('call', 'switch', 'goto'), default='call')
1653 parse(argParser.parse_args(argv[1:]))
1594 1654
1595 if __name__ == '__main__': 1655 if __name__ == '__main__':
1596 from sys import argv 1656 from sys import argv
1597 main(argv) 1657 main(argv)