Mercurial > repos > blastem
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) |