2015-10-16 09:40:38 +00:00
|
|
|
"""Data/storage model for SixtyPical."""
|
|
|
|
|
2017-12-11 10:42:42 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class Type(object):
|
2015-10-16 09:40:38 +00:00
|
|
|
def __init__(self, name):
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def __repr__(self):
|
2015-10-18 16:23:01 +00:00
|
|
|
return 'Type(%r)' % self.name
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2017-12-12 12:45:47 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2015-10-16 22:12:52 +00:00
|
|
|
def __eq__(self, other):
|
2015-10-18 16:23:01 +00:00
|
|
|
return isinstance(other, Type) and other.name == self.name
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.name)
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
TYPE_BIT = Type('bit')
|
|
|
|
TYPE_BYTE = Type('byte')
|
|
|
|
TYPE_BYTE_TABLE = Type('byte table')
|
2016-06-16 16:08:57 +00:00
|
|
|
TYPE_WORD = Type('word')
|
|
|
|
TYPE_WORD_TABLE = Type('word table')
|
2015-10-19 17:18:06 +00:00
|
|
|
|
|
|
|
|
2015-10-19 18:17:27 +00:00
|
|
|
class ExecutableType(Type):
|
2015-10-19 17:18:06 +00:00
|
|
|
"""Used for routines and vectors."""
|
|
|
|
def __init__(self, name, inputs=None, outputs=None, trashes=None):
|
|
|
|
self.name = name
|
2015-10-19 18:17:27 +00:00
|
|
|
self.inputs = inputs or set()
|
|
|
|
self.outputs = outputs or set()
|
|
|
|
self.trashes = trashes or set()
|
2015-10-19 17:18:06 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return 'RoutineType(%r, inputs=%r, outputs=%r, trashes=%r)' % (
|
|
|
|
self.name, self.inputs, self.outputs, self.trashes
|
|
|
|
)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return isinstance(other, RoutineType) and (
|
|
|
|
other.name == self.name and
|
|
|
|
other.inputs == self.inputs and
|
|
|
|
other.outputs == self.outputs and
|
|
|
|
other.trashes == self.trashes
|
|
|
|
)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.name) ^ hash(self.inputs) ^ hash(self.outputs) ^ hash(self.trashes)
|
|
|
|
|
|
|
|
|
2015-10-19 18:17:27 +00:00
|
|
|
class RoutineType(ExecutableType):
|
2015-10-19 17:18:06 +00:00
|
|
|
"""This memory location contains the code for a routine."""
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
super(RoutineType, self).__init__('routine', **kwargs)
|
|
|
|
|
|
|
|
|
2015-10-19 18:17:27 +00:00
|
|
|
class VectorType(ExecutableType):
|
2015-10-19 17:18:06 +00:00
|
|
|
"""This memory location contains the address of a routine."""
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
super(VectorType, self).__init__('vector', **kwargs)
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
|
2017-11-24 11:30:20 +00:00
|
|
|
class BufferType(Type):
|
|
|
|
def __init__(self, size):
|
|
|
|
self.size = size
|
|
|
|
self.name = 'buffer[%s]' % self.size
|
|
|
|
|
|
|
|
|
|
|
|
class PointerType(Type):
|
|
|
|
def __init__(self):
|
|
|
|
self.name = 'pointer'
|
|
|
|
|
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class Ref(object):
|
2015-10-22 19:01:02 +00:00
|
|
|
def is_constant(self):
|
|
|
|
"""read-only means that the program cannot change the value
|
|
|
|
of a location. constant means that the value of the location
|
|
|
|
will not change during the lifetime of the program."""
|
|
|
|
raise NotImplementedError
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
class LocationRef(Ref):
|
|
|
|
def __init__(self, type, name):
|
|
|
|
self.type = type
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
# Ordinarily there will only be one ref with a given name,
|
|
|
|
# but because we store the type in here and we want to treat
|
2017-12-12 12:54:16 +00:00
|
|
|
# these objects as immutable, we compare the types, too,
|
|
|
|
# just to be sure.
|
|
|
|
equal = isinstance(other, self.__class__) and other.name == self.name
|
|
|
|
if equal:
|
|
|
|
assert other.type == self.type
|
|
|
|
return equal
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.name + str(self.type))
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name)
|
|
|
|
|
2017-12-12 12:45:47 +00:00
|
|
|
def __str__(self):
|
|
|
|
return "{}:{}".format(self.name, self.type)
|
|
|
|
|
2015-10-22 19:01:02 +00:00
|
|
|
def is_constant(self):
|
|
|
|
return isinstance(self.type, RoutineType)
|
|
|
|
|
2017-12-12 13:17:00 +00:00
|
|
|
def backpatch_vector_labels(self, resolver):
|
2017-12-12 12:51:19 +00:00
|
|
|
if isinstance(self.type, ExecutableType):
|
|
|
|
t = self.type
|
|
|
|
t.inputs = set([resolver(w) for w in t.inputs])
|
|
|
|
t.outputs = set([resolver(w) for w in t.outputs])
|
|
|
|
t.trashes = set([resolver(w) for w in t.trashes])
|
|
|
|
|
2017-12-12 12:45:47 +00:00
|
|
|
@classmethod
|
|
|
|
def format_set(cls, location_refs):
|
|
|
|
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs)])
|
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
|
2017-12-01 11:44:40 +00:00
|
|
|
class IndirectRef(Ref):
|
|
|
|
def __init__(self, ref):
|
|
|
|
self.ref = ref
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2017-12-08 13:41:48 +00:00
|
|
|
return isinstance(other, self.__class__) and self.ref == other.ref
|
2017-12-01 11:44:40 +00:00
|
|
|
|
|
|
|
def __hash__(self):
|
2017-12-01 12:36:58 +00:00
|
|
|
return hash(self.__class__.name) ^ hash(self.ref)
|
2017-12-01 11:44:40 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r)' % (self.__class__.__name__, self.ref)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return '[{}]+y'.format(self.ref.name)
|
|
|
|
|
|
|
|
def is_constant(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2017-12-08 13:41:48 +00:00
|
|
|
class IndexedRef(Ref):
|
|
|
|
def __init__(self, ref, index):
|
|
|
|
self.ref = ref
|
|
|
|
self.index = index
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return isinstance(other, self.__class__) and self.ref == other.ref and self.index == other.index
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.__class__.name) ^ hash(self.ref) ^ hash(self.index)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (self.__class__.__name__, self.ref, self.index)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return '{}+{}'.format(self.ref.name, self.index.name)
|
|
|
|
|
|
|
|
def is_constant(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2017-12-01 12:36:58 +00:00
|
|
|
class AddressRef(Ref):
|
|
|
|
def __init__(self, ref):
|
|
|
|
self.ref = ref
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return self.ref == other.ref
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.__class__.name) ^ hash(self.ref)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r)' % (self.__class__.__name__, self.ref)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return '^{}'.format(self.ref.name)
|
|
|
|
|
|
|
|
def is_constant(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2016-06-16 16:10:43 +00:00
|
|
|
class PartRef(Ref):
|
|
|
|
"""For 'low byte of' location and 'high byte of' location modifiers.
|
|
|
|
|
|
|
|
height=0 = low byte, height=1 = high byte.
|
|
|
|
|
2017-11-17 15:54:50 +00:00
|
|
|
NOTE: Not actually used yet. Might require more thought before it's usable.
|
2016-06-16 16:10:43 +00:00
|
|
|
"""
|
|
|
|
def __init__(self, ref, height):
|
|
|
|
assert isinstance(ref, Ref)
|
|
|
|
assert ref.type == TYPE_WORD
|
|
|
|
self.ref = ref
|
|
|
|
self.height = height
|
|
|
|
self.type = TYPE_BYTE
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return isinstance(other, PartRef) and (
|
|
|
|
other.height == self.height and other.ref == self.ref
|
|
|
|
)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.ref) ^ hash(self.height) ^ hash(self.type)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (self.__class__.__name__, self.ref, self.height)
|
|
|
|
|
|
|
|
def is_constant(self):
|
|
|
|
return self.ref.is_constant()
|
|
|
|
|
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class ConstantRef(Ref):
|
|
|
|
def __init__(self, type, value):
|
|
|
|
self.type = type
|
2015-10-16 09:40:38 +00:00
|
|
|
self.value = value
|
|
|
|
|
2015-10-16 22:12:52 +00:00
|
|
|
def __eq__(self, other):
|
2015-10-18 16:23:01 +00:00
|
|
|
return isinstance(other, ConstantRef) and (
|
|
|
|
other.type == self.type and other.value == self.value
|
|
|
|
)
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
def __hash__(self):
|
|
|
|
return hash(str(self.value) + str(self.type))
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-22 19:01:02 +00:00
|
|
|
def is_constant(self):
|
|
|
|
return True
|
|
|
|
|
2017-12-07 12:48:56 +00:00
|
|
|
def high_byte(self):
|
|
|
|
return (self.value >> 8) & 255
|
|
|
|
|
|
|
|
def low_byte(self):
|
|
|
|
return self.value & 255
|
|
|
|
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
REG_A = LocationRef(TYPE_BYTE, 'a')
|
|
|
|
REG_X = LocationRef(TYPE_BYTE, 'x')
|
|
|
|
REG_Y = LocationRef(TYPE_BYTE, 'y')
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
FLAG_Z = LocationRef(TYPE_BIT, 'z')
|
|
|
|
FLAG_C = LocationRef(TYPE_BIT, 'c')
|
|
|
|
FLAG_N = LocationRef(TYPE_BIT, 'n')
|
|
|
|
FLAG_V = LocationRef(TYPE_BIT, 'v')
|