diff --git a/bin/sixtypical b/bin/sixtypical index ff6d85f..7cdff71 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -58,5 +58,4 @@ if __name__ == '__main__': if options.execute: context = eval_program(program) - for key, value in sorted(context.iteritems()): - print "%s: %s" % (key, value) + print str(context) diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index e3d879b..d0feae5 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -158,7 +158,7 @@ def analyze_instr(instr, context, routines): context.assert_writeable(dest, FLAG_Z, FLAG_N) context.set_initialized(dest, FLAG_Z, FLAG_N) elif opcode in ('shl', 'shr'): - context.assert_initialized(dest) + context.assert_initialized(dest, FLAG_C) context.assert_writeable(dest, FLAG_Z, FLAG_N, FLAG_C) context.set_initialized(dest, FLAG_Z, FLAG_N, FLAG_C) elif opcode == 'call': diff --git a/src/sixtypical/evaluator.py b/src/sixtypical/evaluator.py index b3cf96a..07c108f 100644 --- a/src/sixtypical/evaluator.py +++ b/src/sixtypical/evaluator.py @@ -1,31 +1,38 @@ # encoding: UTF-8 from sixtypical.ast import Program, Routine, Block, Instr -from sixtypical.model import ConstantRef, LocationRef +from sixtypical.model import ( + ConstantRef, LocationRef, + REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C +) -# TODO: should not inherit from dict -class Context(dict): +class Context(object): + def __init__(self): + self._store = {} + + def __str__(self): + return '\n'.join("%s: %s" % p for p in sorted(self._store.iteritems())) + def get(self, ref): if isinstance(ref, ConstantRef): return ref.value elif isinstance(ref, LocationRef): - return self[ref.name] + return self._store[ref.name] else: raise ValueError(ref) def set(self, ref, value): assert isinstance(ref, LocationRef) - self[ref.name] = value + self._store[ref.name] = value def eval_program(program): assert isinstance(program, Program) routines = {r.name: r for r in program.routines} - context = Context({ - 'a': 0, 'x': 0, 'y': 0, - 'c': 0, 'n': 0, 'z': 0, 'v': 0 - }) + context = Context() + for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C): + context.set(ref, 0) eval_routine(routines['main'], context, routines) return context @@ -49,90 +56,90 @@ def eval_instr(instr, context, routines): if opcode == 'ld': result = context.get(src) - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'st': context.set(dest, context.get(src)) elif opcode == 'add': - carry = context['c'] + carry = context.get(FLAG_C) val = context.get(src) now = context.get(dest) result = now + val + carry if result > 255: result &= 255 - context['c'] = 1 + context.set(FLAG_C, 1) else: - context['c'] = 0 - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_C, 0) + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'sub': - carry = context['c'] + carry = context.get(FLAG_C) val = context.get(src) now = context.get(dest) result = now - val - carry if result < 0: result &= 255 - context['c'] = 1 + context.set(FLAG_C, 1) else: - context['c'] = 0 - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_C, 0) + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'inc': val = context.get(dest) result = (val + 1) & 255 - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'dec': val = context.get(dest) result = (val - 1) & 255 - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'cmp': val = context.get(src) now = context.get(dest) result = now - val - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) if result < 0: result &= 255 - context['c'] = 1 + context.set(FLAG_C, 1) else: - context['c'] = 0 + context.set(FLAG_C, 0) elif opcode == 'and': result = context.get(dest) & context.get(src) - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'or': result = context.get(dest) | context.get(src) - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'xor': result = context.get(dest) ^ context.get(src) - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'shl': val = context.get(dest) - carry = context['c'] - context['c'] = 1 if val & 128 else 0 + carry = context.get(FLAG_C) + context.set(FLAG_C, 1 if val & 128 else 0) result = ((val << 1) + carry) & 255 - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'shr': val = context.get(dest) - carry = context['c'] - context['c'] = 1 if val & 1 else 0 + carry = context.get(FLAG_C) + context.set(FLAG_C, 1 if val & 1 else 0) result = (val >> 1) + (carry * 128) - context['z'] = 1 if result == 0 else 0 - context['n'] = 1 if result & 128 else 0 + context.set(FLAG_Z, 1 if result == 0 else 0) + context.set(FLAG_N, 1 if result & 128 else 0) context.set(dest, result) elif opcode == 'call': eval_routine(routines[instr.name], context, routines) diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 7516668..069e238 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -349,27 +349,167 @@ Location must be initialized and writeable. ### cmp ### -TODO: write some tests +Some rudimentary tests for cmp. + + | routine main + | inputs a + | trashes z, c, n + | { + | cmp a, 4 + | } + = ok + + | routine main + | inputs a + | trashes z, n + | { + | cmp a, 4 + | } + ? IllegalWriteError: c + + | routine main + | trashes z, c, n + | { + | cmp a, 4 + | } + ? UninitializedAccessError: a ### and ### -TODO: write some tests +Some rudimentary tests for and. + + | routine main + | inputs a + | outputs a, z, n + | { + | and a, 4 + | } + = ok + + | routine main + | inputs a + | trashes z, n + | { + | and a, 4 + | } + ? IllegalWriteError: a + + | routine main + | trashes z, n + | { + | and a, 4 + | } + ? UninitializedAccessError: a ### or ### -TODO: write some tests +Writing unit tests on a train. Wow. + + | routine main + | inputs a + | outputs a, z, n + | { + | or a, 4 + | } + = ok + + | routine main + | inputs a + | trashes z, n + | { + | or a, 4 + | } + ? IllegalWriteError: a + + | routine main + | trashes z, n + | { + | or a, 4 + | } + ? UninitializedAccessError: a ### xor ### -TODO: write some tests +Writing unit tests on a train. Wow. + + | routine main + | inputs a + | outputs a, z, n + | { + | xor a, 4 + | } + = ok + + | routine main + | inputs a + | trashes z, n + | { + | xor a, 4 + | } + ? IllegalWriteError: a + + | routine main + | trashes z, n + | { + | xor a, 4 + | } + ? UninitializedAccessError: a ### shl ### -TODO: write some tests +Some rudimentary tests for shl. + + | routine main + | inputs a, c + | outputs a, c, z, n + | { + | shl a + | } + = ok + + | routine main + | inputs a, c + | outputs c, z, n + | { + | shl a + | } + ? IllegalWriteError: a + + | routine main + | inputs a + | outputs a, c, z, n + | { + | shl a + | } + ? UninitializedAccessError: c ### shr ### -TODO: write some tests +Some rudimentary tests for shr. + + | routine main + | inputs a, c + | outputs a, c, z, n + | { + | shr a + | } + = ok + + | routine main + | inputs a, c + | outputs c, z, n + | { + | shr a + | } + ? IllegalWriteError: a + + | routine main + | inputs a + | outputs a, c, z, n + | { + | shr a + | } + ? UninitializedAccessError: c ### call ###