comparison cpu_dsl.py @ 1613:2d9e8a7b8ba2

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