Mercurial > repos > blastem
comparison cpu_dsl.py @ 2053:3414a4423de1 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 15 Jan 2022 13:15:21 -0800 |
parents | 7d4df6b74263 |
children | 338c78da3fff |
comparison
equal
deleted
inserted
replaced
1692:5dacaef602a7 | 2053:3414a4423de1 |
---|---|
18 raise Exception('end is only allowed inside a switch or if block') | 18 raise Exception('end is only allowed inside a switch or if block') |
19 else: | 19 else: |
20 self.addOp(NormalOp(parts)) | 20 self.addOp(NormalOp(parts)) |
21 return self | 21 return self |
22 | 22 |
23 def processOps(self, prog, fieldVals, output, otype, oplist): | |
24 for i in range(0, len(oplist)): | |
25 if i + 1 < len(oplist) and oplist[i+1].op == 'update_flags': | |
26 flagUpdates, _ = prog.flags.parseFlagUpdate(oplist[i+1].params[0]) | |
27 else: | |
28 flagUpdates = None | |
29 oplist[i].generate(prog, self, fieldVals, output, otype, flagUpdates) | |
30 | |
23 def resolveLocal(self, name): | 31 def resolveLocal(self, name): |
24 return None | 32 return None |
25 | 33 |
26 class ChildBlock(Block): | 34 class ChildBlock(Block): |
27 def processLine(self, parts): | 35 def processLine(self, parts): |
38 self.implementation = [] | 46 self.implementation = [] |
39 self.locals = {} | 47 self.locals = {} |
40 self.regValues = {} | 48 self.regValues = {} |
41 self.varyingBits = 0 | 49 self.varyingBits = 0 |
42 self.invalidFieldValues = {} | 50 self.invalidFieldValues = {} |
51 self.invalidCombos = [] | |
43 self.newLocals = [] | 52 self.newLocals = [] |
44 for field in fields: | 53 for field in fields: |
45 self.varyingBits += fields[field][1] | 54 self.varyingBits += fields[field][1] |
46 | 55 |
47 def addOp(self, op): | 56 def addOp(self, op): |
48 if op.op == 'local': | 57 if op.op == 'local': |
49 name = op.params[0] | 58 name = op.params[0] |
50 size = op.params[1] | 59 size = int(op.params[1]) |
51 self.locals[name] = size | 60 self.locals[name] = size |
52 elif op.op == 'invalid': | 61 elif op.op == 'invalid': |
53 name = op.params[0] | 62 if len(op.params) < 3: |
54 value = int(op.params[1]) | 63 name = op.params[0] |
55 self.invalidFieldValues.setdefault(name, set()).add(value) | 64 value = int(op.params[1]) |
65 self.invalidFieldValues.setdefault(name, set()).add(value) | |
66 else: | |
67 vmap = {} | |
68 for i in range(0, len(op.params), 2): | |
69 name = op.params[i] | |
70 value = int(op.params[i+1]) | |
71 vmap[name] = value | |
72 self.invalidCombos.append(vmap) | |
56 else: | 73 else: |
57 self.implementation.append(op) | 74 self.implementation.append(op) |
58 | 75 |
59 def resolveLocal(self, name): | 76 def resolveLocal(self, name): |
60 if name in self.locals: | 77 if name in self.locals: |
79 def allValues(self): | 96 def allValues(self): |
80 values = [] | 97 values = [] |
81 for i in range(0, 1 << self.varyingBits): | 98 for i in range(0, 1 << self.varyingBits): |
82 iword = self.value | 99 iword = self.value |
83 doIt = True | 100 doIt = True |
101 combos = [] | |
102 for combo in self.invalidCombos: | |
103 combos.append(dict(combo)) | |
84 for field in self.fields: | 104 for field in self.fields: |
85 shift,bits = self.fields[field] | 105 shift,bits = self.fields[field] |
86 val = i & ((1 << bits) - 1) | 106 val = i & ((1 << bits) - 1) |
87 if field in self.invalidFieldValues and val in self.invalidFieldValues[field]: | 107 if field in self.invalidFieldValues and val in self.invalidFieldValues[field]: |
88 doIt = False | 108 doIt = False |
109 break | |
110 nextcombos = [] | |
111 for combo in combos: | |
112 if field in combo: | |
113 if combo[field] == val: | |
114 del combo[field] | |
115 if not combo: | |
116 doIt = False | |
117 break | |
118 else: | |
119 continue | |
120 nextcombos.append(combo) | |
121 combos = nextcombos | |
122 if not doIt: | |
89 break | 123 break |
90 i >>= bits | 124 i >>= bits |
91 iword |= val << shift | 125 iword |= val << shift |
92 if doIt: | 126 if doIt: |
93 values.append(iword) | 127 values.append(iword) |
119 self.regValues = {} | 153 self.regValues = {} |
120 for var in self.locals: | 154 for var in self.locals: |
121 output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)) | 155 output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)) |
122 self.newLocals = [] | 156 self.newLocals = [] |
123 fieldVals,_ = self.getFieldVals(value) | 157 fieldVals,_ = self.getFieldVals(value) |
124 for op in self.implementation: | 158 self.processOps(prog, fieldVals, output, otype, self.implementation) |
125 op.generate(prog, self, fieldVals, output, otype) | 159 |
126 begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{' | 160 if prog.dispatch == 'call': |
161 begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context, uint32_t target_cycle)\n{' | |
162 elif prog.dispatch == 'goto': | |
163 begin = '\n' + self.generateName(value) + ': {' | |
164 else: | |
165 raise Exception('Unsupported dispatch type ' + prog.dispatch) | |
127 if prog.needFlagCoalesce: | 166 if prog.needFlagCoalesce: |
128 begin += prog.flags.coalesceFlags(prog, otype) | 167 begin += prog.flags.coalesceFlags(prog, otype) |
129 if prog.needFlagDisperse: | 168 if prog.needFlagDisperse: |
130 output.append(prog.flags.disperseFlags(prog, otype)) | 169 output.append(prog.flags.disperseFlags(prog, otype)) |
131 for var in self.newLocals: | 170 for var in self.newLocals: |
132 begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var) | 171 begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var) |
172 for size in prog.temp: | |
173 begin += '\n\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size) | |
133 prog.popScope() | 174 prog.popScope() |
175 if prog.dispatch == 'goto': | |
176 output += prog.nextInstruction(otype) | |
134 return begin + ''.join(output) + '\n}' | 177 return begin + ''.join(output) + '\n}' |
135 | 178 |
136 def __str__(self): | 179 def __str__(self): |
137 pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)] | 180 pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)] |
138 for name in self.locals: | 181 for name in self.locals: |
148 self.implementation = [] | 191 self.implementation = [] |
149 self.args = [] | 192 self.args = [] |
150 self.arg_map = {} | 193 self.arg_map = {} |
151 self.locals = {} | 194 self.locals = {} |
152 self.regValues = {} | 195 self.regValues = {} |
196 self.argValues = {} | |
153 | 197 |
154 def addOp(self, op): | 198 def addOp(self, op): |
155 if op.op == 'arg': | 199 if op.op == 'arg': |
156 name = op.params[0] | 200 name = op.params[0] |
157 size = op.params[1] | 201 size = int(op.params[1]) |
158 self.arg_map[name] = len(self.args) | 202 self.arg_map[name] = len(self.args) |
159 self.args.append((name, size)) | 203 self.args.append((name, size)) |
160 elif op.op == 'local': | 204 elif op.op == 'local': |
161 name = op.params[0] | 205 name = op.params[0] |
162 size = op.params[1] | 206 size = int(op.params[1]) |
163 self.locals[name] = size | 207 self.locals[name] = size |
164 else: | 208 else: |
165 self.implementation.append(op) | 209 self.implementation.append(op) |
166 | 210 |
167 def resolveLocal(self, name): | 211 def resolveLocal(self, name): |
171 | 215 |
172 def addLocal(self, name, size): | 216 def addLocal(self, name, size): |
173 self.locals[name] = size | 217 self.locals[name] = size |
174 | 218 |
175 def localSize(self, name): | 219 def localSize(self, name): |
176 return self.locals.get(name) | 220 if name in self.locals: |
221 return self.locals[name] | |
222 if name in self.arg_map: | |
223 argIndex = self.arg_map[name] | |
224 return self.args[argIndex][1] | |
225 return None | |
177 | 226 |
178 def inline(self, prog, params, output, otype, parent): | 227 def inline(self, prog, params, output, otype, parent): |
179 if len(params) != len(self.args): | 228 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))) | 229 raise Exception('{0} expects {1} arguments, but was called with {2}'.format(self.name, len(self.args), len(params))) |
181 argValues = {} | 230 argValues = {} |
187 argValues[name] = params[i] | 236 argValues[name] = params[i] |
188 i += 1 | 237 i += 1 |
189 for name in self.locals: | 238 for name in self.locals: |
190 size = self.locals[name] | 239 size = self.locals[name] |
191 output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name)) | 240 output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name)) |
192 for op in self.implementation: | 241 self.argValues = argValues |
193 op.generate(prog, self, argValues, output, otype) | 242 self.processOps(prog, argValues, output, otype, self.implementation) |
194 prog.popScope() | 243 prog.popScope() |
195 | 244 |
196 def __str__(self): | 245 def __str__(self): |
197 pieces = [self.name] | 246 pieces = [self.name] |
198 for name,size in self.args: | 247 for name,size in self.args: |
207 def __init__(self, evalFun = None): | 256 def __init__(self, evalFun = None): |
208 self.evalFun = evalFun | 257 self.evalFun = evalFun |
209 self.impls = {} | 258 self.impls = {} |
210 self.outOp = () | 259 self.outOp = () |
211 def cBinaryOperator(self, op): | 260 def cBinaryOperator(self, op): |
212 def _impl(prog, params): | 261 def _impl(prog, params, rawParams, flagUpdates): |
213 if op == '-': | 262 if op == '-': |
214 a = params[1] | 263 a = params[1] |
215 b = params[0] | 264 b = params[0] |
216 else: | 265 else: |
217 a = params[0] | 266 a = params[0] |
218 b = params[1] | 267 b = params[1] |
219 return '\n\t{dst} = {a} {op} {b};'.format( | 268 needsSizeAdjust = False |
220 dst = params[2], a = a, b = b, op = op | 269 if len(params) > 3: |
221 ) | 270 size = params[3] |
271 if size == 0: | |
272 size = 8 | |
273 elif size == 1: | |
274 size = 16 | |
275 else: | |
276 size = 32 | |
277 prog.lastSize = size | |
278 destSize = prog.paramSize(rawParams[2]) | |
279 if destSize > size: | |
280 needsSizeAdjust = True | |
281 prog.sizeAdjust = size | |
282 needsCarry = needsOflow = needsHalf = False | |
283 if flagUpdates: | |
284 for flag in flagUpdates: | |
285 calc = prog.flags.flagCalc[flag] | |
286 if calc == 'carry': | |
287 needsCarry = True | |
288 elif calc == 'half-carry': | |
289 needsHalf = True | |
290 elif calc == 'overflow': | |
291 needsOflow = True | |
292 decl = '' | |
293 if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): | |
294 if len(params) <= 3: | |
295 size = prog.paramSize(rawParams[2]) | |
296 if needsCarry and op != 'lsr': | |
297 size *= 2 | |
298 decl,name = prog.getTemp(size) | |
299 dst = prog.carryFlowDst = name | |
300 prog.lastA = a | |
301 prog.lastB = b | |
302 if size == 64: | |
303 a = '((uint64_t){a})'.format(a=a) | |
304 b = '((uint64_t){b})'.format(b=b) | |
305 prog.lastBFlow = b if op == '-' else '(~{b})'.format(b=b) | |
306 elif needsSizeAdjust: | |
307 decl,name = prog.getTemp(size) | |
308 dst = params[2] | |
309 return '{decl}\n\t{tmp} = ({a} & {mask}) {op} ({b} & {mask});\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( | |
310 decl = decl, tmp = name, a = a, b = b, op = op, dst = dst, mask = ((1 << size) - 1) | |
311 ) | |
312 else: | |
313 dst = params[2] | |
314 if needsSizeAdjust: | |
315 return decl + '\n\t{dst} = ({a} & {mask}) {op} ({b} & {mask});'.format( | |
316 dst = dst, a = a, b = b, op = op, mask = (1 << prog.sizeAdjust) - 1 | |
317 ) | |
318 else: | |
319 return decl + '\n\t{dst} = {a} {op} {b};'.format( | |
320 dst = dst, a = a, b = b, op = op | |
321 ) | |
222 self.impls['c'] = _impl | 322 self.impls['c'] = _impl |
223 self.outOp = (2,) | 323 self.outOp = (2,) |
224 return self | 324 return self |
225 def cUnaryOperator(self, op): | 325 def cUnaryOperator(self, op): |
226 def _impl(prog, params): | 326 def _impl(prog, params, rawParams, flagUpdates): |
227 return '\n\t{dst} = {op}{a};'.format( | 327 dst = params[1] |
228 dst = params[1], a = params[0], op = op | 328 decl = '' |
229 ) | 329 needsSizeAdjust = False |
330 if len(params) > 2: | |
331 size = params[2] | |
332 if size == 0: | |
333 size = 8 | |
334 elif size == 1: | |
335 size = 16 | |
336 else: | |
337 size = 32 | |
338 prog.lastSize = size | |
339 destSize = prog.paramSize(rawParams[1]) | |
340 if destSize > size: | |
341 needsSizeAdjust = True | |
342 prog.sizeAdjust = size | |
343 if op == '-': | |
344 if flagUpdates: | |
345 for flag in flagUpdates: | |
346 calc = prog.flags.flagCalc[flag] | |
347 if calc == 'carry': | |
348 needsCarry = True | |
349 elif calc == 'half-carry': | |
350 needsHalf = True | |
351 elif calc == 'overflow': | |
352 needsOflow = True | |
353 if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): | |
354 size = prog.paramSize(rawParams[1]) | |
355 if needsCarry: | |
356 size *= 2 | |
357 decl,name = prog.getTemp(size) | |
358 dst = prog.carryFlowDst = name | |
359 prog.lastA = 0 | |
360 prog.lastB = params[0] | |
361 prog.lastBFlow = params[0] | |
362 if needsSizeAdjust: | |
363 return decl + '\n\t{dst} = ({dst} & ~{mask}) | (({op}{a}) & {mask});'.format( | |
364 dst = dst, a = params[0], op = op, mask = (1 << prog.sizeAdjust) - 1 | |
365 ) | |
366 else: | |
367 return decl + '\n\t{dst} = {op}{a};'.format( | |
368 dst = dst, a = params[0], op = op | |
369 ) | |
230 self.impls['c'] = _impl | 370 self.impls['c'] = _impl |
231 self.outOp = (1,) | 371 self.outOp = (1,) |
232 return self | 372 return self |
233 def addImplementation(self, lang, outOp, impl): | 373 def addImplementation(self, lang, outOp, impl): |
234 self.impls[lang] = impl | 374 self.impls[lang] = impl |
242 return self.evalFun(*params) | 382 return self.evalFun(*params) |
243 def canEval(self): | 383 def canEval(self): |
244 return not self.evalFun is None | 384 return not self.evalFun is None |
245 def numArgs(self): | 385 def numArgs(self): |
246 return self.evalFun.__code__.co_argcount | 386 return self.evalFun.__code__.co_argcount |
247 def generate(self, otype, prog, params, rawParams): | 387 def numParams(self): |
388 if self.outOp: | |
389 params = max(self.outOp) + 1 | |
390 else: | |
391 params = 0 | |
392 if self.evalFun: | |
393 params = max(params, self.numArgs()) | |
394 return params | |
395 def generate(self, otype, prog, params, rawParams, flagUpdates): | |
248 if self.impls[otype].__code__.co_argcount == 2: | 396 if self.impls[otype].__code__.co_argcount == 2: |
249 return self.impls[otype](prog, params) | 397 return self.impls[otype](prog, params) |
250 else: | 398 elif self.impls[otype].__code__.co_argcount == 3: |
251 return self.impls[otype](prog, params, rawParams) | 399 return self.impls[otype](prog, params, rawParams) |
400 else: | |
401 return self.impls[otype](prog, params, rawParams, flagUpdates) | |
252 | 402 |
253 | 403 |
254 def _xchgCImpl(prog, params, rawParams): | 404 def _xchgCImpl(prog, params, rawParams): |
255 size = prog.paramSize(rawParams[0]) | 405 size = prog.paramSize(rawParams[0]) |
256 decl,name = prog.getTemp(size) | 406 decl,name = prog.getTemp(size) |
259 def _dispatchCImpl(prog, params): | 409 def _dispatchCImpl(prog, params): |
260 if len(params) == 1: | 410 if len(params) == 1: |
261 table = 'main' | 411 table = 'main' |
262 else: | 412 else: |
263 table = params[1] | 413 table = params[1] |
264 return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0]) | 414 if prog.dispatch == 'call': |
415 return '\n\timpl_{tbl}[{op}](context, target_cycle);'.format(tbl = table, op = params[0]) | |
416 elif prog.dispatch == 'goto': | |
417 return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0]) | |
418 else: | |
419 raise Exception('Unsupported dispatch type ' + prog.dispatch) | |
265 | 420 |
266 def _updateFlagsCImpl(prog, params, rawParams): | 421 def _updateFlagsCImpl(prog, params, rawParams): |
267 i = 0 | 422 autoUpdate, explicit = prog.flags.parseFlagUpdate(params[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 = [] | 423 output = [] |
288 #TODO: handle autoUpdate flags | 424 parity = None |
425 directFlags = {} | |
289 for flag in autoUpdate: | 426 for flag in autoUpdate: |
290 calc = prog.flags.flagCalc[flag] | 427 calc = prog.flags.flagCalc[flag] |
291 calc,_,resultBit = calc.partition('-') | 428 calc,_,resultBit = calc.partition('-') |
292 lastDst = prog.resolveParam(prog.lastDst, None, {}) | 429 if prog.carryFlowDst: |
430 lastDst = prog.carryFlowDst | |
431 else: | |
432 lastDst = prog.resolveParam(prog.lastDst, prog.currentScope, {}) | |
293 storage = prog.flags.getStorage(flag) | 433 storage = prog.flags.getStorage(flag) |
294 if calc == 'bit' or calc == 'sign': | 434 if calc == 'bit' or calc == 'sign' or calc == 'carry' or calc == 'half' or calc == 'overflow': |
435 myRes = lastDst | |
295 if calc == 'sign': | 436 if calc == 'sign': |
296 resultBit = prog.paramSize(prog.lastDst) - 1 | 437 resultBit = prog.getLastSize() - 1 |
297 else: | 438 elif calc == 'carry': |
298 resultBit = int(resultBit) | 439 if prog.lastOp.op in ('asr', 'lsr'): |
440 resultBit = 0 | |
441 myRes = prog.lastA | |
442 else: | |
443 resultBit = prog.getLastSize() | |
444 if prog.lastOp.op == 'ror': | |
445 resultBit -= 1 | |
446 elif calc == 'half': | |
447 resultBit = prog.getLastSize() - 4 | |
448 myRes = '({a} ^ {b} ^ {res})'.format(a = prog.lastA, b = prog.lastB, res = lastDst) | |
449 elif calc == 'overflow': | |
450 resultBit = prog.getLastSize() - 1 | |
451 myRes = '((({a} ^ {b})) & ({a} ^ {res}))'.format(a = prog.lastA, b = prog.lastBFlow, res = lastDst) | |
452 else: | |
453 #Note: offsetting this by the operation size - 8 makes sense for the Z80 | |
454 #but might not for other CPUs with this kind of fixed bit flag behavior | |
455 resultBit = int(resultBit) + prog.getLastSize() - 8 | |
299 if type(storage) is tuple: | 456 if type(storage) is tuple: |
300 reg,storageBit = storage | 457 reg,storageBit = storage |
301 reg = prog.resolveParam(reg, None, {}) | |
302 if storageBit == resultBit: | 458 if storageBit == resultBit: |
303 #TODO: optimize this case | 459 directFlags.setdefault((reg, myRes), []).append(resultBit) |
304 output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format( | 460 else: |
305 reg = reg, mask = 1 << resultBit, res = lastDst | 461 reg = prog.resolveParam(reg, None, {}) |
306 )) | |
307 else: | |
308 if resultBit > storageBit: | 462 if resultBit > storageBit: |
309 op = '>>' | 463 op = '>>' |
310 shift = resultBit - storageBit | 464 shift = resultBit - storageBit |
311 else: | 465 else: |
312 op = '<<' | 466 op = '<<' |
313 shift = storageBit - resultBit | 467 shift = storageBit - resultBit |
314 output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} {op} {shift}U & {mask}U);'.format( | 468 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 | 469 reg = reg, mask = 1 << storageBit, res = myRes, op = op, shift = shift |
316 )) | 470 )) |
317 else: | 471 else: |
318 reg = prog.resolveParam(storage, None, {}) | 472 reg = prog.resolveParam(storage, None, {}) |
319 output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=lastDst, mask = 1 << resultBit)) | 473 maxBit = prog.paramSize(storage) - 1 |
474 if resultBit > maxBit: | |
475 output.append('\n\t{reg} = {res} >> {shift} & {mask}U;'.format(reg=reg, res=myRes, shift = resultBit - maxBit, mask = 1 << maxBit)) | |
476 else: | |
477 output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=myRes, mask = 1 << resultBit)) | |
320 elif calc == 'zero': | 478 elif calc == 'zero': |
479 if prog.carryFlowDst: | |
480 realSize = prog.getLastSize() | |
481 if realSize != prog.paramSize(prog.carryFlowDst): | |
482 lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) | |
321 if type(storage) is tuple: | 483 if type(storage) is tuple: |
322 reg,storageBit = storage | 484 reg,storageBit = storage |
323 reg = prog.resolveParam(reg, None, {}) | 485 reg = prog.resolveParam(reg, None, {}) |
324 output.append('\n\t{reg} = {res} ? ({reg} & {mask}U) : ({reg} | {bit}U);'.format( | 486 output.append('\n\t{reg} = {res} ? ({reg} & {mask}U) : ({reg} | {bit}U);'.format( |
325 reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit | 487 reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit |
326 )) | 488 )) |
327 elif prog.paramSize(prog.lastDst) > prog.paramSize(storage): | 489 else: |
328 reg = prog.resolveParam(storage, None, {}) | 490 reg = prog.resolveParam(storage, None, {}) |
329 output.append('\n\t{reg} = {res} != 0;'.format( | 491 output.append('\n\t{reg} = {res} == 0;'.format( |
330 reg = reg, res = lastDst | 492 reg = reg, res = lastDst |
331 )) | 493 )) |
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': | 494 elif calc == 'parity': |
342 pass | 495 parity = storage |
496 paritySize = prog.getLastSize() | |
497 if prog.carryFlowDst: | |
498 parityDst = paritySrc = prog.carryFlowDst | |
499 else: | |
500 paritySrc = lastDst | |
501 decl,name = prog.getTemp(paritySize) | |
502 output.append(decl) | |
503 parityDst = name | |
504 else: | |
505 raise Exception('Unknown flag calc type: ' + calc) | |
506 for reg, myRes in directFlags: | |
507 bits = directFlags[(reg, myRes)] | |
508 resolved = prog.resolveParam(reg, None, {}) | |
509 if len(bits) == len(prog.flags.storageToFlags[reg]): | |
510 output.append('\n\t{reg} = {res};'.format(reg = resolved, res = myRes)) | |
511 else: | |
512 mask = 0 | |
513 for bit in bits: | |
514 mask |= 1 << bit | |
515 output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format( | |
516 reg = resolved, mask = mask, res = myRes | |
517 )) | |
518 if prog.carryFlowDst: | |
519 if prog.lastOp.op != 'cmp': | |
520 if prog.sizeAdjust: | |
521 output.append('\n\t{dst} = ({dst} & ~{mask}) | ({tmpdst} & {mask});'.format( | |
522 dst = prog.resolveParam(prog.lastDst, prog.currentScope, {}), tmpdst = prog.carryFlowDst, mask = ((1 << prog.sizeAdjust) - 1) | |
523 )) | |
524 prog.sizeAdjust = None | |
525 else: | |
526 output.append('\n\t{dst} = {tmpdst};'.format(dst = prog.resolveParam(prog.lastDst, prog.currentScope, {}), tmpdst = prog.carryFlowDst)) | |
527 prog.carryFlowDst = None | |
528 if parity: | |
529 if paritySize > 8: | |
530 if paritySize > 16: | |
531 output.append('\n\t{dst} = {src} ^ ({src} >> 16);'.format(dst=parityDst, src=paritySrc)) | |
532 paritySrc = parityDst | |
533 output.append('\n\t{dst} = {src} ^ ({src} >> 8);'.format(dst=parityDst, src=paritySrc)) | |
534 paritySrc = parityDst | |
535 output.append('\n\t{dst} = ({src} ^ ({src} >> 4)) & 0xF;'.format(dst=parityDst, src=paritySrc)) | |
536 if type(parity) is tuple: | |
537 reg,bit = parity | |
538 reg = prog.resolveParam(reg, None, {}) | |
539 output.append('\n\t{flag} = ({flag} & ~{mask}U) | ((0x6996 >> {parity}) << {bit} & {mask}U);'.format( | |
540 flag=reg, mask = 1 << bit, bit = bit, parity = parityDst | |
541 )) | |
542 else: | |
543 reg = prog.resolveParam(parity, None, {}) | |
544 output.append('\n\t{flag} = 0x9669 >> {parity} & 1;'.format(flag=reg, parity=parityDst)) | |
545 | |
343 #TODO: combine explicit flags targeting the same storage location | 546 #TODO: combine explicit flags targeting the same storage location |
344 for flag in explicit: | 547 for flag in explicit: |
345 location = prog.flags.getStorage(flag) | 548 location = prog.flags.getStorage(flag) |
346 if type(location) is tuple: | 549 if type(location) is tuple: |
347 reg,bit = location | 550 reg,bit = location |
356 else: | 559 else: |
357 reg = prog.resolveReg(location, None, {}) | 560 reg = prog.resolveReg(location, None, {}) |
358 output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag])) | 561 output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag])) |
359 return ''.join(output) | 562 return ''.join(output) |
360 | 563 |
361 def _cmpCImpl(prog, params): | 564 def _cmpCImpl(prog, params, rawParams, flagUpdates): |
362 size = prog.paramSize(params[1]) | 565 size = prog.paramSize(rawParams[1]) |
566 needsCarry = False | |
567 if flagUpdates: | |
568 for flag in flagUpdates: | |
569 calc = prog.flags.flagCalc[flag] | |
570 if calc == 'carry': | |
571 needsCarry = True | |
572 break | |
573 if needsCarry: | |
574 size *= 2 | |
363 tmpvar = 'cmp_tmp{sz}__'.format(sz=size) | 575 tmpvar = 'cmp_tmp{sz}__'.format(sz=size) |
364 typename = '' | 576 if flagUpdates: |
577 prog.carryFlowDst = tmpvar | |
578 prog.lastA = params[1] | |
579 prog.lastB = params[0] | |
580 prog.lastBFlow = params[0] | |
365 scope = prog.getRootScope() | 581 scope = prog.getRootScope() |
366 if not scope.resolveLocal(tmpvar): | 582 if not scope.resolveLocal(tmpvar): |
367 scope.addLocal(tmpvar, size) | 583 scope.addLocal(tmpvar, size) |
368 prog.lastDst = tmpvar | 584 prog.lastDst = rawParams[1] |
585 if len(params) > 2: | |
586 size = params[2] | |
587 if size == 0: | |
588 size = 8 | |
589 elif size == 1: | |
590 size = 16 | |
591 else: | |
592 size = 32 | |
593 prog.lastSize = size | |
594 else: | |
595 prog.lastSize = None | |
369 return '\n\t{var} = {b} - {a};'.format(var = tmpvar, a = params[0], b = params[1]) | 596 return '\n\t{var} = {b} - {a};'.format(var = tmpvar, a = params[0], b = params[1]) |
370 | 597 |
371 def _asrCImpl(prog, params, rawParams): | 598 def _asrCImpl(prog, params, rawParams, flagUpdates): |
372 shiftSize = prog.paramSize(rawParams[0]) | 599 needsCarry = False |
373 mask = 1 << (shiftSize - 1) | 600 if flagUpdates: |
374 return '\n\t{dst} = ({a} >> {b}) | ({a} & {mask});'.format(a = params[0], b = params[1], dst = params[2], mask = mask) | 601 for flag in flagUpdates: |
375 | 602 calc = prog.flags.flagCalc[flag] |
603 if calc == 'carry': | |
604 needsCarry = True | |
605 decl = '' | |
606 size = prog.paramSize(rawParams[2]) | |
607 if needsCarry: | |
608 decl,name = prog.getTemp(size * 2) | |
609 dst = prog.carryFlowDst = name | |
610 prog.lastA = params[0] | |
611 else: | |
612 dst = params[2] | |
613 mask = 1 << (size - 1) | |
614 return decl + '\n\t{dst} = ({a} >> {b}) | ({a} & {mask} ? 0xFFFFFFFFU << ({size} - {b}) : 0);'.format( | |
615 a = params[0], b = params[1], dst = dst, mask = mask, size=size) | |
616 | |
617 def _sext(size, src): | |
618 if size == 16: | |
619 return src | 0xFF00 if src & 0x80 else src & 0x7F | |
620 else: | |
621 return src | 0xFFFF0000 if src & 0x8000 else src & 0x7FFF | |
622 | |
623 def _sextCImpl(prog, params, rawParms): | |
624 if params[0] == 16: | |
625 fmt = '\n\t{dst} = {src} & 0x80 ? {src} | 0xFF00 : {src} & 0x7F;' | |
626 else: | |
627 fmt = '\n\t{dst} = {src} & 0x8000 ? {src} | 0xFFFF0000 : {src} & 0x7FFF;' | |
628 return fmt.format(src=params[1], dst=params[2]) | |
629 | |
630 def _getCarryCheck(prog): | |
631 carryFlag = None | |
632 for flag in prog.flags.flagOrder: | |
633 if prog.flags.flagCalc[flag] == 'carry': | |
634 carryFlag = flag | |
635 break | |
636 if carryFlag is None: | |
637 raise Exception('adc requires a defined carry flag') | |
638 carryStorage = prog.flags.getStorage(carryFlag) | |
639 if type(carryStorage) is tuple: | |
640 reg,bit = carryStorage | |
641 reg = prog.resolveReg(reg, None, (), False) | |
642 return '({reg} & 1 << {bit})'.format(reg=reg, bit=bit) | |
643 else: | |
644 return prog.resolveReg(carryStorage, None, (), False) | |
645 | |
646 def _adcCImpl(prog, params, rawParams, flagUpdates): | |
647 needsSizeAdjust = False | |
648 if len(params) > 3: | |
649 size = params[3] | |
650 if size == 0: | |
651 size = 8 | |
652 elif size == 1: | |
653 size = 16 | |
654 else: | |
655 size = 32 | |
656 prog.lastSize = size | |
657 destSize = prog.paramSize(rawParams[2]) | |
658 if destSize > size: | |
659 needsSizeAdjust = True | |
660 prog.sizeAdjust = size | |
661 needsCarry = needsOflow = needsHalf = False | |
662 if flagUpdates: | |
663 for flag in flagUpdates: | |
664 calc = prog.flags.flagCalc[flag] | |
665 if calc == 'carry': | |
666 needsCarry = True | |
667 elif calc == 'half-carry': | |
668 needsHalf = True | |
669 elif calc == 'overflow': | |
670 needsOflow = True | |
671 decl = '' | |
672 carryCheck = _getCarryCheck(prog) | |
673 vals = '1 : 0' | |
674 if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): | |
675 if len(params) <= 3: | |
676 size = prog.paramSize(rawParams[2]) | |
677 if needsCarry: | |
678 size *= 2 | |
679 decl,name = prog.getTemp(size) | |
680 dst = prog.carryFlowDst = name | |
681 prog.lastA = params[0] | |
682 prog.lastB = params[1] | |
683 prog.lastBFlow = '(~{b})'.format(b=params[1]) | |
684 if size == 64: | |
685 params[0] = '((uint64_t){a})'.format(a=params[0]) | |
686 params[1] = '((uint64_t){b})'.format(b=params[1]) | |
687 vals = '((uint64_t)1) : ((uint64_t)0)' | |
688 elif needsSizeAdjust: | |
689 decl,name = prog.getTemp(size) | |
690 dst = params[2] | |
691 return '{decl}\n\t{tmp} = ({a} & {mask}) + ({b} & {mask}) + ({check} ? 1 : 0);\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( | |
692 decl = decl, tmp = name, a = a, b = b, op = op, dst = dst, mask = ((1 << size) - 1), check = carryCheck | |
693 ) | |
694 else: | |
695 dst = params[2] | |
696 return decl + '\n\t{dst} = {a} + {b} + ({check} ? {vals});'.format(dst = dst, | |
697 a = params[0], b = params[1], check = carryCheck, vals = vals | |
698 ) | |
699 | |
700 def _sbcCImpl(prog, params, rawParams, flagUpdates): | |
701 needsSizeAdjust = False | |
702 if len(params) > 3: | |
703 size = params[3] | |
704 if size == 0: | |
705 size = 8 | |
706 elif size == 1: | |
707 size = 16 | |
708 else: | |
709 size = 32 | |
710 prog.lastSize = size | |
711 destSize = prog.paramSize(rawParams[2]) | |
712 if destSize > size: | |
713 needsSizeAdjust = True | |
714 prog.sizeAdjust = size | |
715 needsCarry = needsOflow = needsHalf = False | |
716 if flagUpdates: | |
717 for flag in flagUpdates: | |
718 calc = prog.flags.flagCalc[flag] | |
719 if calc == 'carry': | |
720 needsCarry = True | |
721 elif calc == 'half-carry': | |
722 needsHalf = True | |
723 elif calc == 'overflow': | |
724 needsOflow = True | |
725 decl = '' | |
726 carryCheck = _getCarryCheck(prog) | |
727 vals = '1 : 0' | |
728 if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): | |
729 size = prog.paramSize(rawParams[2]) | |
730 if needsCarry: | |
731 size *= 2 | |
732 decl,name = prog.getTemp(size) | |
733 dst = prog.carryFlowDst = name | |
734 prog.lastA = params[1] | |
735 prog.lastB = params[0] | |
736 prog.lastBFlow = params[0] | |
737 if size == 64: | |
738 params[1] = '((uint64_t){a})'.format(a=params[1]) | |
739 params[0] = '((uint64_t){b})'.format(b=params[0]) | |
740 vals = '((uint64_t)1) : ((uint64_t)0)' | |
741 elif needsSizeAdjust: | |
742 decl,name = prog.getTemp(size) | |
743 dst = params[2] | |
744 return '{decl}\n\t{tmp} = ({b} & {mask}) - ({a} & {mask}) - ({check} ? 1 : 0);\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( | |
745 decl = decl, tmp = name, a = params[0], b = params[1], op = op, dst = dst, mask = ((1 << size) - 1), check = carryCheck | |
746 ) | |
747 else: | |
748 dst = params[2] | |
749 return decl + '\n\t{dst} = {b} - {a} - ({check} ? {vals});'.format(dst = dst, | |
750 a = params[0], b = params[1], check=_getCarryCheck(prog), vals = vals | |
751 ) | |
752 | |
753 def _rolCImpl(prog, params, rawParams, flagUpdates): | |
754 needsCarry = False | |
755 if flagUpdates: | |
756 for flag in flagUpdates: | |
757 calc = prog.flags.flagCalc[flag] | |
758 if calc == 'carry': | |
759 needsCarry = True | |
760 decl = '' | |
761 size = prog.paramSize(rawParams[2]) | |
762 if needsCarry: | |
763 decl,name = prog.getTemp(size * 2) | |
764 dst = prog.carryFlowDst = name | |
765 else: | |
766 dst = params[2] | |
767 return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} - {b});'.format(dst = dst, | |
768 a = params[0], b = params[1], size=size | |
769 ) | |
770 | |
771 def _rlcCImpl(prog, params, rawParams, flagUpdates): | |
772 needsCarry = False | |
773 if flagUpdates: | |
774 for flag in flagUpdates: | |
775 calc = prog.flags.flagCalc[flag] | |
776 if calc == 'carry': | |
777 needsCarry = True | |
778 decl = '' | |
779 carryCheck = _getCarryCheck(prog) | |
780 size = prog.paramSize(rawParams[2]) | |
781 if needsCarry: | |
782 decl,name = prog.getTemp(size * 2) | |
783 dst = prog.carryFlowDst = name | |
784 else: | |
785 dst = params[2] | |
786 return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({b} - 1);'.format(dst = dst, | |
787 a = params[0], b = params[1], size=size, check=carryCheck | |
788 ) | |
789 | |
790 def _rorCImpl(prog, params, rawParams, flagUpdates): | |
791 size = prog.paramSize(rawParams[2]) | |
792 return '\n\t{dst} = {a} >> {b} | {a} << ({size} - {b});'.format(dst = params[2], | |
793 a = params[0], b = params[1], size=size | |
794 ) | |
795 | |
796 def _rrcCImpl(prog, params, rawParams, flagUpdates): | |
797 needsCarry = False | |
798 if flagUpdates: | |
799 for flag in flagUpdates: | |
800 calc = prog.flags.flagCalc[flag] | |
801 if calc == 'carry': | |
802 needsCarry = True | |
803 decl = '' | |
804 carryCheck = _getCarryCheck(prog) | |
805 size = prog.paramSize(rawParams[2]) | |
806 if needsCarry: | |
807 decl,name = prog.getTemp(size * 2) | |
808 dst = prog.carryFlowDst = name | |
809 else: | |
810 dst = params[2] | |
811 return decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst, | |
812 a = params[0], b = params[1], size=size, check=carryCheck | |
813 ) | |
814 | |
815 def _updateSyncCImpl(prog, params): | |
816 return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle) | |
817 | |
376 _opMap = { | 818 _opMap = { |
377 'mov': Op(lambda val: val).cUnaryOperator(''), | 819 'mov': Op(lambda val: val).cUnaryOperator(''), |
378 'not': Op(lambda val: ~val).cUnaryOperator('~'), | 820 'not': Op(lambda val: ~val).cUnaryOperator('~'), |
379 'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'), | 821 'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'), |
380 'neg': Op(lambda val: -val).cUnaryOperator('-'), | 822 'neg': Op(lambda val: -val).cUnaryOperator('-'), |
381 'add': Op(lambda a, b: a + b).cBinaryOperator('+'), | 823 'add': Op(lambda a, b: a + b).cBinaryOperator('+'), |
824 'adc': Op().addImplementation('c', 2, _adcCImpl), | |
382 'sub': Op(lambda a, b: b - a).cBinaryOperator('-'), | 825 'sub': Op(lambda a, b: b - a).cBinaryOperator('-'), |
826 'sbc': Op().addImplementation('c', 2, _sbcCImpl), | |
383 'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'), | 827 'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'), |
384 'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'), | 828 'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'), |
385 'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl), | 829 'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl), |
830 'rol': Op().addImplementation('c', 2, _rolCImpl), | |
831 'rlc': Op().addImplementation('c', 2, _rlcCImpl), | |
832 'ror': Op().addImplementation('c', 2, _rorCImpl), | |
833 'rrc': Op().addImplementation('c', 2, _rrcCImpl), | |
386 'and': Op(lambda a, b: a & b).cBinaryOperator('&'), | 834 'and': Op(lambda a, b: a & b).cBinaryOperator('&'), |
387 'or': Op(lambda a, b: a | b).cBinaryOperator('|'), | 835 'or': Op(lambda a, b: a | b).cBinaryOperator('|'), |
388 'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'), | 836 'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'), |
389 'abs': Op(lambda val: abs(val)).addImplementation( | 837 '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]) | 838 'c', 1, lambda prog, params: '\n\t{dst} = abs({src});'.format(dst=params[1], src=params[0]) |
391 ), | 839 ), |
392 'cmp': Op().addImplementation('c', None, _cmpCImpl), | 840 'cmp': Op().addImplementation('c', None, _cmpCImpl), |
841 'sext': Op(_sext).addImplementation('c', 2, _sextCImpl), | |
393 'ocall': Op().addImplementation('c', None, lambda prog, params: '\n\t{pre}{fun}({args});'.format( | 842 '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:]]) | 843 pre = prog.prefix, fun = params[0], args = ', '.join(['context'] + [str(p) for p in params[1:]]) |
844 )), | |
845 'pcall': Op().addImplementation('c', None, lambda prog, params: '\n\t(({typ}){fun})({args});'.format( | |
846 typ = params[1], fun = params[0], args = ', '.join([str(p) for p in params[2:]]) | |
395 )), | 847 )), |
396 'cycles': Op().addImplementation('c', None, | 848 'cycles': Op().addImplementation('c', None, |
397 lambda prog, params: '\n\tcontext->cycles += context->opts->gen.clock_divider * {0};'.format( | 849 lambda prog, params: '\n\tcontext->cycles += context->opts->gen.clock_divider * {0};'.format( |
398 params[0] | 850 params[0] |
399 ) | 851 ) |
400 ), | 852 ), |
401 'addsize': Op( | 853 'addsize': Op( |
402 lambda a, b: b + (2 * a if a else 1) | 854 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( | 855 ).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] | 856 dst = params[2], sz = params[0], val = params[1] |
405 )), | 857 )), |
406 'decsize': Op( | 858 'decsize': Op( |
407 lambda a, b: b - (2 * a if a else 1) | 859 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( | 860 ).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] | 861 dst = params[2], sz = params[0], val = params[1] |
410 )), | 862 )), |
411 'xchg': Op().addImplementation('c', (0,1), _xchgCImpl), | 863 'xchg': Op().addImplementation('c', (0,1), _xchgCImpl), |
412 'dispatch': Op().addImplementation('c', None, _dispatchCImpl), | 864 'dispatch': Op().addImplementation('c', None, _dispatchCImpl), |
413 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl) | 865 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl), |
866 'update_sync': Op().addImplementation('c', None, _updateSyncCImpl) | |
414 } | 867 } |
415 | 868 |
416 #represents a simple DSL instruction | 869 #represents a simple DSL instruction |
417 class NormalOp: | 870 class NormalOp: |
418 def __init__(self, parts): | 871 def __init__(self, parts): |
419 self.op = parts[0] | 872 self.op = parts[0] |
420 self.params = parts[1:] | 873 self.params = parts[1:] |
421 | 874 |
422 def generate(self, prog, parent, fieldVals, output, otype): | 875 def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): |
423 procParams = [] | 876 procParams = [] |
424 allParamsConst = True | 877 allParamsConst = flagUpdates is None and not prog.conditional |
425 opDef = _opMap.get(self.op) | 878 opDef = _opMap.get(self.op) |
426 for param in self.params: | 879 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 | 880 isDst = (not opDef is None) and len(procParams) in opDef.outOp |
881 allowConst = (self.op in prog.subroutines or not isDst) and param in parent.regValues | |
882 if isDst and self.op == 'xchg': | |
883 #xchg uses its regs as both source and destination | |
884 #we need to resolve as both so that disperse/coalesce flag stuff gets done | |
885 prog.resolveParam(param, parent, fieldVals, allowConst, False) | |
429 param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst) | 886 param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst) |
430 | 887 |
431 if (not type(param) is int) and len(procParams) != len(self.params) - 1: | 888 if (not type(param) is int) and len(procParams) != len(self.params) - 1: |
432 allParamsConst = False | 889 allParamsConst = False |
433 procParams.append(param) | 890 procParams.append(param) |
440 index = str(fieldVals[index]) | 897 index = str(fieldVals[index]) |
441 param = param + '.' + index | 898 param = param + '.' + index |
442 else: | 899 else: |
443 param = parent.resolveLocal(param) or param | 900 param = parent.resolveLocal(param) or param |
444 if param in fieldVals: | 901 if param in fieldVals: |
445 param = fieldVals[index] | 902 param = fieldVals[param] |
446 prog.meta[self.params[0]] = param | 903 prog.meta[self.params[0]] = param |
447 elif self.op == 'dis': | 904 elif self.op == 'dis': |
448 #TODO: Disassembler | 905 #TODO: Disassembler |
449 pass | 906 pass |
450 elif not opDef is None: | 907 elif not opDef is None: |
908 if opDef.numParams() > len(procParams): | |
909 raise Exception('Insufficient params for ' + self.op + ' (' + ', '.join(self.params) + ')') | |
451 if opDef.canEval() and allParamsConst: | 910 if opDef.canEval() and allParamsConst: |
452 #do constant folding | 911 #do constant folding |
453 if opDef.numArgs() >= len(procParams): | 912 if opDef.numArgs() >= len(procParams): |
454 raise Exception('Insufficient args for ' + self.op + ' (' + ', '.join(self.params) + ')') | 913 raise Exception('Insufficient args for ' + self.op + ' (' + ', '.join(self.params) + ')') |
455 dst = self.params[opDef.numArgs()] | 914 dst = self.params[opDef.numArgs()] |
459 maybeLocal = parent.resolveLocal(dst) | 918 maybeLocal = parent.resolveLocal(dst) |
460 if maybeLocal: | 919 if maybeLocal: |
461 dst = maybeLocal | 920 dst = maybeLocal |
462 parent.regValues[dst] = result | 921 parent.regValues[dst] = result |
463 if prog.isReg(dst): | 922 if prog.isReg(dst): |
464 output.append(_opMap['mov'].generate(otype, prog, procParams, self.params)) | 923 shortProc = (procParams[0], procParams[-1]) |
465 else: | 924 shortParams = (self.params[0], self.params[-1]) |
466 output.append(opDef.generate(otype, prog, procParams, self.params)) | 925 output.append(_opMap['mov'].generate(otype, prog, shortProc, shortParams, None)) |
926 else: | |
927 output.append(opDef.generate(otype, prog, procParams, self.params, flagUpdates)) | |
928 for dstIdx in opDef.outOp: | |
929 dst = self.params[dstIdx] | |
930 while dst in prog.meta: | |
931 dst = prog.meta[dst] | |
932 if dst in parent.regValues: | |
933 del parent.regValues[dst] | |
934 | |
467 elif self.op in prog.subroutines: | 935 elif self.op in prog.subroutines: |
936 procParams = [] | |
937 for param in self.params: | |
938 begin,sep,end = param.partition('.') | |
939 if sep: | |
940 if end in fieldVals: | |
941 param = begin + '.' + str(fieldVals[end]) | |
942 else: | |
943 if param in fieldVals: | |
944 param = fieldVals[param] | |
945 else: | |
946 maybeLocal = parent.resolveLocal(param) | |
947 if maybeLocal and maybeLocal in parent.regValues: | |
948 param = parent.regValues[maybeLocal] | |
949 procParams.append(param) | |
468 prog.subroutines[self.op].inline(prog, procParams, output, otype, parent) | 950 prog.subroutines[self.op].inline(prog, procParams, output, otype, parent) |
469 else: | 951 else: |
470 output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');') | 952 output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');') |
471 prog.lastOp = self | 953 prog.lastOp = self |
472 | 954 |
515 def localSize(self, name): | 997 def localSize(self, name): |
516 if name in self.current_locals: | 998 if name in self.current_locals: |
517 return self.current_locals[name] | 999 return self.current_locals[name] |
518 return self.parent.localSize(name) | 1000 return self.parent.localSize(name) |
519 | 1001 |
520 def generate(self, prog, parent, fieldVals, output, otype): | 1002 def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): |
521 prog.pushScope(self) | 1003 prog.pushScope(self) |
522 param = prog.resolveParam(self.param, parent, fieldVals) | 1004 param = prog.resolveParam(self.param, parent, fieldVals) |
523 if type(param) is int: | 1005 if type(param) is int: |
524 self.regValues = self.parent.regValues | 1006 self.regValues = self.parent.regValues |
525 if param in self.cases: | 1007 if param in self.cases: |
526 self.current_locals = self.case_locals[param] | 1008 self.current_locals = self.case_locals[param] |
527 output.append('\n\t{') | 1009 output.append('\n\t{') |
528 for local in self.case_locals[param]: | 1010 for local in self.case_locals[param]: |
529 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local)) | 1011 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local)) |
530 for op in self.cases[param]: | 1012 self.processOps(prog, fieldVals, output, otype, self.cases[param]) |
531 op.generate(prog, self, fieldVals, output, otype) | |
532 output.append('\n\t}') | 1013 output.append('\n\t}') |
533 elif self.default: | 1014 elif self.default: |
534 self.current_locals = self.default_locals | 1015 self.current_locals = self.default_locals |
535 output.append('\n\t{') | 1016 output.append('\n\t{') |
536 for local in self.default_locals: | 1017 for local in self.default_locals: |
537 output.append('\n\tuint{0}_t {1};'.format(self.default[local], local)) | 1018 output.append('\n\tuint{0}_t {1};'.format(self.default[local], local)) |
538 for op in self.default: | 1019 self.processOps(prog, fieldVals, output, otype, self.default) |
539 op.generate(prog, self, fieldVals, output, otype) | |
540 output.append('\n\t}') | 1020 output.append('\n\t}') |
541 else: | 1021 else: |
1022 oldCond = prog.conditional | |
1023 prog.conditional = True | |
542 output.append('\n\tswitch(' + param + ')') | 1024 output.append('\n\tswitch(' + param + ')') |
543 output.append('\n\t{') | 1025 output.append('\n\t{') |
544 for case in self.cases: | 1026 for case in self.cases: |
1027 #temp = prog.temp.copy() | |
545 self.current_locals = self.case_locals[case] | 1028 self.current_locals = self.case_locals[case] |
546 self.regValues = dict(self.parent.regValues) | 1029 self.regValues = dict(self.parent.regValues) |
547 output.append('\n\tcase {0}U: '.format(case) + '{') | 1030 output.append('\n\tcase {0}U: '.format(case) + '{') |
548 for local in self.case_locals[case]: | 1031 for local in self.case_locals[case]: |
549 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local)) | 1032 output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local)) |
550 for op in self.cases[case]: | 1033 self.processOps(prog, fieldVals, output, otype, self.cases[case]) |
551 op.generate(prog, self, fieldVals, output, otype) | |
552 output.append('\n\tbreak;') | 1034 output.append('\n\tbreak;') |
553 output.append('\n\t}') | 1035 output.append('\n\t}') |
1036 #prog.temp = temp | |
554 if self.default: | 1037 if self.default: |
1038 #temp = prog.temp.copy() | |
555 self.current_locals = self.default_locals | 1039 self.current_locals = self.default_locals |
556 self.regValues = dict(self.parent.regValues) | 1040 self.regValues = dict(self.parent.regValues) |
557 output.append('\n\tdefault: {') | 1041 output.append('\n\tdefault: {') |
558 for local in self.default_locals: | 1042 for local in self.default_locals: |
559 output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local)) | 1043 output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local)) |
560 for op in self.default: | 1044 self.processOps(prog, fieldVals, output, otype, self.default) |
561 op.generate(prog, self, fieldVals, output, otype) | 1045 #prog.temp = temp |
562 output.append('\n\t}') | 1046 output.append('\n\t}') |
1047 prog.conditional = oldCond | |
563 prog.popScope() | 1048 prog.popScope() |
564 | 1049 |
565 def __str__(self): | 1050 def __str__(self): |
566 keys = self.cases.keys() | 1051 keys = self.cases.keys() |
567 keys.sort() | 1052 keys.sort() |
577 if prog.lastOp.op == 'cmp': | 1062 if prog.lastOp.op == 'cmp': |
578 output.pop() | 1063 output.pop() |
579 params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params] | 1064 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]) + '{' | 1065 return '\n\tif ({a} >= {b}) '.format(a=params[1], b = params[0]) + '{' |
581 else: | 1066 else: |
582 raise ion(">=U not implemented in the general case yet") | 1067 raise Exception(">=U not implemented in the general case yet") |
1068 | |
1069 def _eqCImpl(prog, parent, fieldVals, output): | |
1070 if prog.lastOp.op == 'cmp': | |
1071 output.pop() | |
1072 params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params] | |
1073 return '\n\tif ({a} == {b}) '.format(a=params[1], b = params[0]) + '{' | |
1074 else: | |
1075 return '\n\tif (!{a}) {{'.format(a=prog.resolveParam(prog.lastDst, None, {})) | |
1076 | |
1077 def _neqCImpl(prog, parent, fieldVals, output): | |
1078 return '\n\tif ({a}) {{'.format(a=prog.resolveParam(prog.lastDst, None, {})) | |
583 | 1079 |
584 _ifCmpImpl = { | 1080 _ifCmpImpl = { |
585 'c': { | 1081 'c': { |
586 '>=U': _geuCImpl | 1082 '>=U': _geuCImpl, |
1083 '=': _eqCImpl, | |
1084 '!=': _neqCImpl | |
587 } | 1085 } |
588 } | 1086 } |
589 #represents a DSL conditional construct | 1087 #represents a DSL conditional construct |
590 class If(ChildBlock): | 1088 class If(ChildBlock): |
591 def __init__(self, parent, cond): | 1089 def __init__(self, parent, cond): |
604 if op.op in ('case', 'arg'): | 1102 if op.op in ('case', 'arg'): |
605 raise Exception(self.op + ' is not allows inside an if block') | 1103 raise Exception(self.op + ' is not allows inside an if block') |
606 if op.op == 'local': | 1104 if op.op == 'local': |
607 name = op.params[0] | 1105 name = op.params[0] |
608 size = op.params[1] | 1106 size = op.params[1] |
609 self.locals[name] = size | 1107 self.curLocals[name] = size |
610 elif op.op == 'else': | 1108 elif op.op == 'else': |
611 self.curLocals = self.elseLocals | 1109 self.curLocals = self.elseLocals |
612 self.curBody = self.elseBody | 1110 self.curBody = self.elseBody |
613 else: | 1111 else: |
614 self.curBody.append(op) | 1112 self.curBody.append(op) |
615 | 1113 |
616 def localSize(self, name): | 1114 def localSize(self, name): |
617 return self.curLocals.get(name) | 1115 return self.curLocals.get(name) |
618 | 1116 |
619 def resolveLocal(self, name): | 1117 def resolveLocal(self, name): |
620 if name in self.locals: | 1118 if name in self.curLocals: |
621 return name | 1119 return name |
622 return self.parent.resolveLocal(name) | 1120 return self.parent.resolveLocal(name) |
623 | 1121 |
624 def _genTrueBody(self, prog, fieldVals, output, otype): | 1122 def _genTrueBody(self, prog, fieldVals, output, otype): |
625 self.curLocals = self.locals | 1123 self.curLocals = self.locals |
1124 subOut = [] | |
1125 self.processOps(prog, fieldVals, subOut, otype, self.body) | |
626 for local in self.locals: | 1126 for local in self.locals: |
627 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.locals[local], nm=local)) | 1127 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.locals[local], nm=local)) |
628 for op in self.body: | 1128 output += subOut |
629 op.generate(prog, self, fieldVals, output, otype) | |
630 | 1129 |
631 def _genFalseBody(self, prog, fieldVals, output, otype): | 1130 def _genFalseBody(self, prog, fieldVals, output, otype): |
632 self.curLocals = self.elseLocals | 1131 self.curLocals = self.elseLocals |
1132 subOut = [] | |
1133 self.processOps(prog, fieldVals, subOut, otype, self.elseBody) | |
633 for local in self.elseLocals: | 1134 for local in self.elseLocals: |
634 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.elseLocals[local], nm=local)) | 1135 output.append('\n\tuint{sz}_t {nm};'.format(sz=self.elseLocals[local], nm=local)) |
635 for op in self.elseBody: | 1136 output += subOut |
636 op.generate(prog, self, fieldVals, output, otype) | |
637 | 1137 |
638 def _genConstParam(self, param, prog, fieldVals, output, otype): | 1138 def _genConstParam(self, param, prog, fieldVals, output, otype): |
639 if param: | 1139 if param: |
640 self._genTrueBody(prog, fieldVals, output, otype) | 1140 self._genTrueBody(prog, fieldVals, output, otype) |
641 else: | 1141 else: |
642 self._genFalseBody(prog, fieldVals, output, otype) | 1142 self._genFalseBody(prog, fieldVals, output, otype) |
643 | 1143 |
644 def generate(self, prog, parent, fieldVals, output, otype): | 1144 def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): |
645 self.regValues = parent.regValues | 1145 self.regValues = parent.regValues |
646 try: | 1146 if self.cond in prog.booleans: |
647 self._genConstParam(prog.checkBool(self.cond), prog, fieldVals, output, otype) | 1147 self._genConstParam(prog.checkBool(self.cond), prog, fieldVals, output, otype) |
648 except Exception: | 1148 else: |
649 if self.cond in _ifCmpImpl[otype]: | 1149 if self.cond in _ifCmpImpl[otype]: |
1150 oldCond = prog.conditional | |
1151 prog.conditional = True | |
1152 #temp = prog.temp.copy() | |
650 output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output)) | 1153 output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output)) |
651 self._genTrueBody(prog, fieldVals, output, otype) | 1154 self._genTrueBody(prog, fieldVals, output, otype) |
1155 #prog.temp = temp | |
652 if self.elseBody: | 1156 if self.elseBody: |
1157 #temp = prog.temp.copy() | |
653 output.append('\n\t} else {') | 1158 output.append('\n\t} else {') |
654 self._genFalseBody(prog, fieldVals, output, otype) | 1159 self._genFalseBody(prog, fieldVals, output, otype) |
1160 #prog.temp = temp | |
655 output.append('\n\t}') | 1161 output.append('\n\t}') |
1162 prog.conditional = oldCond | |
656 else: | 1163 else: |
657 cond = prog.resolveParam(self.cond, parent, fieldVals) | 1164 cond = prog.resolveParam(self.cond, parent, fieldVals) |
658 if type(cond) is int: | 1165 if type(cond) is int: |
659 self._genConstParam(cond, prog, fieldVals, output, otype) | 1166 self._genConstParam(cond, prog, fieldVals, output, otype) |
660 else: | 1167 else: |
1168 #temp = prog.temp.copy() | |
661 output.append('\n\tif ({cond}) '.format(cond=cond) + '{') | 1169 output.append('\n\tif ({cond}) '.format(cond=cond) + '{') |
1170 oldCond = prog.conditional | |
1171 prog.conditional = True | |
662 self._genTrueBody(prog, fieldVals, output, otype) | 1172 self._genTrueBody(prog, fieldVals, output, otype) |
1173 #prog.temp = temp | |
663 if self.elseBody: | 1174 if self.elseBody: |
1175 #temp = prog.temp.copy() | |
664 output.append('\n\t} else {') | 1176 output.append('\n\t} else {') |
665 self._genFalseBody(prog, fieldVals, output, otype) | 1177 self._genFalseBody(prog, fieldVals, output, otype) |
1178 #prog.temp = temp | |
666 output.append('\n\t}') | 1179 output.append('\n\t}') |
1180 prog.conditional = oldCond | |
667 | 1181 |
668 | 1182 |
669 def __str__(self): | 1183 def __str__(self): |
670 lines = ['\n\tif'] | 1184 lines = ['\n\tif'] |
671 for op in self.body: | 1185 for op in self.body: |
677 def __init__(self): | 1191 def __init__(self): |
678 self.regs = {} | 1192 self.regs = {} |
679 self.pointers = {} | 1193 self.pointers = {} |
680 self.regArrays = {} | 1194 self.regArrays = {} |
681 self.regToArray = {} | 1195 self.regToArray = {} |
1196 self.addReg('cycles', 32) | |
1197 self.addReg('sync_cycle', 32) | |
682 | 1198 |
683 def addReg(self, name, size): | 1199 def addReg(self, name, size): |
684 self.regs[name] = size | 1200 self.regs[name] = size |
685 | 1201 |
686 def addPointer(self, name, size): | 1202 def addPointer(self, name, size, count): |
687 self.pointers[name] = size | 1203 self.pointers[name] = (size, count) |
688 | 1204 |
689 def addRegArray(self, name, size, regs): | 1205 def addRegArray(self, name, size, regs): |
690 self.regArrays[name] = (size, regs) | 1206 self.regArrays[name] = (size, regs) |
691 idx = 0 | 1207 idx = 0 |
692 if not type(regs) is int: | 1208 if not type(regs) is int: |
719 def isNamedArray(self, array): | 1235 def isNamedArray(self, array): |
720 return array in self.regArrays and type(self.regArrays[array][1]) is int | 1236 return array in self.regArrays and type(self.regArrays[array][1]) is int |
721 | 1237 |
722 def processLine(self, parts): | 1238 def processLine(self, parts): |
723 if len(parts) == 3: | 1239 if len(parts) == 3: |
724 self.addRegArray(parts[0], int(parts[1]), int(parts[2])) | 1240 if parts[1].startswith('ptr'): |
1241 self.addPointer(parts[0], parts[1][3:], int(parts[2])) | |
1242 else: | |
1243 self.addRegArray(parts[0], int(parts[1]), int(parts[2])) | |
725 elif len(parts) > 2: | 1244 elif len(parts) > 2: |
726 self.addRegArray(parts[0], int(parts[1]), parts[2:]) | 1245 self.addRegArray(parts[0], int(parts[1]), parts[2:]) |
727 else: | 1246 else: |
728 if parts[1].startswith('ptr'): | 1247 if parts[1].startswith('ptr'): |
729 self.addPointer(parts[0], int(parts[1][3:])) | 1248 self.addPointer(parts[0], parts[1][3:], 1) |
730 else: | 1249 else: |
731 self.addReg(parts[0], int(parts[1])) | 1250 self.addReg(parts[0], int(parts[1])) |
732 return self | 1251 return self |
733 | 1252 |
734 def writeHeader(self, otype, hFile): | 1253 def writeHeader(self, otype, hFile): |
735 fieldList = [] | 1254 fieldList = [] |
736 for pointer in self.pointers: | 1255 for pointer in self.pointers: |
737 hFile.write('\n\tuint{sz}_t *{nm};'.format(nm=pointer, sz=self.pointers[pointer])) | 1256 stars = '*' |
1257 ptype, count = self.pointers[pointer] | |
1258 while ptype.startswith('ptr'): | |
1259 stars += '*' | |
1260 ptype = ptype[3:] | |
1261 if ptype.isdigit(): | |
1262 ptype = 'uint{sz}_t'.format(sz=ptype) | |
1263 if count > 1: | |
1264 arr = '[{n}]'.format(n=count) | |
1265 else: | |
1266 arr = '' | |
1267 hFile.write('\n\t{ptype} {stars}{nm}{arr};'.format(nm=pointer, ptype=ptype, stars=stars, arr=arr)) | |
738 for reg in self.regs: | 1268 for reg in self.regs: |
739 if not self.isRegArrayMember(reg): | 1269 if not self.isRegArrayMember(reg): |
740 fieldList.append((self.regs[reg], 1, reg)) | 1270 fieldList.append((self.regs[reg], 1, reg)) |
741 for arr in self.regArrays: | 1271 for arr in self.regArrays: |
742 size,regs = self.regArrays[arr] | 1272 size,regs = self.regArrays[arr] |
754 class Flags: | 1284 class Flags: |
755 def __init__(self): | 1285 def __init__(self): |
756 self.flagBits = {} | 1286 self.flagBits = {} |
757 self.flagCalc = {} | 1287 self.flagCalc = {} |
758 self.flagStorage = {} | 1288 self.flagStorage = {} |
1289 self.flagOrder = [] | |
759 self.flagReg = None | 1290 self.flagReg = None |
1291 self.storageToFlags = {} | |
760 self.maxBit = -1 | 1292 self.maxBit = -1 |
761 | 1293 |
762 def processLine(self, parts): | 1294 def processLine(self, parts): |
763 if parts[0] == 'register': | 1295 if parts[0] == 'register': |
764 self.flagReg = parts[1] | 1296 self.flagReg = parts[1] |
775 if bit > self.maxBit: | 1307 if bit > self.maxBit: |
776 self.maxBit = bit | 1308 self.maxBit = bit |
777 self.flagBits[flag] = bit | 1309 self.flagBits[flag] = bit |
778 self.flagCalc[flag] = calc | 1310 self.flagCalc[flag] = calc |
779 self.flagStorage[flag] = storage | 1311 self.flagStorage[flag] = storage |
1312 storage,_,storebit = storage.partition('.') | |
1313 self.storageToFlags.setdefault(storage, []).append((storebit, flag)) | |
1314 self.flagOrder.append(flag) | |
780 return self | 1315 return self |
781 | 1316 |
782 def getStorage(self, flag): | 1317 def getStorage(self, flag): |
783 if not flag in self.flagStorage: | 1318 if not flag in self.flagStorage: |
784 raise Exception('Undefined flag ' + flag) | 1319 raise Exception('Undefined flag ' + flag) |
785 loc,_,bit = self.flagStorage[flag].partition('.') | 1320 loc,_,bit = self.flagStorage[flag].partition('.') |
786 if bit: | 1321 if bit: |
787 return (loc, int(bit)) | 1322 return (loc, int(bit)) |
788 else: | 1323 else: |
789 return loc | 1324 return loc |
1325 | |
1326 def parseFlagUpdate(self, flagString): | |
1327 last = '' | |
1328 autoUpdate = set() | |
1329 explicit = {} | |
1330 for c in flagString: | |
1331 if c.isdigit(): | |
1332 if last.isalpha(): | |
1333 num = int(c) | |
1334 if num > 1: | |
1335 raise Exception(c + ' is not a valid digit for update_flags') | |
1336 explicit[last] = num | |
1337 last = c | |
1338 else: | |
1339 raise Exception('Digit must follow flag letter in update_flags') | |
1340 else: | |
1341 if last.isalpha(): | |
1342 autoUpdate.add(last) | |
1343 last = c | |
1344 if last.isalpha(): | |
1345 autoUpdate.add(last) | |
1346 return (autoUpdate, explicit) | |
790 | 1347 |
791 def disperseFlags(self, prog, otype): | 1348 def disperseFlags(self, prog, otype): |
792 bitToFlag = [None] * (self.maxBit+1) | 1349 bitToFlag = [None] * (self.maxBit+1) |
793 src = prog.resolveReg(self.flagReg, None, {}) | 1350 src = prog.resolveReg(self.flagReg, None, {}) |
794 output = [] | 1351 output = [] |
882 else: | 1439 else: |
883 output.append('\n\tif ({src} & (1 << {srcbit})) {{\n\t\t{dst} |= 1 << {dstbit};\n\t}}'.format( | 1440 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 | 1441 src=src, dst=dst, srcbit=srcbit, dstbit=dstbit |
885 )) | 1442 )) |
886 if direct: | 1443 if direct: |
887 output.append('\n\t{dst} |= {src} & {mask}'.format( | 1444 output.append('\n\t{dst} |= {src} & {mask};'.format( |
888 dst=dst, src=src, mask=direct | 1445 dst=dst, src=src, mask=direct |
889 )) | 1446 )) |
890 return ''.join(output) | 1447 return ''.join(output) |
891 | 1448 |
892 | 1449 |
900 self.prefix = info.get('prefix', [''])[0] | 1457 self.prefix = info.get('prefix', [''])[0] |
901 self.opsize = int(info.get('opcode_size', ['8'])[0]) | 1458 self.opsize = int(info.get('opcode_size', ['8'])[0]) |
902 self.extra_tables = info.get('extra_tables', []) | 1459 self.extra_tables = info.get('extra_tables', []) |
903 self.context_type = self.prefix + 'context' | 1460 self.context_type = self.prefix + 'context' |
904 self.body = info.get('body', [None])[0] | 1461 self.body = info.get('body', [None])[0] |
1462 self.interrupt = info.get('interrupt', [None])[0] | |
1463 self.sync_cycle = info.get('sync_cycle', [None])[0] | |
905 self.includes = info.get('include', []) | 1464 self.includes = info.get('include', []) |
906 self.flags = flags | 1465 self.flags = flags |
907 self.lastDst = None | 1466 self.lastDst = None |
908 self.scopes = [] | 1467 self.scopes = [] |
909 self.currentScope = None | 1468 self.currentScope = None |
910 self.lastOp = None | 1469 self.lastOp = None |
1470 self.carryFlowDst = None | |
1471 self.lastA = None | |
1472 self.lastB = None | |
1473 self.lastBFlow = None | |
1474 self.sizeAdjust = None | |
1475 self.conditional = False | |
1476 self.declares = [] | |
1477 self.lastSize = None | |
911 | 1478 |
912 def __str__(self): | 1479 def __str__(self): |
913 pieces = [] | 1480 pieces = [] |
914 for reg in self.regs: | 1481 for reg in self.regs: |
915 pieces.append(str(self.regs[reg])) | 1482 pieces.append(str(self.regs[reg])) |
928 hFile.write('\n\ntypedef struct {') | 1495 hFile.write('\n\ntypedef struct {') |
929 hFile.write('\n\tcpu_options gen;') | 1496 hFile.write('\n\tcpu_options gen;') |
930 hFile.write('\n}} {0}options;'.format(self.prefix)) | 1497 hFile.write('\n}} {0}options;'.format(self.prefix)) |
931 hFile.write('\n\ntypedef struct {') | 1498 hFile.write('\n\ntypedef struct {') |
932 hFile.write('\n\t{0}options *opts;'.format(self.prefix)) | 1499 hFile.write('\n\t{0}options *opts;'.format(self.prefix)) |
933 hFile.write('\n\tuint32_t cycles;') | |
934 self.regs.writeHeader(otype, hFile) | 1500 self.regs.writeHeader(otype, hFile) |
935 hFile.write('\n}} {0}context;'.format(self.prefix)) | 1501 hFile.write('\n}} {0}context;'.format(self.prefix)) |
936 hFile.write('\n') | 1502 hFile.write('\n') |
1503 hFile.write('\nvoid {pre}execute({type} *context, uint32_t target_cycle);'.format(pre = self.prefix, type = self.context_type)) | |
1504 for decl in self.declares: | |
1505 hFile.write('\n' + decl) | |
937 hFile.write('\n#endif //{0}_'.format(macro)) | 1506 hFile.write('\n#endif //{0}_'.format(macro)) |
938 hFile.write('\n') | 1507 hFile.write('\n') |
939 hFile.close() | 1508 hFile.close() |
940 def build(self, otype): | 1509 |
941 body = [] | 1510 def _buildTable(self, otype, table, body, lateBody): |
942 pieces = [] | 1511 pieces = [] |
943 for include in self.includes: | 1512 opmap = [None] * (1 << self.opsize) |
944 body.append('#include "{0}"\n'.format(include)) | 1513 bodymap = {} |
945 for table in self.instructions: | 1514 if table in self.instructions: |
946 opmap = [None] * (1 << self.opsize) | |
947 bodymap = {} | |
948 instructions = self.instructions[table] | 1515 instructions = self.instructions[table] |
949 instructions.sort() | 1516 instructions.sort() |
950 for inst in instructions: | 1517 for inst in instructions: |
951 for val in inst.allValues(): | 1518 for val in inst.allValues(): |
952 if opmap[val] is None: | 1519 if opmap[val] is None: |
955 self.needFlagCoalesce = False | 1522 self.needFlagCoalesce = False |
956 self.needFlagDisperse = False | 1523 self.needFlagDisperse = False |
957 self.lastOp = None | 1524 self.lastOp = None |
958 opmap[val] = inst.generateName(val) | 1525 opmap[val] = inst.generateName(val) |
959 bodymap[val] = inst.generateBody(val, self, otype) | 1526 bodymap[val] = inst.generateBody(val, self, otype) |
960 | 1527 |
961 pieces.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix)) | 1528 if self.dispatch == 'call': |
962 pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) | 1529 pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) |
963 for inst in range(0, len(opmap)): | 1530 for inst in range(0, len(opmap)): |
964 op = opmap[inst] | 1531 op = opmap[inst] |
965 if op is None: | 1532 if op is None: |
966 pieces.append('\n\tunimplemented,') | 1533 pieces.append('\n\tunimplemented,') |
967 else: | 1534 else: |
968 pieces.append('\n\t' + op + ',') | 1535 pieces.append('\n\t' + op + ',') |
969 body.append(bodymap[inst]) | 1536 body.append(bodymap[inst]) |
970 pieces.append('\n};') | 1537 pieces.append('\n};') |
971 if self.body in self.subroutines: | 1538 elif self.dispatch == 'goto': |
1539 body.append('\n\tstatic void *impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) | |
1540 for inst in range(0, len(opmap)): | |
1541 op = opmap[inst] | |
1542 if op is None: | |
1543 body.append('\n\t\t&&unimplemented,') | |
1544 else: | |
1545 body.append('\n\t\t&&' + op + ',') | |
1546 lateBody.append(bodymap[inst]) | |
1547 body.append('\n\t};') | |
1548 else: | |
1549 raise Exception("unimplmeneted dispatch type " + self.dispatch) | |
1550 body.extend(pieces) | |
1551 | |
1552 def nextInstruction(self, otype): | |
1553 output = [] | |
1554 if self.dispatch == 'goto': | |
1555 if self.interrupt in self.subroutines: | |
1556 output.append('\n\tif (context->cycles >= context->sync_cycle) {') | |
1557 output.append('\n\tif (context->cycles >= target_cycle) { return; }') | |
1558 if self.interrupt in self.subroutines: | |
1559 self.meta = {} | |
1560 self.temp = {} | |
1561 self.subroutines[self.interrupt].inline(self, [], output, otype, None) | |
1562 output.append('\n\t}') | |
1563 | |
1564 self.meta = {} | |
1565 self.temp = {} | |
1566 self.subroutines[self.body].inline(self, [], output, otype, None) | |
1567 return output | |
1568 | |
1569 def build(self, otype): | |
1570 body = [] | |
1571 pieces = [] | |
1572 for include in self.includes: | |
1573 body.append('#include "{0}"\n'.format(include)) | |
1574 if self.dispatch == 'call': | |
1575 body.append('\nstatic void unimplemented({pre}context *context, uint32_t target_cycle)'.format(pre = self.prefix)) | |
1576 body.append('\n{') | |
1577 body.append('\n\tfatal_error("Unimplemented instruction\\n");') | |
1578 body.append('\n}\n') | |
1579 body.append('\ntypedef void (*impl_fun)({pre}context *context, uint32_t target_cycle);'.format(pre=self.prefix)) | |
1580 for table in self.extra_tables: | |
1581 body.append('\nstatic impl_fun impl_{name}[{sz}];'.format(name = table, sz=(1 << self.opsize))) | |
1582 body.append('\nstatic impl_fun impl_main[{sz}];'.format(sz=(1 << self.opsize))) | |
1583 elif self.dispatch == 'goto': | |
1584 body.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type)) | |
1585 body.append('\n{') | |
1586 | |
1587 for table in self.extra_tables: | |
1588 self._buildTable(otype, table, body, pieces) | |
1589 self._buildTable(otype, 'main', body, pieces) | |
1590 if self.dispatch == 'call' and 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)) | 1591 pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type)) |
973 pieces.append('\n{') | 1592 pieces.append('\n{') |
1593 pieces.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle)) | |
974 pieces.append('\n\twhile (context->cycles < target_cycle)') | 1594 pieces.append('\n\twhile (context->cycles < target_cycle)') |
975 pieces.append('\n\t{') | 1595 pieces.append('\n\t{') |
1596 if self.interrupt in self.subroutines: | |
1597 pieces.append('\n\t\tif (context->cycles >= context->sync_cycle) {') | |
1598 self.meta = {} | |
1599 self.temp = {} | |
1600 intpieces = [] | |
1601 self.subroutines[self.interrupt].inline(self, [], intpieces, otype, None) | |
1602 for size in self.temp: | |
1603 pieces.append('\n\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size)) | |
1604 pieces += intpieces | |
1605 pieces.append('\n\t\t}') | |
976 self.meta = {} | 1606 self.meta = {} |
977 self.temp = {} | 1607 self.temp = {} |
978 self.subroutines[self.body].inline(self, [], pieces, otype, None) | 1608 self.subroutines[self.body].inline(self, [], pieces, otype, None) |
979 pieces.append('\n\t}') | 1609 pieces.append('\n\t}') |
980 pieces.append('\n}') | 1610 pieces.append('\n}') |
981 body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix)) | 1611 elif self.dispatch == 'goto': |
982 body.append('\n{') | 1612 body.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle)) |
983 body.append('\n\tfatal_error("Unimplemented instruction");') | 1613 body += self.nextInstruction(otype) |
984 body.append('\n}\n') | 1614 pieces.append('\nunimplemented:') |
1615 pieces.append('\n\tfatal_error("Unimplemented instruction\\n");') | |
1616 pieces.append('\n}') | |
985 return ''.join(body) + ''.join(pieces) | 1617 return ''.join(body) + ''.join(pieces) |
986 | 1618 |
987 def checkBool(self, name): | 1619 def checkBool(self, name): |
988 if not name in self.booleans: | 1620 if not name in self.booleans: |
989 raise Exception(name + ' is not a defined boolean flag') | 1621 raise Exception(name + ' is not a defined boolean flag') |
990 return self.booleans[name] | 1622 return self.booleans[name] |
991 | 1623 |
992 def getTemp(self, size): | 1624 def getTemp(self, size): |
993 if size in self.temp: | 1625 if size in self.temp: |
994 return ('', self.temp[size]) | 1626 return ('', self.temp[size]) |
995 self.temp[size] = 'tmp{sz}'.format(sz=size); | 1627 self.temp[size] = 'gen_tmp{sz}__'.format(sz=size); |
996 return ('\n\tuint{sz}_t tmp{sz};'.format(sz=size), self.temp[size]) | 1628 return ('', self.temp[size]) |
997 | 1629 |
998 def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False): | 1630 def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False): |
999 keepGoing = True | 1631 keepGoing = True |
1000 while keepGoing: | 1632 while keepGoing: |
1001 keepGoing = False | 1633 keepGoing = False |
1011 if parent: | 1643 if parent: |
1012 if param in parent.regValues and allowConstant: | 1644 if param in parent.regValues and allowConstant: |
1013 return parent.regValues[param] | 1645 return parent.regValues[param] |
1014 maybeLocal = parent.resolveLocal(param) | 1646 maybeLocal = parent.resolveLocal(param) |
1015 if maybeLocal: | 1647 if maybeLocal: |
1648 if isdst: | |
1649 self.lastDst = param | |
1650 self.lastSize = None | |
1016 return maybeLocal | 1651 return maybeLocal |
1017 if param in fieldVals: | 1652 if param in fieldVals: |
1018 param = fieldVals[param] | 1653 param = fieldVals[param] |
1654 fieldVals = {} | |
1655 keepGoing = True | |
1019 elif param in self.meta: | 1656 elif param in self.meta: |
1020 param = self.meta[param] | 1657 param = self.meta[param] |
1021 keepGoing = True | 1658 keepGoing = True |
1022 elif self.isReg(param): | 1659 elif self.isReg(param): |
1023 param = self.resolveReg(param, parent, fieldVals, isdst) | 1660 return self.resolveReg(param, parent, fieldVals, isdst) |
1661 elif param in self.regs.pointers: | |
1662 return 'context->' + param | |
1663 if isdst: | |
1664 self.lastDst = param | |
1665 self.lastSize = None | |
1024 return param | 1666 return param |
1025 | 1667 |
1026 def isReg(self, name): | 1668 def isReg(self, name): |
1027 if not type(name) is str: | 1669 if not type(name) is str: |
1028 return False | 1670 return False |
1068 return ret | 1710 return ret |
1069 | 1711 |
1070 | 1712 |
1071 | 1713 |
1072 def paramSize(self, name): | 1714 def paramSize(self, name): |
1073 size = self.currentScope.localSize(name) | 1715 if name in self.meta: |
1074 if size: | 1716 return self.paramSize(self.meta[name]) |
1075 return size | 1717 for i in range(len(self.scopes) -1, -1, -1): |
1718 size = self.scopes[i].localSize(name) | |
1719 if size: | |
1720 return size | |
1076 begin,sep,_ = name.partition('.') | 1721 begin,sep,_ = name.partition('.') |
1077 if sep and self.regs.isRegArray(begin): | 1722 if sep and self.regs.isRegArray(begin): |
1078 return self.regs.regArrays[begin][0] | 1723 return self.regs.regArrays[begin][0] |
1079 if self.regs.isReg(name): | 1724 if self.regs.isReg(name): |
1080 return self.regs.regs[name] | 1725 return self.regs.regs[name] |
1081 return 32 | 1726 return 32 |
1082 | 1727 |
1728 def getLastSize(self): | |
1729 if self.lastSize: | |
1730 return self.lastSize | |
1731 return self.paramSize(self.lastDst) | |
1732 | |
1083 def pushScope(self, scope): | 1733 def pushScope(self, scope): |
1084 self.scopes.append(scope) | 1734 self.scopes.append(scope) |
1085 self.currentScope = scope | 1735 self.currentScope = scope |
1086 | 1736 |
1087 def popScope(self): | 1737 def popScope(self): |
1090 return ret | 1740 return ret |
1091 | 1741 |
1092 def getRootScope(self): | 1742 def getRootScope(self): |
1093 return self.scopes[0] | 1743 return self.scopes[0] |
1094 | 1744 |
1095 def parse(f): | 1745 def parse(args): |
1746 f = args.source | |
1096 instructions = {} | 1747 instructions = {} |
1097 subroutines = {} | 1748 subroutines = {} |
1098 registers = None | 1749 registers = None |
1099 flags = None | 1750 flags = None |
1751 declares = [] | |
1100 errors = [] | 1752 errors = [] |
1101 info = {} | 1753 info = {} |
1102 line_num = 0 | 1754 line_num = 0 |
1103 cur_object = None | 1755 cur_object = None |
1104 for line in f: | 1756 for line in f: |
1106 line,_,comment = line.partition('#') | 1758 line,_,comment = line.partition('#') |
1107 if not line.strip(): | 1759 if not line.strip(): |
1108 continue | 1760 continue |
1109 if line[0].isspace(): | 1761 if line[0].isspace(): |
1110 if not cur_object is None: | 1762 if not cur_object is None: |
1111 parts = [el.strip() for el in line.split(' ')] | 1763 sep = True |
1764 parts = [] | |
1765 while sep: | |
1766 before,sep,after = line.partition('"') | |
1767 before = before.strip() | |
1768 if before: | |
1769 parts += [el.strip() for el in before.split(' ')] | |
1770 if sep: | |
1771 #TODO: deal with escaped quotes | |
1772 inside,sep,after = after.partition('"') | |
1773 parts.append('"' + inside + '"') | |
1774 line = after | |
1112 if type(cur_object) is dict: | 1775 if type(cur_object) is dict: |
1113 cur_object[parts[0]] = parts[1:] | 1776 cur_object[parts[0]] = parts[1:] |
1777 elif type(cur_object) is list: | |
1778 cur_object.append(' '.join(parts)) | |
1114 else: | 1779 else: |
1115 cur_object = cur_object.processLine(parts) | 1780 cur_object = cur_object.processLine(parts) |
1116 | 1781 |
1117 # if type(cur_object) is Registers: | 1782 # if type(cur_object) is Registers: |
1118 # if len(parts) > 2: | 1783 # if len(parts) > 2: |
1166 cur_object = info | 1831 cur_object = info |
1167 elif line.strip() == 'flags': | 1832 elif line.strip() == 'flags': |
1168 if flags is None: | 1833 if flags is None: |
1169 flags = Flags() | 1834 flags = Flags() |
1170 cur_object = flags | 1835 cur_object = flags |
1836 elif line.strip() == 'declare': | |
1837 cur_object = declares | |
1171 else: | 1838 else: |
1172 cur_object = SubRoutine(line.strip()) | 1839 cur_object = SubRoutine(line.strip()) |
1173 subroutines[cur_object.name] = cur_object | 1840 subroutines[cur_object.name] = cur_object |
1174 if errors: | 1841 if errors: |
1175 print(errors) | 1842 print(errors) |
1176 else: | 1843 else: |
1177 p = Program(registers, instructions, subroutines, info, flags) | 1844 p = Program(registers, instructions, subroutines, info, flags) |
1845 p.dispatch = args.dispatch | |
1846 p.declares = declares | |
1178 p.booleans['dynarec'] = False | 1847 p.booleans['dynarec'] = False |
1179 p.booleans['interp'] = True | 1848 p.booleans['interp'] = True |
1849 if args.define: | |
1850 for define in args.define: | |
1851 name,sep,val = define.partition('=') | |
1852 name = name.strip() | |
1853 val = val.strip() | |
1854 if sep: | |
1855 p.booleans[name] = bool(val) | |
1856 else: | |
1857 p.booleans[name] = True | |
1180 | 1858 |
1181 if 'header' in info: | 1859 if 'header' in info: |
1182 print('#include "{0}"'.format(info['header'][0])) | 1860 print('#include "{0}"'.format(info['header'][0])) |
1183 p.writeHeader('c', info['header'][0]) | 1861 p.writeHeader('c', info['header'][0]) |
1184 print('#include "util.h"') | 1862 print('#include "util.h"') |
1185 print('#include <stdlib.h>') | 1863 print('#include <stdlib.h>') |
1186 print(p.build('c')) | 1864 print(p.build('c')) |
1187 | 1865 |
1188 def main(argv): | 1866 def main(argv): |
1189 f = open(argv[1]) | 1867 from argparse import ArgumentParser, FileType |
1190 parse(f) | 1868 argParser = ArgumentParser(description='CPU emulator DSL compiler') |
1869 argParser.add_argument('source', type=FileType('r')) | |
1870 argParser.add_argument('-D', '--define', action='append') | |
1871 argParser.add_argument('-d', '--dispatch', choices=('call', 'switch', 'goto'), default='call') | |
1872 parse(argParser.parse_args(argv[1:])) | |
1191 | 1873 |
1192 if __name__ == '__main__': | 1874 if __name__ == '__main__': |
1193 from sys import argv | 1875 from sys import argv |
1194 main(argv) | 1876 main(argv) |