1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-25 23:49:17 +00:00

Improve evaluator internals. Finish test suite for analysis.

This commit is contained in:
Chris Pressey 2015-10-16 19:32:18 +01:00
parent 4d61f439bc
commit 22c58ba556
4 changed files with 198 additions and 52 deletions

View File

@ -58,5 +58,4 @@ if __name__ == '__main__':
if options.execute: if options.execute:
context = eval_program(program) context = eval_program(program)
for key, value in sorted(context.iteritems()): print str(context)
print "%s: %s" % (key, value)

View File

@ -158,7 +158,7 @@ def analyze_instr(instr, context, routines):
context.assert_writeable(dest, FLAG_Z, FLAG_N) context.assert_writeable(dest, FLAG_Z, FLAG_N)
context.set_initialized(dest, FLAG_Z, FLAG_N) context.set_initialized(dest, FLAG_Z, FLAG_N)
elif opcode in ('shl', 'shr'): 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.assert_writeable(dest, FLAG_Z, FLAG_N, FLAG_C)
context.set_initialized(dest, FLAG_Z, FLAG_N, FLAG_C) context.set_initialized(dest, FLAG_Z, FLAG_N, FLAG_C)
elif opcode == 'call': elif opcode == 'call':

View File

@ -1,31 +1,38 @@
# encoding: UTF-8 # encoding: UTF-8
from sixtypical.ast import Program, Routine, Block, Instr 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(object):
class Context(dict): 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): def get(self, ref):
if isinstance(ref, ConstantRef): if isinstance(ref, ConstantRef):
return ref.value return ref.value
elif isinstance(ref, LocationRef): elif isinstance(ref, LocationRef):
return self[ref.name] return self._store[ref.name]
else: else:
raise ValueError(ref) raise ValueError(ref)
def set(self, ref, value): def set(self, ref, value):
assert isinstance(ref, LocationRef) assert isinstance(ref, LocationRef)
self[ref.name] = value self._store[ref.name] = value
def eval_program(program): def eval_program(program):
assert isinstance(program, Program) assert isinstance(program, Program)
routines = {r.name: r for r in program.routines} routines = {r.name: r for r in program.routines}
context = Context({ context = Context()
'a': 0, 'x': 0, 'y': 0, for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C):
'c': 0, 'n': 0, 'z': 0, 'v': 0 context.set(ref, 0)
})
eval_routine(routines['main'], context, routines) eval_routine(routines['main'], context, routines)
return context return context
@ -49,90 +56,90 @@ def eval_instr(instr, context, routines):
if opcode == 'ld': if opcode == 'ld':
result = context.get(src) result = context.get(src)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'st': elif opcode == 'st':
context.set(dest, context.get(src)) context.set(dest, context.get(src))
elif opcode == 'add': elif opcode == 'add':
carry = context['c'] carry = context.get(FLAG_C)
val = context.get(src) val = context.get(src)
now = context.get(dest) now = context.get(dest)
result = now + val + carry result = now + val + carry
if result > 255: if result > 255:
result &= 255 result &= 255
context['c'] = 1 context.set(FLAG_C, 1)
else: else:
context['c'] = 0 context.set(FLAG_C, 0)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'sub': elif opcode == 'sub':
carry = context['c'] carry = context.get(FLAG_C)
val = context.get(src) val = context.get(src)
now = context.get(dest) now = context.get(dest)
result = now - val - carry result = now - val - carry
if result < 0: if result < 0:
result &= 255 result &= 255
context['c'] = 1 context.set(FLAG_C, 1)
else: else:
context['c'] = 0 context.set(FLAG_C, 0)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'inc': elif opcode == 'inc':
val = context.get(dest) val = context.get(dest)
result = (val + 1) & 255 result = (val + 1) & 255
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'dec': elif opcode == 'dec':
val = context.get(dest) val = context.get(dest)
result = (val - 1) & 255 result = (val - 1) & 255
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'cmp': elif opcode == 'cmp':
val = context.get(src) val = context.get(src)
now = context.get(dest) now = context.get(dest)
result = now - val result = now - val
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
if result < 0: if result < 0:
result &= 255 result &= 255
context['c'] = 1 context.set(FLAG_C, 1)
else: else:
context['c'] = 0 context.set(FLAG_C, 0)
elif opcode == 'and': elif opcode == 'and':
result = context.get(dest) & context.get(src) result = context.get(dest) & context.get(src)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'or': elif opcode == 'or':
result = context.get(dest) | context.get(src) result = context.get(dest) | context.get(src)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'xor': elif opcode == 'xor':
result = context.get(dest) ^ context.get(src) result = context.get(dest) ^ context.get(src)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'shl': elif opcode == 'shl':
val = context.get(dest) val = context.get(dest)
carry = context['c'] carry = context.get(FLAG_C)
context['c'] = 1 if val & 128 else 0 context.set(FLAG_C, 1 if val & 128 else 0)
result = ((val << 1) + carry) & 255 result = ((val << 1) + carry) & 255
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'shr': elif opcode == 'shr':
val = context.get(dest) val = context.get(dest)
carry = context['c'] carry = context.get(FLAG_C)
context['c'] = 1 if val & 1 else 0 context.set(FLAG_C, 1 if val & 1 else 0)
result = (val >> 1) + (carry * 128) result = (val >> 1) + (carry * 128)
context['z'] = 1 if result == 0 else 0 context.set(FLAG_Z, 1 if result == 0 else 0)
context['n'] = 1 if result & 128 else 0 context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result) context.set(dest, result)
elif opcode == 'call': elif opcode == 'call':
eval_routine(routines[instr.name], context, routines) eval_routine(routines[instr.name], context, routines)

View File

@ -349,27 +349,167 @@ Location must be initialized and writeable.
### cmp ### ### 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 ### ### 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 ### ### 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 ### ### 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 ### ### 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 ### ### 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 ### ### call ###