comparison cpu_dsl.py @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents ca158bc091f9
children 44d8c6e61ad4
comparison
equal deleted inserted replaced
1504:95b3a1a8b26c 1692:5dacaef602a7
1 #!/usr/bin/env python3
2
3
4 class Block:
5 def addOp(self, op):
6 pass
7
8 def processLine(self, parts):
9 if parts[0] == 'switch':
10 o = Switch(self, parts[1])
11 self.addOp(o)
12 return o
13 elif parts[0] == 'if':
14 o = If(self, parts[1])
15 self.addOp(o)
16 return o
17 elif parts[0] == 'end':
18 raise Exception('end is only allowed inside a switch or if block')
19 else:
20 self.addOp(NormalOp(parts))
21 return self
22
23 def resolveLocal(self, name):
24 return None
25
26 class ChildBlock(Block):
27 def processLine(self, parts):
28 if parts[0] == 'end':
29 return self.parent
30 return super().processLine(parts)
31
32 #Represents an instruction of the emulated CPU
33 class Instruction(Block):
34 def __init__(self, value, fields, name):
35 self.value = value
36 self.fields = fields
37 self.name = name
38 self.implementation = []
39 self.locals = {}
40 self.regValues = {}
41 self.varyingBits = 0
42 self.invalidFieldValues = {}
43 self.newLocals = []
44 for field in fields:
45 self.varyingBits += fields[field][1]
46
47 def addOp(self, op):
48 if op.op == 'local':
49 name = op.params[0]
50 size = op.params[1]
51 self.locals[name] = size
52 elif op.op == 'invalid':
53 name = op.params[0]
54 value = int(op.params[1])
55 self.invalidFieldValues.setdefault(name, set()).add(value)
56 else:
57 self.implementation.append(op)
58
59 def resolveLocal(self, name):
60 if name in self.locals:
61 return name
62 return None
63
64 def addLocal(self, name, size):
65 self.locals[name] = size
66 self.newLocals.append(name)
67
68 def localSize(self, name):
69 return self.locals.get(name)
70
71 def __lt__(self, other):
72 if isinstance(other, Instruction):
73 if self.varyingBits != other.varyingBits:
74 return self.varyingBits < other.varyingBits
75 return self.value < other.value
76 else:
77 return NotImplemented
78
79 def allValues(self):
80 values = []
81 for i in range(0, 1 << self.varyingBits):
82 iword = self.value
83 doIt = True
84 for field in self.fields:
85 shift,bits = self.fields[field]
86 val = i & ((1 << bits) - 1)
87 if field in self.invalidFieldValues and val in self.invalidFieldValues[field]:
88 doIt = False
89 break
90 i >>= bits
91 iword |= val << shift
92 if doIt:
93 values.append(iword)
94 return values
95
96 def getFieldVals(self, value):
97 fieldVals = {}
98 fieldBits = {}
99 for field in self.fields:
100 shift,bits = self.fields[field]
101 val = (value >> shift) & ((1 << bits) - 1)
102 fieldVals[field] = val
103 fieldBits[field] = bits
104 return (fieldVals, fieldBits)
105
106 def generateName(self, value):
107 fieldVals,fieldBits = self.getFieldVals(value)
108 names = list(fieldVals.keys())
109 names.sort()
110 funName = self.name
111 for name in names:
112 funName += '_{0}_{1:0>{2}}'.format(name, bin(fieldVals[name])[2:], fieldBits[name])
113 return funName
114
115 def generateBody(self, value, prog, otype):
116 output = []
117 prog.meta = {}
118 prog.pushScope(self)
119 self.regValues = {}
120 for var in self.locals:
121 output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var))
122 self.newLocals = []
123 fieldVals,_ = self.getFieldVals(value)
124 for op in self.implementation:
125 op.generate(prog, self, fieldVals, output, otype)
126 begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{'
127 if prog.needFlagCoalesce:
128 begin += prog.flags.coalesceFlags(prog, otype)
129 if prog.needFlagDisperse:
130 output.append(prog.flags.disperseFlags(prog, otype))
131 for var in self.newLocals:
132 begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)
133 prog.popScope()
134 return begin + ''.join(output) + '\n}'
135
136 def __str__(self):
137 pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)]
138 for name in self.locals:
139 pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
140 for op in self.implementation:
141 pieces.append(str(op))
142 return ''.join(pieces)
143
144 #Represents the definition of a helper function
145 class SubRoutine(Block):
146 def __init__(self, name):
147 self.name = name
148 self.implementation = []
149 self.args = []
150 self.arg_map = {}
151 self.locals = {}
152 self.regValues = {}
153
154 def addOp(self, op):
155 if op.op == 'arg':
156 name = op.params[0]
157 size = op.params[1]
158 self.arg_map[name] = len(self.args)
159 self.args.append((name, size))
160 elif op.op == 'local':
161 name = op.params[0]
162 size = op.params[1]
163 self.locals[name] = size
164 else:
165 self.implementation.append(op)
166
167 def resolveLocal(self, name):
168 if name in self.locals:
169 return self.name + '_' + name
170 return None
171
172 def addLocal(self, name, size):
173 self.locals[name] = size
174
175 def localSize(self, name):
176 return self.locals.get(name)
177
178 def inline(self, prog, params, output, otype, parent):
179 if len(params) != len(self.args):
180 raise Exception('{0} expects {1} arguments, but was called with {2}'.format(self.name, len(self.args), len(params)))
181 argValues = {}
182 if parent:
183 self.regValues = parent.regValues
184 prog.pushScope(self)
185 i = 0
186 for name,size in self.args:
187 argValues[name] = params[i]
188 i += 1
189 for name in self.locals:
190 size = self.locals[name]
191 output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name))
192 for op in self.implementation:
193 op.generate(prog, self, argValues, output, otype)
194 prog.popScope()
195
196 def __str__(self):
197 pieces = [self.name]
198 for name,size in self.args:
199 pieces.append('\n\targ {0} {1}'.format(name, size))
200 for name in self.locals:
201 pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
202 for op in self.implementation:
203 pieces.append(str(op))
204 return ''.join(pieces)
205
206 class Op:
207 def __init__(self, evalFun = None):
208 self.evalFun = evalFun
209 self.impls = {}
210 self.outOp = ()
211 def cBinaryOperator(self, op):
212 def _impl(prog, params):
213 if op == '-':
214 a = params[1]
215 b = params[0]
216 else:
217 a = params[0]
218 b = params[1]
219 return '\n\t{dst} = {a} {op} {b};'.format(
220 dst = params[2], a = a, b = b, op = op
221 )
222 self.impls['c'] = _impl
223 self.outOp = (2,)
224 return self
225 def cUnaryOperator(self, op):
226 def _impl(prog, params):
227 return '\n\t{dst} = {op}{a};'.format(
228 dst = params[1], a = params[0], op = op
229 )
230 self.impls['c'] = _impl
231 self.outOp = (1,)
232 return self
233 def addImplementation(self, lang, outOp, impl):
234 self.impls[lang] = impl
235 if not outOp is None:
236 if type(outOp) is tuple:
237 self.outOp = outOp
238 else:
239 self.outOp = (outOp,)
240 return self
241 def evaluate(self, params):
242 return self.evalFun(*params)
243 def canEval(self):
244 return not self.evalFun is None
245 def numArgs(self):
246 return self.evalFun.__code__.co_argcount
247 def generate(self, otype, prog, params, rawParams):
248 if self.impls[otype].__code__.co_argcount == 2:
249 return self.impls[otype](prog, params)
250 else:
251 return self.impls[otype](prog, params, rawParams)
252
253
254 def _xchgCImpl(prog, params, rawParams):
255 size = prog.paramSize(rawParams[0])
256 decl,name = prog.getTemp(size)
257 return decl + '\n\t{tmp} = {a};\n\t{a} = {b};\n\t{b} = {tmp};'.format(a = params[0], b = params[1], tmp = name)
258
259 def _dispatchCImpl(prog, params):
260 if len(params) == 1:
261 table = 'main'
262 else:
263 table = params[1]
264 return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0])
265
266 def _updateFlagsCImpl(prog, params, rawParams):
267 i = 0
268 last = ''
269 autoUpdate = set()
270 explicit = {}
271 for c in params[0]:
272 if c.isdigit():
273 if last.isalpha():
274 num = int(c)
275 if num > 1:
276 raise Exception(c + ' is not a valid digit for update_flags')
277 explicit[last] = num
278 last = c
279 else:
280 raise Exception('Digit must follow flag letter in update_flags')
281 else:
282 if last.isalpha():
283 autoUpdate.add(last)
284 last = c
285 if last.isalpha():
286 autoUpdate.add(last)
287 output = []
288 #TODO: handle autoUpdate flags
289 for flag in autoUpdate:
290 calc = prog.flags.flagCalc[flag]
291 calc,_,resultBit = calc.partition('-')
292 lastDst = prog.resolveParam(prog.lastDst, None, {})
293 storage = prog.flags.getStorage(flag)
294 if calc == 'bit' or calc == 'sign':
295 if calc == 'sign':
296 resultBit = prog.paramSize(prog.lastDst) - 1
297 else:
298 resultBit = int(resultBit)
299 if type(storage) is tuple:
300 reg,storageBit = storage
301 reg = prog.resolveParam(reg, None, {})
302 if storageBit == resultBit:
303 #TODO: optimize this case
304 output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format(
305 reg = reg, mask = 1 << resultBit, res = lastDst
306 ))
307 else:
308 if resultBit > storageBit:
309 op = '>>'
310 shift = resultBit - storageBit
311 else:
312 op = '<<'
313 shift = storageBit - resultBit
314 output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} {op} {shift}U & {mask}U);'.format(
315 reg = reg, mask = 1 << storageBit, res = lastDst, op = op, shift = shift
316 ))
317 else:
318 reg = prog.resolveParam(storage, None, {})
319 output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=lastDst, mask = 1 << resultBit))
320 elif calc == 'zero':
321 if type(storage) is tuple:
322 reg,storageBit = storage
323 reg = prog.resolveParam(reg, None, {})
324 output.append('\n\t{reg} = {res} ? ({reg} & {mask}U) : ({reg} | {bit}U);'.format(
325 reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit
326 ))
327 elif prog.paramSize(prog.lastDst) > prog.paramSize(storage):
328 reg = prog.resolveParam(storage, None, {})
329 output.append('\n\t{reg} = {res} != 0;'.format(
330 reg = reg, res = lastDst
331 ))
332 else:
333 reg = prog.resolveParam(storage, None, {})
334 output.append('\n\t{reg} = {res};'.format(reg = reg, res = lastDst))
335 elif calc == 'half-carry':
336 pass
337 elif calc == 'carry':
338 pass
339 elif calc == 'overflow':
340 pass
341 elif calc == 'parity':
342 pass
343 #TODO: combine explicit flags targeting the same storage location
344 for flag in explicit:
345 location = prog.flags.getStorage(flag)
346 if type(location) is tuple:
347 reg,bit = location
348 reg = prog.resolveReg(reg, None, {})
349 value = str(1 << bit)
350 if explicit[flag]:
351 operator = '|='
352 else:
353 operator = '&='
354 value = '~' + value
355 output.append('\n\t{reg} {op} {val};'.format(reg=reg, op=operator, val=value))
356 else:
357 reg = prog.resolveReg(location, None, {})
358 output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag]))
359 return ''.join(output)
360
361 def _cmpCImpl(prog, params):
362 size = prog.paramSize(params[1])
363 tmpvar = 'cmp_tmp{sz}__'.format(sz=size)
364 typename = ''
365 scope = prog.getRootScope()
366 if not scope.resolveLocal(tmpvar):
367 scope.addLocal(tmpvar, size)
368 prog.lastDst = tmpvar
369 return '\n\t{var} = {b} - {a};'.format(var = tmpvar, a = params[0], b = params[1])
370
371 def _asrCImpl(prog, params, rawParams):
372 shiftSize = prog.paramSize(rawParams[0])
373 mask = 1 << (shiftSize - 1)
374 return '\n\t{dst} = ({a} >> {b}) | ({a} & {mask});'.format(a = params[0], b = params[1], dst = params[2], mask = mask)
375
376 _opMap = {
377 'mov': Op(lambda val: val).cUnaryOperator(''),
378 'not': Op(lambda val: ~val).cUnaryOperator('~'),
379 'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'),
380 'neg': Op(lambda val: -val).cUnaryOperator('-'),
381 'add': Op(lambda a, b: a + b).cBinaryOperator('+'),
382 'sub': Op(lambda a, b: b - a).cBinaryOperator('-'),
383 'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'),
384 'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'),
385 'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl),
386 'and': Op(lambda a, b: a & b).cBinaryOperator('&'),
387 'or': Op(lambda a, b: a | b).cBinaryOperator('|'),
388 'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'),
389 'abs': Op(lambda val: abs(val)).addImplementation(
390 'c', 1, lambda prog, params: '\n\t{dst} = abs({src});'.format(dst=params[1], src=params[0])
391 ),
392 'cmp': Op().addImplementation('c', None, _cmpCImpl),
393 'ocall': Op().addImplementation('c', None, lambda prog, params: '\n\t{pre}{fun}({args});'.format(
394 pre = prog.prefix, fun = params[0], args = ', '.join(['context'] + [str(p) for p in params[1:]])
395 )),
396 'cycles': Op().addImplementation('c', None,
397 lambda prog, params: '\n\tcontext->cycles += context->opts->gen.clock_divider * {0};'.format(
398 params[0]
399 )
400 ),
401 'addsize': Op(
402 lambda a, b: b + (2 * a if a else 1)
403 ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} + {sz} ? {sz} * 2 : 1;'.format(
404 dst = params[2], sz = params[0], val = params[1]
405 )),
406 'decsize': Op(
407 lambda a, b: b - (2 * a if a else 1)
408 ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} - {sz} ? {sz} * 2 : 1;'.format(
409 dst = params[2], sz = params[0], val = params[1]
410 )),
411 'xchg': Op().addImplementation('c', (0,1), _xchgCImpl),
412 'dispatch': Op().addImplementation('c', None, _dispatchCImpl),
413 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl)
414 }
415
416 #represents a simple DSL instruction
417 class NormalOp:
418 def __init__(self, parts):
419 self.op = parts[0]
420 self.params = parts[1:]
421
422 def generate(self, prog, parent, fieldVals, output, otype):
423 procParams = []
424 allParamsConst = True
425 opDef = _opMap.get(self.op)
426 for param in self.params:
427 allowConst = (self.op in prog.subroutines or len(procParams) != len(self.params) - 1) and param in parent.regValues
428 isDst = (not opDef is None) and len(procParams) in opDef.outOp
429 param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst)
430
431 if (not type(param) is int) and len(procParams) != len(self.params) - 1:
432 allParamsConst = False
433 procParams.append(param)
434
435 if self.op == 'meta':
436 param,_,index = self.params[1].partition('.')
437 if index:
438 index = (parent.resolveLocal(index) or index)
439 if index in fieldVals:
440 index = str(fieldVals[index])
441 param = param + '.' + index
442 else:
443 param = parent.resolveLocal(param) or param
444 if param in fieldVals:
445 param = fieldVals[index]
446 prog.meta[self.params[0]] = param
447 elif self.op == 'dis':
448 #TODO: Disassembler
449 pass
450 elif not opDef is None:
451 if opDef.canEval() and allParamsConst:
452 #do constant folding
453 if opDef.numArgs() >= len(procParams):
454 raise Exception('Insufficient args for ' + self.op + ' (' + ', '.join(self.params) + ')')
455 dst = self.params[opDef.numArgs()]
456 result = opDef.evaluate(procParams[:opDef.numArgs()])
457 while dst in prog.meta:
458 dst = prog.meta[dst]
459 maybeLocal = parent.resolveLocal(dst)
460 if maybeLocal:
461 dst = maybeLocal
462 parent.regValues[dst] = result
463 if prog.isReg(dst):
464 output.append(_opMap['mov'].generate(otype, prog, procParams, self.params))
465 else:
466 output.append(opDef.generate(otype, prog, procParams, self.params))
467 elif self.op in prog.subroutines:
468 prog.subroutines[self.op].inline(prog, procParams, output, otype, parent)
469 else:
470 output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');')
471 prog.lastOp = self
472
473 def __str__(self):
474 return '\n\t' + self.op + ' ' + ' '.join(self.params)
475
476 #represents a DSL switch construct
477 class Switch(ChildBlock):
478 def __init__(self, parent, param):
479 self.op = 'switch'
480 self.parent = parent
481 self.param = param
482 self.cases = {}
483 self.regValues = None
484 self.current_locals = {}
485 self.case_locals = {}
486 self.current_case = None
487 self.default = None
488 self.default_locals = None
489
490 def addOp(self, op):
491 if op.op == 'case':
492 val = int(op.params[0], 16) if op.params[0].startswith('0x') else int(op.params[0])
493 self.cases[val] = self.current_case = []
494 self.case_locals[val] = self.current_locals = {}
495 elif op.op == 'default':
496 self.default = self.current_case = []
497 self.default_locals = self.current_locals = {}
498 elif self.current_case == None:
499 raise ion('Orphan instruction in switch')
500 elif op.op == 'local':
501 name = op.params[0]
502 size = op.params[1]
503 self.current_locals[name] = size
504 else:
505 self.current_case.append(op)
506
507 def resolveLocal(self, name):
508 if name in self.current_locals:
509 return name
510 return self.parent.resolveLocal(name)
511
512 def addLocal(self, name, size):
513 self.current_locals[name] = size
514
515 def localSize(self, name):
516 if name in self.current_locals:
517 return self.current_locals[name]
518 return self.parent.localSize(name)
519
520 def generate(self, prog, parent, fieldVals, output, otype):
521 prog.pushScope(self)
522 param = prog.resolveParam(self.param, parent, fieldVals)
523 if type(param) is int:
524 self.regValues = self.parent.regValues
525 if param in self.cases:
526 self.current_locals = self.case_locals[param]
527 output.append('\n\t{')
528 for local in self.case_locals[param]:
529 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local))
530 for op in self.cases[param]:
531 op.generate(prog, self, fieldVals, output, otype)
532 output.append('\n\t}')
533 elif self.default:
534 self.current_locals = self.default_locals
535 output.append('\n\t{')
536 for local in self.default_locals:
537 output.append('\n\tuint{0}_t {1};'.format(self.default[local], local))
538 for op in self.default:
539 op.generate(prog, self, fieldVals, output, otype)
540 output.append('\n\t}')
541 else:
542 output.append('\n\tswitch(' + param + ')')
543 output.append('\n\t{')
544 for case in self.cases:
545 self.current_locals = self.case_locals[case]
546 self.regValues = dict(self.parent.regValues)
547 output.append('\n\tcase {0}U: '.format(case) + '{')
548 for local in self.case_locals[case]:
549 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local))
550 for op in self.cases[case]:
551 op.generate(prog, self, fieldVals, output, otype)
552 output.append('\n\tbreak;')
553 output.append('\n\t}')
554 if self.default:
555 self.current_locals = self.default_locals
556 self.regValues = dict(self.parent.regValues)
557 output.append('\n\tdefault: {')
558 for local in self.default_locals:
559 output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local))
560 for op in self.default:
561 op.generate(prog, self, fieldVals, output, otype)
562 output.append('\n\t}')
563 prog.popScope()
564
565 def __str__(self):
566 keys = self.cases.keys()
567 keys.sort()
568 lines = ['\n\tswitch']
569 for case in keys:
570 lines.append('\n\tcase {0}'.format(case))
571 lines.append(''.join([str(op) for op in self.cases[case]]))
572 lines.append('\n\tend')
573 return ''.join(lines)
574
575
576 def _geuCImpl(prog, parent, fieldVals, output):
577 if prog.lastOp.op == 'cmp':
578 output.pop()
579 params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params]
580 return '\n\tif ({a} >= {b}) '.format(a=params[1], b = params[0]) + '{'
581 else:
582 raise ion(">=U not implemented in the general case yet")
583
584 _ifCmpImpl = {
585 'c': {
586 '>=U': _geuCImpl
587 }
588 }
589 #represents a DSL conditional construct
590 class If(ChildBlock):
591 def __init__(self, parent, cond):
592 self.op = 'if'
593 self.parent = parent
594 self.cond = cond
595 self.body = []
596 self.elseBody = []
597 self.curBody = self.body
598 self.locals = {}
599 self.elseLocals = {}
600 self.curLocals = self.locals
601 self.regValues = None
602
603 def addOp(self, op):
604 if op.op in ('case', 'arg'):
605 raise Exception(self.op + ' is not allows inside an if block')
606 if op.op == 'local':
607 name = op.params[0]
608 size = op.params[1]
609 self.locals[name] = size
610 elif op.op == 'else':
611 self.curLocals = self.elseLocals
612 self.curBody = self.elseBody
613 else:
614 self.curBody.append(op)
615
616 def localSize(self, name):
617 return self.curLocals.get(name)
618
619 def resolveLocal(self, name):
620 if name in self.locals:
621 return name
622 return self.parent.resolveLocal(name)
623
624 def _genTrueBody(self, prog, fieldVals, output, otype):
625 self.curLocals = self.locals
626 for local in self.locals:
627 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.locals[local], nm=local))
628 for op in self.body:
629 op.generate(prog, self, fieldVals, output, otype)
630
631 def _genFalseBody(self, prog, fieldVals, output, otype):
632 self.curLocals = self.elseLocals
633 for local in self.elseLocals:
634 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.elseLocals[local], nm=local))
635 for op in self.elseBody:
636 op.generate(prog, self, fieldVals, output, otype)
637
638 def _genConstParam(self, param, prog, fieldVals, output, otype):
639 if param:
640 self._genTrueBody(prog, fieldVals, output, otype)
641 else:
642 self._genFalseBody(prog, fieldVals, output, otype)
643
644 def generate(self, prog, parent, fieldVals, output, otype):
645 self.regValues = parent.regValues
646 try:
647 self._genConstParam(prog.checkBool(self.cond), prog, fieldVals, output, otype)
648 except Exception:
649 if self.cond in _ifCmpImpl[otype]:
650 output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output))
651 self._genTrueBody(prog, fieldVals, output, otype)
652 if self.elseBody:
653 output.append('\n\t} else {')
654 self._genFalseBody(prog, fieldVals, output, otype)
655 output.append('\n\t}')
656 else:
657 cond = prog.resolveParam(self.cond, parent, fieldVals)
658 if type(cond) is int:
659 self._genConstParam(cond, prog, fieldVals, output, otype)
660 else:
661 output.append('\n\tif ({cond}) '.format(cond=cond) + '{')
662 self._genTrueBody(prog, fieldVals, output, otype)
663 if self.elseBody:
664 output.append('\n\t} else {')
665 self._genFalseBody(prog, fieldVals, output, otype)
666 output.append('\n\t}')
667
668
669 def __str__(self):
670 lines = ['\n\tif']
671 for op in self.body:
672 lines.append(str(op))
673 lines.append('\n\tend')
674 return ''.join(lines)
675
676 class Registers:
677 def __init__(self):
678 self.regs = {}
679 self.pointers = {}
680 self.regArrays = {}
681 self.regToArray = {}
682
683 def addReg(self, name, size):
684 self.regs[name] = size
685
686 def addPointer(self, name, size):
687 self.pointers[name] = size
688
689 def addRegArray(self, name, size, regs):
690 self.regArrays[name] = (size, regs)
691 idx = 0
692 if not type(regs) is int:
693 for reg in regs:
694 self.regs[reg] = size
695 self.regToArray[reg] = (name, idx)
696 idx += 1
697
698 def isReg(self, name):
699 return name in self.regs
700
701 def isRegArray(self, name):
702 return name in self.regArrays
703
704 def isRegArrayMember(self, name):
705 return name in self.regToArray
706
707 def arrayMemberParent(self, name):
708 return self.regToArray[name][0]
709
710 def arrayMemberIndex(self, name):
711 return self.regToArray[name][1]
712
713 def arrayMemberName(self, array, index):
714 if type(index) is int and not type(self.regArrays[array][1]) is int:
715 return self.regArrays[array][1][index]
716 else:
717 return None
718
719 def isNamedArray(self, array):
720 return array in self.regArrays and type(self.regArrays[array][1]) is int
721
722 def processLine(self, parts):
723 if len(parts) == 3:
724 self.addRegArray(parts[0], int(parts[1]), int(parts[2]))
725 elif len(parts) > 2:
726 self.addRegArray(parts[0], int(parts[1]), parts[2:])
727 else:
728 if parts[1].startswith('ptr'):
729 self.addPointer(parts[0], int(parts[1][3:]))
730 else:
731 self.addReg(parts[0], int(parts[1]))
732 return self
733
734 def writeHeader(self, otype, hFile):
735 fieldList = []
736 for pointer in self.pointers:
737 hFile.write('\n\tuint{sz}_t *{nm};'.format(nm=pointer, sz=self.pointers[pointer]))
738 for reg in self.regs:
739 if not self.isRegArrayMember(reg):
740 fieldList.append((self.regs[reg], 1, reg))
741 for arr in self.regArrays:
742 size,regs = self.regArrays[arr]
743 if not type(regs) is int:
744 regs = len(regs)
745 fieldList.append((size, regs, arr))
746 fieldList.sort()
747 fieldList.reverse()
748 for size, count, name in fieldList:
749 if count > 1:
750 hFile.write('\n\tuint{sz}_t {nm}[{ct}];'.format(sz=size, nm=name, ct=count))
751 else:
752 hFile.write('\n\tuint{sz}_t {nm};'.format(sz=size, nm=name))
753
754 class Flags:
755 def __init__(self):
756 self.flagBits = {}
757 self.flagCalc = {}
758 self.flagStorage = {}
759 self.flagReg = None
760 self.maxBit = -1
761
762 def processLine(self, parts):
763 if parts[0] == 'register':
764 self.flagReg = parts[1]
765 else:
766 flag,bit,calc,storage = parts
767 bit,_,top = bit.partition('-')
768 bit = int(bit)
769 if top:
770 top = int(bit)
771 if top > self.maxBit:
772 self.maxBit = top
773 self.flagBits[flag] = (bit,top)
774 else:
775 if bit > self.maxBit:
776 self.maxBit = bit
777 self.flagBits[flag] = bit
778 self.flagCalc[flag] = calc
779 self.flagStorage[flag] = storage
780 return self
781
782 def getStorage(self, flag):
783 if not flag in self.flagStorage:
784 raise Exception('Undefined flag ' + flag)
785 loc,_,bit = self.flagStorage[flag].partition('.')
786 if bit:
787 return (loc, int(bit))
788 else:
789 return loc
790
791 def disperseFlags(self, prog, otype):
792 bitToFlag = [None] * (self.maxBit+1)
793 src = prog.resolveReg(self.flagReg, None, {})
794 output = []
795 for flag in self.flagBits:
796 bit = self.flagBits[flag]
797 if type(bit) is tuple:
798 bot,top = bit
799 mask = ((1 << (top + 1 - bot)) - 1) << bot
800 output.append('\n\t{dst} = {src} & mask;'.format(
801 dst=prog.resolveReg(self.flagStorage[flag], None, {}), src=src, mask=mask
802 ))
803 else:
804 bitToFlag[self.flagBits[flag]] = flag
805 multi = {}
806 for bit in range(len(bitToFlag)-1,-1,-1):
807 flag = bitToFlag[bit]
808 if not flag is None:
809 field,_,dstbit = self.flagStorage[flag].partition('.')
810 dst = prog.resolveReg(field, None, {})
811 if dstbit:
812 dstbit = int(dstbit)
813 multi.setdefault(dst, []).append((dstbit, bit))
814 else:
815 output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=(1 << bit)))
816 for dst in multi:
817 didClear = False
818 direct = []
819 for dstbit, bit in multi[dst]:
820 if dstbit == bit:
821 direct.append(bit)
822 else:
823 if not didClear:
824 output.append('\n\t{dst} = 0;'.format(dst=dst))
825 didClear = True
826 if dstbit > bit:
827 shift = '<<'
828 diff = dstbit - bit
829 else:
830 shift = '>>'
831 diff = bit - dstbit
832 output.append('\n\t{dst} |= {src} {shift} {diff} & {mask};'.format(
833 src=src, dst=dst, shift=shift, diff=diff, mask=(1 << dstbit)
834 ))
835 if direct:
836 if len(direct) == len(multi[dst]):
837 output.append('\n\t{dst} = {src};'.format(dst=dst, src=src))
838 else:
839 mask = 0
840 for bit in direct:
841 mask = mask | (1 << bit)
842 output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=mask))
843 return ''.join(output)
844
845 def coalesceFlags(self, prog, otype):
846 dst = prog.resolveReg(self.flagReg, None, {})
847 output = ['\n\t{dst} = 0;'.format(dst=dst)]
848 bitToFlag = [None] * (self.maxBit+1)
849 for flag in self.flagBits:
850 bit = self.flagBits[flag]
851 if type(bit) is tuple:
852 bot,_ = bit
853 src = prog.resolveReg(self.flagStorage[flag], None, {})
854 if bot:
855 output.append('\n\t{dst} |= {src} << {shift};'.format(
856 dst=dst, src = src, shift = bot
857 ))
858 else:
859 output.append('\n\t{dst} |= {src};'.format(
860 dst=dst, src = src
861 ))
862 else:
863 bitToFlag[bit] = flag
864 multi = {}
865 for bit in range(len(bitToFlag)-1,-1,-1):
866 flag = bitToFlag[bit]
867 if not flag is None:
868 field,_,srcbit = self.flagStorage[flag].partition('.')
869 src = prog.resolveReg(field, None, {})
870 if srcbit:
871 srcbit = int(srcbit)
872 multi.setdefault(src, []).append((srcbit,bit))
873 else:
874 output.append('\n\tif ({src}) {{\n\t\t{dst} |= 1 << {bit};\n\t}}'.format(
875 dst=dst, src=src, bit=bit
876 ))
877 for src in multi:
878 direct = 0
879 for srcbit, dstbit in multi[src]:
880 if srcbit == dstbit:
881 direct = direct | (1 << srcbit)
882 else:
883 output.append('\n\tif ({src} & (1 << {srcbit})) {{\n\t\t{dst} |= 1 << {dstbit};\n\t}}'.format(
884 src=src, dst=dst, srcbit=srcbit, dstbit=dstbit
885 ))
886 if direct:
887 output.append('\n\t{dst} |= {src} & {mask}'.format(
888 dst=dst, src=src, mask=direct
889 ))
890 return ''.join(output)
891
892
893 class Program:
894 def __init__(self, regs, instructions, subs, info, flags):
895 self.regs = regs
896 self.instructions = instructions
897 self.subroutines = subs
898 self.meta = {}
899 self.booleans = {}
900 self.prefix = info.get('prefix', [''])[0]
901 self.opsize = int(info.get('opcode_size', ['8'])[0])
902 self.extra_tables = info.get('extra_tables', [])
903 self.context_type = self.prefix + 'context'
904 self.body = info.get('body', [None])[0]
905 self.includes = info.get('include', [])
906 self.flags = flags
907 self.lastDst = None
908 self.scopes = []
909 self.currentScope = None
910 self.lastOp = None
911
912 def __str__(self):
913 pieces = []
914 for reg in self.regs:
915 pieces.append(str(self.regs[reg]))
916 for name in self.subroutines:
917 pieces.append('\n'+str(self.subroutines[name]))
918 for instruction in self.instructions:
919 pieces.append('\n'+str(instruction))
920 return ''.join(pieces)
921
922 def writeHeader(self, otype, header):
923 hFile = open(header, 'w')
924 macro = header.upper().replace('.', '_')
925 hFile.write('#ifndef {0}_'.format(macro))
926 hFile.write('\n#define {0}_'.format(macro))
927 hFile.write('\n#include "backend.h"')
928 hFile.write('\n\ntypedef struct {')
929 hFile.write('\n\tcpu_options gen;')
930 hFile.write('\n}} {0}options;'.format(self.prefix))
931 hFile.write('\n\ntypedef struct {')
932 hFile.write('\n\t{0}options *opts;'.format(self.prefix))
933 hFile.write('\n\tuint32_t cycles;')
934 self.regs.writeHeader(otype, hFile)
935 hFile.write('\n}} {0}context;'.format(self.prefix))
936 hFile.write('\n')
937 hFile.write('\n#endif //{0}_'.format(macro))
938 hFile.write('\n')
939 hFile.close()
940 def build(self, otype):
941 body = []
942 pieces = []
943 for include in self.includes:
944 body.append('#include "{0}"\n'.format(include))
945 for table in self.instructions:
946 opmap = [None] * (1 << self.opsize)
947 bodymap = {}
948 instructions = self.instructions[table]
949 instructions.sort()
950 for inst in instructions:
951 for val in inst.allValues():
952 if opmap[val] is None:
953 self.meta = {}
954 self.temp = {}
955 self.needFlagCoalesce = False
956 self.needFlagDisperse = False
957 self.lastOp = None
958 opmap[val] = inst.generateName(val)
959 bodymap[val] = inst.generateBody(val, self, otype)
960
961 pieces.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix))
962 pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
963 for inst in range(0, len(opmap)):
964 op = opmap[inst]
965 if op is None:
966 pieces.append('\n\tunimplemented,')
967 else:
968 pieces.append('\n\t' + op + ',')
969 body.append(bodymap[inst])
970 pieces.append('\n};')
971 if self.body in self.subroutines:
972 pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
973 pieces.append('\n{')
974 pieces.append('\n\twhile (context->cycles < target_cycle)')
975 pieces.append('\n\t{')
976 self.meta = {}
977 self.temp = {}
978 self.subroutines[self.body].inline(self, [], pieces, otype, None)
979 pieces.append('\n\t}')
980 pieces.append('\n}')
981 body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix))
982 body.append('\n{')
983 body.append('\n\tfatal_error("Unimplemented instruction");')
984 body.append('\n}\n')
985 return ''.join(body) + ''.join(pieces)
986
987 def checkBool(self, name):
988 if not name in self.booleans:
989 raise Exception(name + ' is not a defined boolean flag')
990 return self.booleans[name]
991
992 def getTemp(self, size):
993 if size in self.temp:
994 return ('', self.temp[size])
995 self.temp[size] = 'tmp{sz}'.format(sz=size);
996 return ('\n\tuint{sz}_t tmp{sz};'.format(sz=size), self.temp[size])
997
998 def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False):
999 keepGoing = True
1000 while keepGoing:
1001 keepGoing = False
1002 try:
1003 if type(param) is int:
1004 pass
1005 elif param.startswith('0x'):
1006 param = int(param, 16)
1007 else:
1008 param = int(param)
1009 except ValueError:
1010
1011 if parent:
1012 if param in parent.regValues and allowConstant:
1013 return parent.regValues[param]
1014 maybeLocal = parent.resolveLocal(param)
1015 if maybeLocal:
1016 return maybeLocal
1017 if param in fieldVals:
1018 param = fieldVals[param]
1019 elif param in self.meta:
1020 param = self.meta[param]
1021 keepGoing = True
1022 elif self.isReg(param):
1023 param = self.resolveReg(param, parent, fieldVals, isdst)
1024 return param
1025
1026 def isReg(self, name):
1027 if not type(name) is str:
1028 return False
1029 begin,sep,_ = name.partition('.')
1030 if sep:
1031 if begin in self.meta:
1032 begin = self.meta[begin]
1033 return self.regs.isRegArray(begin)
1034 else:
1035 return self.regs.isReg(name)
1036
1037 def resolveReg(self, name, parent, fieldVals, isDst=False):
1038 begin,sep,end = name.partition('.')
1039 if sep:
1040 if begin in self.meta:
1041 begin = self.meta[begin]
1042 if not self.regs.isRegArrayMember(end):
1043 end = self.resolveParam(end, parent, fieldVals)
1044 if not type(end) is int and self.regs.isRegArrayMember(end):
1045 arrayName = self.regs.arrayMemberParent(end)
1046 end = self.regs.arrayMemberIndex(end)
1047 if arrayName != begin:
1048 end = 'context->{0}[{1}]'.format(arrayName, end)
1049 if self.regs.isNamedArray(begin):
1050 regName = self.regs.arrayMemberName(begin, end)
1051 else:
1052 regName = '{0}.{1}'.format(begin, end)
1053 ret = 'context->{0}[{1}]'.format(begin, end)
1054 else:
1055 regName = name
1056 if self.regs.isRegArrayMember(name):
1057 arr,idx = self.regs.regToArray[name]
1058 ret = 'context->{0}[{1}]'.format(arr, idx)
1059 else:
1060 ret = 'context->' + name
1061 if regName == self.flags.flagReg:
1062 if isDst:
1063 self.needFlagDisperse = True
1064 else:
1065 self.needFlagCoalesce = True
1066 if isDst:
1067 self.lastDst = regName
1068 return ret
1069
1070
1071
1072 def paramSize(self, name):
1073 size = self.currentScope.localSize(name)
1074 if size:
1075 return size
1076 begin,sep,_ = name.partition('.')
1077 if sep and self.regs.isRegArray(begin):
1078 return self.regs.regArrays[begin][0]
1079 if self.regs.isReg(name):
1080 return self.regs.regs[name]
1081 return 32
1082
1083 def pushScope(self, scope):
1084 self.scopes.append(scope)
1085 self.currentScope = scope
1086
1087 def popScope(self):
1088 ret = self.scopes.pop()
1089 self.currentScope = self.scopes[-1] if self.scopes else None
1090 return ret
1091
1092 def getRootScope(self):
1093 return self.scopes[0]
1094
1095 def parse(f):
1096 instructions = {}
1097 subroutines = {}
1098 registers = None
1099 flags = None
1100 errors = []
1101 info = {}
1102 line_num = 0
1103 cur_object = None
1104 for line in f:
1105 line_num += 1
1106 line,_,comment = line.partition('#')
1107 if not line.strip():
1108 continue
1109 if line[0].isspace():
1110 if not cur_object is None:
1111 parts = [el.strip() for el in line.split(' ')]
1112 if type(cur_object) is dict:
1113 cur_object[parts[0]] = parts[1:]
1114 else:
1115 cur_object = cur_object.processLine(parts)
1116
1117 # if type(cur_object) is Registers:
1118 # if len(parts) > 2:
1119 # cur_object.addRegArray(parts[0], int(parts[1]), parts[2:])
1120 # else:
1121 # cur_object.addReg(parts[0], int(parts[1]))
1122 # elif type(cur_object) is dict:
1123 # cur_object[parts[0]] = parts[1:]
1124 # elif parts[0] == 'switch':
1125 # o = Switch(cur_object, parts[1])
1126 # cur_object.addOp(o)
1127 # cur_object = o
1128 # elif parts[0] == 'if':
1129 # o = If(cur_object, parts[1])
1130 # cur_object.addOp(o)
1131 # cur_object = o
1132 # elif parts[0] == 'end':
1133 # cur_object = cur_object.parent
1134 # else:
1135 # cur_object.addOp(NormalOp(parts))
1136 else:
1137 errors.append("Orphan instruction on line {0}".format(line_num))
1138 else:
1139 parts = line.split(' ')
1140 if len(parts) > 1:
1141 if len(parts) > 2:
1142 table,bitpattern,name = parts
1143 else:
1144 bitpattern,name = parts
1145 table = 'main'
1146 value = 0
1147 fields = {}
1148 curbit = len(bitpattern) - 1
1149 for char in bitpattern:
1150 value <<= 1
1151 if char in ('0', '1'):
1152 value |= int(char)
1153 else:
1154 if char in fields:
1155 fields[char] = (curbit, fields[char][1] + 1)
1156 else:
1157 fields[char] = (curbit, 1)
1158 curbit -= 1
1159 cur_object = Instruction(value, fields, name.strip())
1160 instructions.setdefault(table, []).append(cur_object)
1161 elif line.strip() == 'regs':
1162 if registers is None:
1163 registers = Registers()
1164 cur_object = registers
1165 elif line.strip() == 'info':
1166 cur_object = info
1167 elif line.strip() == 'flags':
1168 if flags is None:
1169 flags = Flags()
1170 cur_object = flags
1171 else:
1172 cur_object = SubRoutine(line.strip())
1173 subroutines[cur_object.name] = cur_object
1174 if errors:
1175 print(errors)
1176 else:
1177 p = Program(registers, instructions, subroutines, info, flags)
1178 p.booleans['dynarec'] = False
1179 p.booleans['interp'] = True
1180
1181 if 'header' in info:
1182 print('#include "{0}"'.format(info['header'][0]))
1183 p.writeHeader('c', info['header'][0])
1184 print('#include "util.h"')
1185 print('#include <stdlib.h>')
1186 print(p.build('c'))
1187
1188 def main(argv):
1189 f = open(argv[1])
1190 parse(f)
1191
1192 if __name__ == '__main__':
1193 from sys import argv
1194 main(argv)