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:
parent
4d61f439bc
commit
22c58ba556
@ -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)
|
||||
|
@ -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':
|
||||
|
@ -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)
|
||||
|
@ -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 ###
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user