mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-26 14:49:15 +00:00
Improve evaluator internals. Finish test suite for analysis.
This commit is contained in:
parent
4d61f439bc
commit
22c58ba556
@ -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)
|
|
||||||
|
@ -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':
|
||||||
|
@ -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)
|
||||||
|
@ -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 ###
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user