Mercurial > repos > blastem
diff 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 |
line wrap: on
line diff
--- a/cpu_dsl.py Sat Jan 05 00:58:08 2019 -0800 +++ b/cpu_dsl.py Sat Jan 15 13:15:21 2022 -0800 @@ -20,6 +20,14 @@ self.addOp(NormalOp(parts)) return self + def processOps(self, prog, fieldVals, output, otype, oplist): + for i in range(0, len(oplist)): + if i + 1 < len(oplist) and oplist[i+1].op == 'update_flags': + flagUpdates, _ = prog.flags.parseFlagUpdate(oplist[i+1].params[0]) + else: + flagUpdates = None + oplist[i].generate(prog, self, fieldVals, output, otype, flagUpdates) + def resolveLocal(self, name): return None @@ -40,6 +48,7 @@ self.regValues = {} self.varyingBits = 0 self.invalidFieldValues = {} + self.invalidCombos = [] self.newLocals = [] for field in fields: self.varyingBits += fields[field][1] @@ -47,12 +56,20 @@ def addOp(self, op): if op.op == 'local': name = op.params[0] - size = op.params[1] + size = int(op.params[1]) self.locals[name] = size elif op.op == 'invalid': - name = op.params[0] - value = int(op.params[1]) - self.invalidFieldValues.setdefault(name, set()).add(value) + if len(op.params) < 3: + name = op.params[0] + value = int(op.params[1]) + self.invalidFieldValues.setdefault(name, set()).add(value) + else: + vmap = {} + for i in range(0, len(op.params), 2): + name = op.params[i] + value = int(op.params[i+1]) + vmap[name] = value + self.invalidCombos.append(vmap) else: self.implementation.append(op) @@ -81,12 +98,29 @@ for i in range(0, 1 << self.varyingBits): iword = self.value doIt = True + combos = [] + for combo in self.invalidCombos: + combos.append(dict(combo)) for field in self.fields: shift,bits = self.fields[field] val = i & ((1 << bits) - 1) if field in self.invalidFieldValues and val in self.invalidFieldValues[field]: doIt = False break + nextcombos = [] + for combo in combos: + if field in combo: + if combo[field] == val: + del combo[field] + if not combo: + doIt = False + break + else: + continue + nextcombos.append(combo) + combos = nextcombos + if not doIt: + break i >>= bits iword |= val << shift if doIt: @@ -121,16 +155,25 @@ output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)) self.newLocals = [] fieldVals,_ = self.getFieldVals(value) - for op in self.implementation: - op.generate(prog, self, fieldVals, output, otype) - begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{' + self.processOps(prog, fieldVals, output, otype, self.implementation) + + if prog.dispatch == 'call': + begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context, uint32_t target_cycle)\n{' + elif prog.dispatch == 'goto': + begin = '\n' + self.generateName(value) + ': {' + else: + raise Exception('Unsupported dispatch type ' + prog.dispatch) if prog.needFlagCoalesce: begin += prog.flags.coalesceFlags(prog, otype) if prog.needFlagDisperse: output.append(prog.flags.disperseFlags(prog, otype)) for var in self.newLocals: begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var) + for size in prog.temp: + begin += '\n\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size) prog.popScope() + if prog.dispatch == 'goto': + output += prog.nextInstruction(otype) return begin + ''.join(output) + '\n}' def __str__(self): @@ -150,16 +193,17 @@ self.arg_map = {} self.locals = {} self.regValues = {} + self.argValues = {} def addOp(self, op): if op.op == 'arg': name = op.params[0] - size = op.params[1] + size = int(op.params[1]) self.arg_map[name] = len(self.args) self.args.append((name, size)) elif op.op == 'local': name = op.params[0] - size = op.params[1] + size = int(op.params[1]) self.locals[name] = size else: self.implementation.append(op) @@ -173,7 +217,12 @@ self.locals[name] = size def localSize(self, name): - return self.locals.get(name) + if name in self.locals: + return self.locals[name] + if name in self.arg_map: + argIndex = self.arg_map[name] + return self.args[argIndex][1] + return None def inline(self, prog, params, output, otype, parent): if len(params) != len(self.args): @@ -189,8 +238,8 @@ for name in self.locals: size = self.locals[name] output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name)) - for op in self.implementation: - op.generate(prog, self, argValues, output, otype) + self.argValues = argValues + self.processOps(prog, argValues, output, otype, self.implementation) prog.popScope() def __str__(self): @@ -209,24 +258,115 @@ self.impls = {} self.outOp = () def cBinaryOperator(self, op): - def _impl(prog, params): + def _impl(prog, params, rawParams, flagUpdates): if op == '-': a = params[1] b = params[0] else: a = params[0] b = params[1] - return '\n\t{dst} = {a} {op} {b};'.format( - dst = params[2], a = a, b = b, op = op - ) + needsSizeAdjust = False + if len(params) > 3: + size = params[3] + if size == 0: + size = 8 + elif size == 1: + size = 16 + else: + size = 32 + prog.lastSize = size + destSize = prog.paramSize(rawParams[2]) + if destSize > size: + needsSizeAdjust = True + prog.sizeAdjust = size + needsCarry = needsOflow = needsHalf = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + elif calc == 'half-carry': + needsHalf = True + elif calc == 'overflow': + needsOflow = True + decl = '' + if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): + if len(params) <= 3: + size = prog.paramSize(rawParams[2]) + if needsCarry and op != 'lsr': + size *= 2 + decl,name = prog.getTemp(size) + dst = prog.carryFlowDst = name + prog.lastA = a + prog.lastB = b + if size == 64: + a = '((uint64_t){a})'.format(a=a) + b = '((uint64_t){b})'.format(b=b) + prog.lastBFlow = b if op == '-' else '(~{b})'.format(b=b) + elif needsSizeAdjust: + decl,name = prog.getTemp(size) + dst = params[2] + return '{decl}\n\t{tmp} = ({a} & {mask}) {op} ({b} & {mask});\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( + decl = decl, tmp = name, a = a, b = b, op = op, dst = dst, mask = ((1 << size) - 1) + ) + else: + dst = params[2] + if needsSizeAdjust: + return decl + '\n\t{dst} = ({a} & {mask}) {op} ({b} & {mask});'.format( + dst = dst, a = a, b = b, op = op, mask = (1 << prog.sizeAdjust) - 1 + ) + else: + return decl + '\n\t{dst} = {a} {op} {b};'.format( + dst = dst, a = a, b = b, op = op + ) self.impls['c'] = _impl self.outOp = (2,) return self def cUnaryOperator(self, op): - def _impl(prog, params): - return '\n\t{dst} = {op}{a};'.format( - dst = params[1], a = params[0], op = op - ) + def _impl(prog, params, rawParams, flagUpdates): + dst = params[1] + decl = '' + needsSizeAdjust = False + if len(params) > 2: + size = params[2] + if size == 0: + size = 8 + elif size == 1: + size = 16 + else: + size = 32 + prog.lastSize = size + destSize = prog.paramSize(rawParams[1]) + if destSize > size: + needsSizeAdjust = True + prog.sizeAdjust = size + if op == '-': + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + elif calc == 'half-carry': + needsHalf = True + elif calc == 'overflow': + needsOflow = True + if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): + size = prog.paramSize(rawParams[1]) + if needsCarry: + size *= 2 + decl,name = prog.getTemp(size) + dst = prog.carryFlowDst = name + prog.lastA = 0 + prog.lastB = params[0] + prog.lastBFlow = params[0] + if needsSizeAdjust: + return decl + '\n\t{dst} = ({dst} & ~{mask}) | (({op}{a}) & {mask});'.format( + dst = dst, a = params[0], op = op, mask = (1 << prog.sizeAdjust) - 1 + ) + else: + return decl + '\n\t{dst} = {op}{a};'.format( + dst = dst, a = params[0], op = op + ) self.impls['c'] = _impl self.outOp = (1,) return self @@ -244,11 +384,21 @@ return not self.evalFun is None def numArgs(self): return self.evalFun.__code__.co_argcount - def generate(self, otype, prog, params, rawParams): + def numParams(self): + if self.outOp: + params = max(self.outOp) + 1 + else: + params = 0 + if self.evalFun: + params = max(params, self.numArgs()) + return params + def generate(self, otype, prog, params, rawParams, flagUpdates): if self.impls[otype].__code__.co_argcount == 2: return self.impls[otype](prog, params) + elif self.impls[otype].__code__.co_argcount == 3: + return self.impls[otype](prog, params, rawParams) else: - return self.impls[otype](prog, params, rawParams) + return self.impls[otype](prog, params, rawParams, flagUpdates) def _xchgCImpl(prog, params, rawParams): @@ -261,50 +411,54 @@ table = 'main' else: table = params[1] - return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0]) + if prog.dispatch == 'call': + return '\n\timpl_{tbl}[{op}](context, target_cycle);'.format(tbl = table, op = params[0]) + elif prog.dispatch == 'goto': + return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0]) + else: + raise Exception('Unsupported dispatch type ' + prog.dispatch) def _updateFlagsCImpl(prog, params, rawParams): - i = 0 - last = '' - autoUpdate = set() - explicit = {} - for c in params[0]: - if c.isdigit(): - if last.isalpha(): - num = int(c) - if num > 1: - raise Exception(c + ' is not a valid digit for update_flags') - explicit[last] = num - last = c - else: - raise Exception('Digit must follow flag letter in update_flags') - else: - if last.isalpha(): - autoUpdate.add(last) - last = c - if last.isalpha(): - autoUpdate.add(last) + autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0]) output = [] - #TODO: handle autoUpdate flags + parity = None + directFlags = {} for flag in autoUpdate: calc = prog.flags.flagCalc[flag] calc,_,resultBit = calc.partition('-') - lastDst = prog.resolveParam(prog.lastDst, None, {}) + if prog.carryFlowDst: + lastDst = prog.carryFlowDst + else: + lastDst = prog.resolveParam(prog.lastDst, prog.currentScope, {}) storage = prog.flags.getStorage(flag) - if calc == 'bit' or calc == 'sign': + if calc == 'bit' or calc == 'sign' or calc == 'carry' or calc == 'half' or calc == 'overflow': + myRes = lastDst if calc == 'sign': - resultBit = prog.paramSize(prog.lastDst) - 1 + resultBit = prog.getLastSize() - 1 + elif calc == 'carry': + if prog.lastOp.op in ('asr', 'lsr'): + resultBit = 0 + myRes = prog.lastA + else: + resultBit = prog.getLastSize() + if prog.lastOp.op == 'ror': + resultBit -= 1 + elif calc == 'half': + resultBit = prog.getLastSize() - 4 + myRes = '({a} ^ {b} ^ {res})'.format(a = prog.lastA, b = prog.lastB, res = lastDst) + elif calc == 'overflow': + resultBit = prog.getLastSize() - 1 + myRes = '((({a} ^ {b})) & ({a} ^ {res}))'.format(a = prog.lastA, b = prog.lastBFlow, res = lastDst) else: - resultBit = int(resultBit) + #Note: offsetting this by the operation size - 8 makes sense for the Z80 + #but might not for other CPUs with this kind of fixed bit flag behavior + resultBit = int(resultBit) + prog.getLastSize() - 8 if type(storage) is tuple: reg,storageBit = storage - reg = prog.resolveParam(reg, None, {}) if storageBit == resultBit: - #TODO: optimize this case - output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format( - reg = reg, mask = 1 << resultBit, res = lastDst - )) + directFlags.setdefault((reg, myRes), []).append(resultBit) else: + reg = prog.resolveParam(reg, None, {}) if resultBit > storageBit: op = '>>' shift = resultBit - storageBit @@ -312,34 +466,83 @@ op = '<<' shift = storageBit - resultBit output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} {op} {shift}U & {mask}U);'.format( - reg = reg, mask = 1 << storageBit, res = lastDst, op = op, shift = shift + reg = reg, mask = 1 << storageBit, res = myRes, op = op, shift = shift )) else: reg = prog.resolveParam(storage, None, {}) - output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=lastDst, mask = 1 << resultBit)) + maxBit = prog.paramSize(storage) - 1 + if resultBit > maxBit: + output.append('\n\t{reg} = {res} >> {shift} & {mask}U;'.format(reg=reg, res=myRes, shift = resultBit - maxBit, mask = 1 << maxBit)) + else: + output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=myRes, mask = 1 << resultBit)) elif calc == 'zero': + if prog.carryFlowDst: + realSize = prog.getLastSize() + if realSize != prog.paramSize(prog.carryFlowDst): + lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1) if type(storage) is tuple: reg,storageBit = storage reg = prog.resolveParam(reg, None, {}) output.append('\n\t{reg} = {res} ? ({reg} & {mask}U) : ({reg} | {bit}U);'.format( reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit )) - elif prog.paramSize(prog.lastDst) > prog.paramSize(storage): - reg = prog.resolveParam(storage, None, {}) - output.append('\n\t{reg} = {res} != 0;'.format( - reg = reg, res = lastDst - )) else: reg = prog.resolveParam(storage, None, {}) - output.append('\n\t{reg} = {res};'.format(reg = reg, res = lastDst)) - elif calc == 'half-carry': - pass - elif calc == 'carry': - pass - elif calc == 'overflow': - pass + output.append('\n\t{reg} = {res} == 0;'.format( + reg = reg, res = lastDst + )) elif calc == 'parity': - pass + parity = storage + paritySize = prog.getLastSize() + if prog.carryFlowDst: + parityDst = paritySrc = prog.carryFlowDst + else: + paritySrc = lastDst + decl,name = prog.getTemp(paritySize) + output.append(decl) + parityDst = name + else: + raise Exception('Unknown flag calc type: ' + calc) + for reg, myRes in directFlags: + bits = directFlags[(reg, myRes)] + resolved = prog.resolveParam(reg, None, {}) + if len(bits) == len(prog.flags.storageToFlags[reg]): + output.append('\n\t{reg} = {res};'.format(reg = resolved, res = myRes)) + else: + mask = 0 + for bit in bits: + mask |= 1 << bit + output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format( + reg = resolved, mask = mask, res = myRes + )) + if prog.carryFlowDst: + if prog.lastOp.op != 'cmp': + if prog.sizeAdjust: + output.append('\n\t{dst} = ({dst} & ~{mask}) | ({tmpdst} & {mask});'.format( + dst = prog.resolveParam(prog.lastDst, prog.currentScope, {}), tmpdst = prog.carryFlowDst, mask = ((1 << prog.sizeAdjust) - 1) + )) + prog.sizeAdjust = None + else: + output.append('\n\t{dst} = {tmpdst};'.format(dst = prog.resolveParam(prog.lastDst, prog.currentScope, {}), tmpdst = prog.carryFlowDst)) + prog.carryFlowDst = None + if parity: + if paritySize > 8: + if paritySize > 16: + output.append('\n\t{dst} = {src} ^ ({src} >> 16);'.format(dst=parityDst, src=paritySrc)) + paritySrc = parityDst + output.append('\n\t{dst} = {src} ^ ({src} >> 8);'.format(dst=parityDst, src=paritySrc)) + paritySrc = parityDst + output.append('\n\t{dst} = ({src} ^ ({src} >> 4)) & 0xF;'.format(dst=parityDst, src=paritySrc)) + if type(parity) is tuple: + reg,bit = parity + reg = prog.resolveParam(reg, None, {}) + output.append('\n\t{flag} = ({flag} & ~{mask}U) | ((0x6996 >> {parity}) << {bit} & {mask}U);'.format( + flag=reg, mask = 1 << bit, bit = bit, parity = parityDst + )) + else: + reg = prog.resolveParam(parity, None, {}) + output.append('\n\t{flag} = 0x9669 >> {parity} & 1;'.format(flag=reg, parity=parityDst)) + #TODO: combine explicit flags targeting the same storage location for flag in explicit: location = prog.flags.getStorage(flag) @@ -358,31 +561,276 @@ output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag])) return ''.join(output) -def _cmpCImpl(prog, params): - size = prog.paramSize(params[1]) +def _cmpCImpl(prog, params, rawParams, flagUpdates): + size = prog.paramSize(rawParams[1]) + needsCarry = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + break + if needsCarry: + size *= 2 tmpvar = 'cmp_tmp{sz}__'.format(sz=size) - typename = '' + if flagUpdates: + prog.carryFlowDst = tmpvar + prog.lastA = params[1] + prog.lastB = params[0] + prog.lastBFlow = params[0] scope = prog.getRootScope() if not scope.resolveLocal(tmpvar): scope.addLocal(tmpvar, size) - prog.lastDst = tmpvar + prog.lastDst = rawParams[1] + if len(params) > 2: + size = params[2] + if size == 0: + size = 8 + elif size == 1: + size = 16 + else: + size = 32 + prog.lastSize = size + else: + prog.lastSize = None return '\n\t{var} = {b} - {a};'.format(var = tmpvar, a = params[0], b = params[1]) -def _asrCImpl(prog, params, rawParams): - shiftSize = prog.paramSize(rawParams[0]) - mask = 1 << (shiftSize - 1) - return '\n\t{dst} = ({a} >> {b}) | ({a} & {mask});'.format(a = params[0], b = params[1], dst = params[2], mask = mask) - +def _asrCImpl(prog, params, rawParams, flagUpdates): + needsCarry = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + decl = '' + size = prog.paramSize(rawParams[2]) + if needsCarry: + decl,name = prog.getTemp(size * 2) + dst = prog.carryFlowDst = name + prog.lastA = params[0] + else: + dst = params[2] + mask = 1 << (size - 1) + return decl + '\n\t{dst} = ({a} >> {b}) | ({a} & {mask} ? 0xFFFFFFFFU << ({size} - {b}) : 0);'.format( + a = params[0], b = params[1], dst = dst, mask = mask, size=size) + +def _sext(size, src): + if size == 16: + return src | 0xFF00 if src & 0x80 else src & 0x7F + else: + return src | 0xFFFF0000 if src & 0x8000 else src & 0x7FFF + +def _sextCImpl(prog, params, rawParms): + if params[0] == 16: + fmt = '\n\t{dst} = {src} & 0x80 ? {src} | 0xFF00 : {src} & 0x7F;' + else: + fmt = '\n\t{dst} = {src} & 0x8000 ? {src} | 0xFFFF0000 : {src} & 0x7FFF;' + return fmt.format(src=params[1], dst=params[2]) + +def _getCarryCheck(prog): + carryFlag = None + for flag in prog.flags.flagOrder: + if prog.flags.flagCalc[flag] == 'carry': + carryFlag = flag + break + if carryFlag is None: + raise Exception('adc requires a defined carry flag') + carryStorage = prog.flags.getStorage(carryFlag) + if type(carryStorage) is tuple: + reg,bit = carryStorage + reg = prog.resolveReg(reg, None, (), False) + return '({reg} & 1 << {bit})'.format(reg=reg, bit=bit) + else: + return prog.resolveReg(carryStorage, None, (), False) + +def _adcCImpl(prog, params, rawParams, flagUpdates): + needsSizeAdjust = False + if len(params) > 3: + size = params[3] + if size == 0: + size = 8 + elif size == 1: + size = 16 + else: + size = 32 + prog.lastSize = size + destSize = prog.paramSize(rawParams[2]) + if destSize > size: + needsSizeAdjust = True + prog.sizeAdjust = size + needsCarry = needsOflow = needsHalf = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + elif calc == 'half-carry': + needsHalf = True + elif calc == 'overflow': + needsOflow = True + decl = '' + carryCheck = _getCarryCheck(prog) + vals = '1 : 0' + if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): + if len(params) <= 3: + size = prog.paramSize(rawParams[2]) + if needsCarry: + size *= 2 + decl,name = prog.getTemp(size) + dst = prog.carryFlowDst = name + prog.lastA = params[0] + prog.lastB = params[1] + prog.lastBFlow = '(~{b})'.format(b=params[1]) + if size == 64: + params[0] = '((uint64_t){a})'.format(a=params[0]) + params[1] = '((uint64_t){b})'.format(b=params[1]) + vals = '((uint64_t)1) : ((uint64_t)0)' + elif needsSizeAdjust: + decl,name = prog.getTemp(size) + dst = params[2] + return '{decl}\n\t{tmp} = ({a} & {mask}) + ({b} & {mask}) + ({check} ? 1 : 0);\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( + decl = decl, tmp = name, a = a, b = b, op = op, dst = dst, mask = ((1 << size) - 1), check = carryCheck + ) + else: + dst = params[2] + return decl + '\n\t{dst} = {a} + {b} + ({check} ? {vals});'.format(dst = dst, + a = params[0], b = params[1], check = carryCheck, vals = vals + ) + +def _sbcCImpl(prog, params, rawParams, flagUpdates): + needsSizeAdjust = False + if len(params) > 3: + size = params[3] + if size == 0: + size = 8 + elif size == 1: + size = 16 + else: + size = 32 + prog.lastSize = size + destSize = prog.paramSize(rawParams[2]) + if destSize > size: + needsSizeAdjust = True + prog.sizeAdjust = size + needsCarry = needsOflow = needsHalf = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + elif calc == 'half-carry': + needsHalf = True + elif calc == 'overflow': + needsOflow = True + decl = '' + carryCheck = _getCarryCheck(prog) + vals = '1 : 0' + if needsCarry or needsOflow or needsHalf or (flagUpdates and needsSizeAdjust): + size = prog.paramSize(rawParams[2]) + if needsCarry: + size *= 2 + decl,name = prog.getTemp(size) + dst = prog.carryFlowDst = name + prog.lastA = params[1] + prog.lastB = params[0] + prog.lastBFlow = params[0] + if size == 64: + params[1] = '((uint64_t){a})'.format(a=params[1]) + params[0] = '((uint64_t){b})'.format(b=params[0]) + vals = '((uint64_t)1) : ((uint64_t)0)' + elif needsSizeAdjust: + decl,name = prog.getTemp(size) + dst = params[2] + return '{decl}\n\t{tmp} = ({b} & {mask}) - ({a} & {mask}) - ({check} ? 1 : 0);\n\t{dst} = ({dst} & ~{mask}) | {tmp};'.format( + decl = decl, tmp = name, a = params[0], b = params[1], op = op, dst = dst, mask = ((1 << size) - 1), check = carryCheck + ) + else: + dst = params[2] + return decl + '\n\t{dst} = {b} - {a} - ({check} ? {vals});'.format(dst = dst, + a = params[0], b = params[1], check=_getCarryCheck(prog), vals = vals + ) + +def _rolCImpl(prog, params, rawParams, flagUpdates): + needsCarry = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + decl = '' + size = prog.paramSize(rawParams[2]) + if needsCarry: + decl,name = prog.getTemp(size * 2) + dst = prog.carryFlowDst = name + else: + dst = params[2] + return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} - {b});'.format(dst = dst, + a = params[0], b = params[1], size=size + ) + +def _rlcCImpl(prog, params, rawParams, flagUpdates): + needsCarry = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + decl = '' + carryCheck = _getCarryCheck(prog) + size = prog.paramSize(rawParams[2]) + if needsCarry: + decl,name = prog.getTemp(size * 2) + dst = prog.carryFlowDst = name + else: + dst = params[2] + return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({b} - 1);'.format(dst = dst, + a = params[0], b = params[1], size=size, check=carryCheck + ) + +def _rorCImpl(prog, params, rawParams, flagUpdates): + size = prog.paramSize(rawParams[2]) + return '\n\t{dst} = {a} >> {b} | {a} << ({size} - {b});'.format(dst = params[2], + a = params[0], b = params[1], size=size + ) + +def _rrcCImpl(prog, params, rawParams, flagUpdates): + needsCarry = False + if flagUpdates: + for flag in flagUpdates: + calc = prog.flags.flagCalc[flag] + if calc == 'carry': + needsCarry = True + decl = '' + carryCheck = _getCarryCheck(prog) + size = prog.paramSize(rawParams[2]) + if needsCarry: + decl,name = prog.getTemp(size * 2) + dst = prog.carryFlowDst = name + else: + dst = params[2] + return decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst, + a = params[0], b = params[1], size=size, check=carryCheck + ) + +def _updateSyncCImpl(prog, params): + return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle) + _opMap = { 'mov': Op(lambda val: val).cUnaryOperator(''), 'not': Op(lambda val: ~val).cUnaryOperator('~'), 'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'), 'neg': Op(lambda val: -val).cUnaryOperator('-'), 'add': Op(lambda a, b: a + b).cBinaryOperator('+'), + 'adc': Op().addImplementation('c', 2, _adcCImpl), 'sub': Op(lambda a, b: b - a).cBinaryOperator('-'), + 'sbc': Op().addImplementation('c', 2, _sbcCImpl), 'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'), 'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'), 'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl), + 'rol': Op().addImplementation('c', 2, _rolCImpl), + 'rlc': Op().addImplementation('c', 2, _rlcCImpl), + 'ror': Op().addImplementation('c', 2, _rorCImpl), + 'rrc': Op().addImplementation('c', 2, _rrcCImpl), 'and': Op(lambda a, b: a & b).cBinaryOperator('&'), 'or': Op(lambda a, b: a | b).cBinaryOperator('|'), 'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'), @@ -390,9 +838,13 @@ 'c', 1, lambda prog, params: '\n\t{dst} = abs({src});'.format(dst=params[1], src=params[0]) ), 'cmp': Op().addImplementation('c', None, _cmpCImpl), + 'sext': Op(_sext).addImplementation('c', 2, _sextCImpl), 'ocall': Op().addImplementation('c', None, lambda prog, params: '\n\t{pre}{fun}({args});'.format( pre = prog.prefix, fun = params[0], args = ', '.join(['context'] + [str(p) for p in params[1:]]) )), + 'pcall': Op().addImplementation('c', None, lambda prog, params: '\n\t(({typ}){fun})({args});'.format( + typ = params[1], fun = params[0], args = ', '.join([str(p) for p in params[2:]]) + )), 'cycles': Op().addImplementation('c', None, lambda prog, params: '\n\tcontext->cycles += context->opts->gen.clock_divider * {0};'.format( params[0] @@ -400,17 +852,18 @@ ), 'addsize': Op( lambda a, b: b + (2 * a if a else 1) - ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} + {sz} ? {sz} * 2 : 1;'.format( + ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} + ({sz} ? {sz} * 2 : 1);'.format( dst = params[2], sz = params[0], val = params[1] )), 'decsize': Op( lambda a, b: b - (2 * a if a else 1) - ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} - {sz} ? {sz} * 2 : 1;'.format( + ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} - ({sz} ? {sz} * 2 : 1);'.format( dst = params[2], sz = params[0], val = params[1] )), 'xchg': Op().addImplementation('c', (0,1), _xchgCImpl), 'dispatch': Op().addImplementation('c', None, _dispatchCImpl), - 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl) + 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl), + 'update_sync': Op().addImplementation('c', None, _updateSyncCImpl) } #represents a simple DSL instruction @@ -419,13 +872,17 @@ self.op = parts[0] self.params = parts[1:] - def generate(self, prog, parent, fieldVals, output, otype): + def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): procParams = [] - allParamsConst = True + allParamsConst = flagUpdates is None and not prog.conditional opDef = _opMap.get(self.op) for param in self.params: - allowConst = (self.op in prog.subroutines or len(procParams) != len(self.params) - 1) and param in parent.regValues isDst = (not opDef is None) and len(procParams) in opDef.outOp + allowConst = (self.op in prog.subroutines or not isDst) and param in parent.regValues + if isDst and self.op == 'xchg': + #xchg uses its regs as both source and destination + #we need to resolve as both so that disperse/coalesce flag stuff gets done + prog.resolveParam(param, parent, fieldVals, allowConst, False) param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst) if (not type(param) is int) and len(procParams) != len(self.params) - 1: @@ -442,12 +899,14 @@ else: param = parent.resolveLocal(param) or param if param in fieldVals: - param = fieldVals[index] + param = fieldVals[param] prog.meta[self.params[0]] = param elif self.op == 'dis': #TODO: Disassembler pass elif not opDef is None: + if opDef.numParams() > len(procParams): + raise Exception('Insufficient params for ' + self.op + ' (' + ', '.join(self.params) + ')') if opDef.canEval() and allParamsConst: #do constant folding if opDef.numArgs() >= len(procParams): @@ -461,10 +920,33 @@ dst = maybeLocal parent.regValues[dst] = result if prog.isReg(dst): - output.append(_opMap['mov'].generate(otype, prog, procParams, self.params)) + shortProc = (procParams[0], procParams[-1]) + shortParams = (self.params[0], self.params[-1]) + output.append(_opMap['mov'].generate(otype, prog, shortProc, shortParams, None)) else: - output.append(opDef.generate(otype, prog, procParams, self.params)) + output.append(opDef.generate(otype, prog, procParams, self.params, flagUpdates)) + for dstIdx in opDef.outOp: + dst = self.params[dstIdx] + while dst in prog.meta: + dst = prog.meta[dst] + if dst in parent.regValues: + del parent.regValues[dst] + elif self.op in prog.subroutines: + procParams = [] + for param in self.params: + begin,sep,end = param.partition('.') + if sep: + if end in fieldVals: + param = begin + '.' + str(fieldVals[end]) + else: + if param in fieldVals: + param = fieldVals[param] + else: + maybeLocal = parent.resolveLocal(param) + if maybeLocal and maybeLocal in parent.regValues: + param = parent.regValues[maybeLocal] + procParams.append(param) prog.subroutines[self.op].inline(prog, procParams, output, otype, parent) else: output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');') @@ -517,7 +999,7 @@ return self.current_locals[name] return self.parent.localSize(name) - def generate(self, prog, parent, fieldVals, output, otype): + def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): prog.pushScope(self) param = prog.resolveParam(self.param, parent, fieldVals) if type(param) is int: @@ -527,39 +1009,42 @@ output.append('\n\t{') for local in self.case_locals[param]: output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local)) - for op in self.cases[param]: - op.generate(prog, self, fieldVals, output, otype) + self.processOps(prog, fieldVals, output, otype, self.cases[param]) output.append('\n\t}') elif self.default: self.current_locals = self.default_locals output.append('\n\t{') for local in self.default_locals: output.append('\n\tuint{0}_t {1};'.format(self.default[local], local)) - for op in self.default: - op.generate(prog, self, fieldVals, output, otype) + self.processOps(prog, fieldVals, output, otype, self.default) output.append('\n\t}') else: + oldCond = prog.conditional + prog.conditional = True output.append('\n\tswitch(' + param + ')') output.append('\n\t{') for case in self.cases: + #temp = prog.temp.copy() self.current_locals = self.case_locals[case] self.regValues = dict(self.parent.regValues) output.append('\n\tcase {0}U: '.format(case) + '{') for local in self.case_locals[case]: output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local)) - for op in self.cases[case]: - op.generate(prog, self, fieldVals, output, otype) + self.processOps(prog, fieldVals, output, otype, self.cases[case]) output.append('\n\tbreak;') output.append('\n\t}') + #prog.temp = temp if self.default: + #temp = prog.temp.copy() self.current_locals = self.default_locals self.regValues = dict(self.parent.regValues) output.append('\n\tdefault: {') for local in self.default_locals: output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local)) - for op in self.default: - op.generate(prog, self, fieldVals, output, otype) + self.processOps(prog, fieldVals, output, otype, self.default) + #prog.temp = temp output.append('\n\t}') + prog.conditional = oldCond prog.popScope() def __str__(self): @@ -579,11 +1064,24 @@ params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params] return '\n\tif ({a} >= {b}) '.format(a=params[1], b = params[0]) + '{' else: - raise ion(">=U not implemented in the general case yet") + raise Exception(">=U not implemented in the general case yet") + +def _eqCImpl(prog, parent, fieldVals, output): + if prog.lastOp.op == 'cmp': + output.pop() + params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params] + return '\n\tif ({a} == {b}) '.format(a=params[1], b = params[0]) + '{' + else: + return '\n\tif (!{a}) {{'.format(a=prog.resolveParam(prog.lastDst, None, {})) + +def _neqCImpl(prog, parent, fieldVals, output): + return '\n\tif ({a}) {{'.format(a=prog.resolveParam(prog.lastDst, None, {})) _ifCmpImpl = { 'c': { - '>=U': _geuCImpl + '>=U': _geuCImpl, + '=': _eqCImpl, + '!=': _neqCImpl } } #represents a DSL conditional construct @@ -606,7 +1104,7 @@ if op.op == 'local': name = op.params[0] size = op.params[1] - self.locals[name] = size + self.curLocals[name] = size elif op.op == 'else': self.curLocals = self.elseLocals self.curBody = self.elseBody @@ -617,23 +1115,25 @@ return self.curLocals.get(name) def resolveLocal(self, name): - if name in self.locals: + if name in self.curLocals: return name return self.parent.resolveLocal(name) def _genTrueBody(self, prog, fieldVals, output, otype): self.curLocals = self.locals + subOut = [] + self.processOps(prog, fieldVals, subOut, otype, self.body) for local in self.locals: output.append('\n\tuint{sz}_t {nm};'.format(sz=self.locals[local], nm=local)) - for op in self.body: - op.generate(prog, self, fieldVals, output, otype) + output += subOut def _genFalseBody(self, prog, fieldVals, output, otype): self.curLocals = self.elseLocals + subOut = [] + self.processOps(prog, fieldVals, subOut, otype, self.elseBody) for local in self.elseLocals: output.append('\n\tuint{sz}_t {nm};'.format(sz=self.elseLocals[local], nm=local)) - for op in self.elseBody: - op.generate(prog, self, fieldVals, output, otype) + output += subOut def _genConstParam(self, param, prog, fieldVals, output, otype): if param: @@ -641,29 +1141,43 @@ else: self._genFalseBody(prog, fieldVals, output, otype) - def generate(self, prog, parent, fieldVals, output, otype): + def generate(self, prog, parent, fieldVals, output, otype, flagUpdates): self.regValues = parent.regValues - try: + if self.cond in prog.booleans: self._genConstParam(prog.checkBool(self.cond), prog, fieldVals, output, otype) - except Exception: + else: if self.cond in _ifCmpImpl[otype]: + oldCond = prog.conditional + prog.conditional = True + #temp = prog.temp.copy() output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output)) self._genTrueBody(prog, fieldVals, output, otype) + #prog.temp = temp if self.elseBody: + #temp = prog.temp.copy() output.append('\n\t} else {') self._genFalseBody(prog, fieldVals, output, otype) + #prog.temp = temp output.append('\n\t}') + prog.conditional = oldCond else: cond = prog.resolveParam(self.cond, parent, fieldVals) if type(cond) is int: self._genConstParam(cond, prog, fieldVals, output, otype) else: + #temp = prog.temp.copy() output.append('\n\tif ({cond}) '.format(cond=cond) + '{') + oldCond = prog.conditional + prog.conditional = True self._genTrueBody(prog, fieldVals, output, otype) + #prog.temp = temp if self.elseBody: + #temp = prog.temp.copy() output.append('\n\t} else {') self._genFalseBody(prog, fieldVals, output, otype) + #prog.temp = temp output.append('\n\t}') + prog.conditional = oldCond def __str__(self): @@ -679,12 +1193,14 @@ self.pointers = {} self.regArrays = {} self.regToArray = {} + self.addReg('cycles', 32) + self.addReg('sync_cycle', 32) def addReg(self, name, size): self.regs[name] = size - def addPointer(self, name, size): - self.pointers[name] = size + def addPointer(self, name, size, count): + self.pointers[name] = (size, count) def addRegArray(self, name, size, regs): self.regArrays[name] = (size, regs) @@ -721,12 +1237,15 @@ def processLine(self, parts): if len(parts) == 3: - self.addRegArray(parts[0], int(parts[1]), int(parts[2])) + if parts[1].startswith('ptr'): + self.addPointer(parts[0], parts[1][3:], int(parts[2])) + else: + self.addRegArray(parts[0], int(parts[1]), int(parts[2])) elif len(parts) > 2: self.addRegArray(parts[0], int(parts[1]), parts[2:]) else: if parts[1].startswith('ptr'): - self.addPointer(parts[0], int(parts[1][3:])) + self.addPointer(parts[0], parts[1][3:], 1) else: self.addReg(parts[0], int(parts[1])) return self @@ -734,7 +1253,18 @@ def writeHeader(self, otype, hFile): fieldList = [] for pointer in self.pointers: - hFile.write('\n\tuint{sz}_t *{nm};'.format(nm=pointer, sz=self.pointers[pointer])) + stars = '*' + ptype, count = self.pointers[pointer] + while ptype.startswith('ptr'): + stars += '*' + ptype = ptype[3:] + if ptype.isdigit(): + ptype = 'uint{sz}_t'.format(sz=ptype) + if count > 1: + arr = '[{n}]'.format(n=count) + else: + arr = '' + hFile.write('\n\t{ptype} {stars}{nm}{arr};'.format(nm=pointer, ptype=ptype, stars=stars, arr=arr)) for reg in self.regs: if not self.isRegArrayMember(reg): fieldList.append((self.regs[reg], 1, reg)) @@ -756,7 +1286,9 @@ self.flagBits = {} self.flagCalc = {} self.flagStorage = {} + self.flagOrder = [] self.flagReg = None + self.storageToFlags = {} self.maxBit = -1 def processLine(self, parts): @@ -777,6 +1309,9 @@ self.flagBits[flag] = bit self.flagCalc[flag] = calc self.flagStorage[flag] = storage + storage,_,storebit = storage.partition('.') + self.storageToFlags.setdefault(storage, []).append((storebit, flag)) + self.flagOrder.append(flag) return self def getStorage(self, flag): @@ -788,6 +1323,28 @@ else: return loc + def parseFlagUpdate(self, flagString): + last = '' + autoUpdate = set() + explicit = {} + for c in flagString: + if c.isdigit(): + if last.isalpha(): + num = int(c) + if num > 1: + raise Exception(c + ' is not a valid digit for update_flags') + explicit[last] = num + last = c + else: + raise Exception('Digit must follow flag letter in update_flags') + else: + if last.isalpha(): + autoUpdate.add(last) + last = c + if last.isalpha(): + autoUpdate.add(last) + return (autoUpdate, explicit) + def disperseFlags(self, prog, otype): bitToFlag = [None] * (self.maxBit+1) src = prog.resolveReg(self.flagReg, None, {}) @@ -884,7 +1441,7 @@ src=src, dst=dst, srcbit=srcbit, dstbit=dstbit )) if direct: - output.append('\n\t{dst} |= {src} & {mask}'.format( + output.append('\n\t{dst} |= {src} & {mask};'.format( dst=dst, src=src, mask=direct )) return ''.join(output) @@ -902,12 +1459,22 @@ self.extra_tables = info.get('extra_tables', []) self.context_type = self.prefix + 'context' self.body = info.get('body', [None])[0] + self.interrupt = info.get('interrupt', [None])[0] + self.sync_cycle = info.get('sync_cycle', [None])[0] self.includes = info.get('include', []) self.flags = flags self.lastDst = None self.scopes = [] self.currentScope = None self.lastOp = None + self.carryFlowDst = None + self.lastA = None + self.lastB = None + self.lastBFlow = None + self.sizeAdjust = None + self.conditional = False + self.declares = [] + self.lastSize = None def __str__(self): pieces = [] @@ -930,21 +1497,21 @@ hFile.write('\n}} {0}options;'.format(self.prefix)) hFile.write('\n\ntypedef struct {') hFile.write('\n\t{0}options *opts;'.format(self.prefix)) - hFile.write('\n\tuint32_t cycles;') self.regs.writeHeader(otype, hFile) hFile.write('\n}} {0}context;'.format(self.prefix)) hFile.write('\n') + hFile.write('\nvoid {pre}execute({type} *context, uint32_t target_cycle);'.format(pre = self.prefix, type = self.context_type)) + for decl in self.declares: + hFile.write('\n' + decl) hFile.write('\n#endif //{0}_'.format(macro)) hFile.write('\n') hFile.close() - def build(self, otype): - body = [] + + def _buildTable(self, otype, table, body, lateBody): pieces = [] - for include in self.includes: - body.append('#include "{0}"\n'.format(include)) - for table in self.instructions: - opmap = [None] * (1 << self.opsize) - bodymap = {} + opmap = [None] * (1 << self.opsize) + bodymap = {} + if table in self.instructions: instructions = self.instructions[table] instructions.sort() for inst in instructions: @@ -957,8 +1524,8 @@ self.lastOp = None opmap[val] = inst.generateName(val) bodymap[val] = inst.generateBody(val, self, otype) - - pieces.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix)) + + if self.dispatch == 'call': pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) for inst in range(0, len(opmap)): op = opmap[inst] @@ -968,20 +1535,85 @@ pieces.append('\n\t' + op + ',') body.append(bodymap[inst]) pieces.append('\n};') - if self.body in self.subroutines: + elif self.dispatch == 'goto': + body.append('\n\tstatic void *impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap))) + for inst in range(0, len(opmap)): + op = opmap[inst] + if op is None: + body.append('\n\t\t&&unimplemented,') + else: + body.append('\n\t\t&&' + op + ',') + lateBody.append(bodymap[inst]) + body.append('\n\t};') + else: + raise Exception("unimplmeneted dispatch type " + self.dispatch) + body.extend(pieces) + + def nextInstruction(self, otype): + output = [] + if self.dispatch == 'goto': + if self.interrupt in self.subroutines: + output.append('\n\tif (context->cycles >= context->sync_cycle) {') + output.append('\n\tif (context->cycles >= target_cycle) { return; }') + if self.interrupt in self.subroutines: + self.meta = {} + self.temp = {} + self.subroutines[self.interrupt].inline(self, [], output, otype, None) + output.append('\n\t}') + + self.meta = {} + self.temp = {} + self.subroutines[self.body].inline(self, [], output, otype, None) + return output + + def build(self, otype): + body = [] + pieces = [] + for include in self.includes: + body.append('#include "{0}"\n'.format(include)) + if self.dispatch == 'call': + body.append('\nstatic void unimplemented({pre}context *context, uint32_t target_cycle)'.format(pre = self.prefix)) + body.append('\n{') + body.append('\n\tfatal_error("Unimplemented instruction\\n");') + body.append('\n}\n') + body.append('\ntypedef void (*impl_fun)({pre}context *context, uint32_t target_cycle);'.format(pre=self.prefix)) + for table in self.extra_tables: + body.append('\nstatic impl_fun impl_{name}[{sz}];'.format(name = table, sz=(1 << self.opsize))) + body.append('\nstatic impl_fun impl_main[{sz}];'.format(sz=(1 << self.opsize))) + elif self.dispatch == 'goto': + body.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type)) + body.append('\n{') + + for table in self.extra_tables: + self._buildTable(otype, table, body, pieces) + self._buildTable(otype, 'main', body, pieces) + if self.dispatch == 'call' and self.body in self.subroutines: pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type)) pieces.append('\n{') + pieces.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle)) pieces.append('\n\twhile (context->cycles < target_cycle)') pieces.append('\n\t{') + if self.interrupt in self.subroutines: + pieces.append('\n\t\tif (context->cycles >= context->sync_cycle) {') + self.meta = {} + self.temp = {} + intpieces = [] + self.subroutines[self.interrupt].inline(self, [], intpieces, otype, None) + for size in self.temp: + pieces.append('\n\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size)) + pieces += intpieces + pieces.append('\n\t\t}') self.meta = {} self.temp = {} self.subroutines[self.body].inline(self, [], pieces, otype, None) pieces.append('\n\t}') pieces.append('\n}') - body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix)) - body.append('\n{') - body.append('\n\tfatal_error("Unimplemented instruction");') - body.append('\n}\n') + elif self.dispatch == 'goto': + body.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle)) + body += self.nextInstruction(otype) + pieces.append('\nunimplemented:') + pieces.append('\n\tfatal_error("Unimplemented instruction\\n");') + pieces.append('\n}') return ''.join(body) + ''.join(pieces) def checkBool(self, name): @@ -992,8 +1624,8 @@ def getTemp(self, size): if size in self.temp: return ('', self.temp[size]) - self.temp[size] = 'tmp{sz}'.format(sz=size); - return ('\n\tuint{sz}_t tmp{sz};'.format(sz=size), self.temp[size]) + self.temp[size] = 'gen_tmp{sz}__'.format(sz=size); + return ('', self.temp[size]) def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False): keepGoing = True @@ -1013,14 +1645,24 @@ return parent.regValues[param] maybeLocal = parent.resolveLocal(param) if maybeLocal: + if isdst: + self.lastDst = param + self.lastSize = None return maybeLocal if param in fieldVals: param = fieldVals[param] + fieldVals = {} + keepGoing = True elif param in self.meta: param = self.meta[param] keepGoing = True elif self.isReg(param): - param = self.resolveReg(param, parent, fieldVals, isdst) + return self.resolveReg(param, parent, fieldVals, isdst) + elif param in self.regs.pointers: + return 'context->' + param + if isdst: + self.lastDst = param + self.lastSize = None return param def isReg(self, name): @@ -1070,9 +1712,12 @@ def paramSize(self, name): - size = self.currentScope.localSize(name) - if size: - return size + if name in self.meta: + return self.paramSize(self.meta[name]) + for i in range(len(self.scopes) -1, -1, -1): + size = self.scopes[i].localSize(name) + if size: + return size begin,sep,_ = name.partition('.') if sep and self.regs.isRegArray(begin): return self.regs.regArrays[begin][0] @@ -1080,6 +1725,11 @@ return self.regs.regs[name] return 32 + def getLastSize(self): + if self.lastSize: + return self.lastSize + return self.paramSize(self.lastDst) + def pushScope(self, scope): self.scopes.append(scope) self.currentScope = scope @@ -1092,11 +1742,13 @@ def getRootScope(self): return self.scopes[0] -def parse(f): +def parse(args): + f = args.source instructions = {} subroutines = {} registers = None flags = None + declares = [] errors = [] info = {} line_num = 0 @@ -1108,9 +1760,22 @@ continue if line[0].isspace(): if not cur_object is None: - parts = [el.strip() for el in line.split(' ')] + sep = True + parts = [] + while sep: + before,sep,after = line.partition('"') + before = before.strip() + if before: + parts += [el.strip() for el in before.split(' ')] + if sep: + #TODO: deal with escaped quotes + inside,sep,after = after.partition('"') + parts.append('"' + inside + '"') + line = after if type(cur_object) is dict: cur_object[parts[0]] = parts[1:] + elif type(cur_object) is list: + cur_object.append(' '.join(parts)) else: cur_object = cur_object.processLine(parts) @@ -1168,6 +1833,8 @@ if flags is None: flags = Flags() cur_object = flags + elif line.strip() == 'declare': + cur_object = declares else: cur_object = SubRoutine(line.strip()) subroutines[cur_object.name] = cur_object @@ -1175,8 +1842,19 @@ print(errors) else: p = Program(registers, instructions, subroutines, info, flags) + p.dispatch = args.dispatch + p.declares = declares p.booleans['dynarec'] = False p.booleans['interp'] = True + if args.define: + for define in args.define: + name,sep,val = define.partition('=') + name = name.strip() + val = val.strip() + if sep: + p.booleans[name] = bool(val) + else: + p.booleans[name] = True if 'header' in info: print('#include "{0}"'.format(info['header'][0])) @@ -1186,8 +1864,12 @@ print(p.build('c')) def main(argv): - f = open(argv[1]) - parse(f) + from argparse import ArgumentParser, FileType + argParser = ArgumentParser(description='CPU emulator DSL compiler') + argParser.add_argument('source', type=FileType('r')) + argParser.add_argument('-D', '--define', action='append') + argParser.add_argument('-d', '--dispatch', choices=('call', 'switch', 'goto'), default='call') + parse(argParser.parse_args(argv[1:])) if __name__ == '__main__': from sys import argv