1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-06-15 14:29:32 +00:00

Require that the program does ^buf to get at the address of buf.

This commit is contained in:
Chris Pressey 2017-12-01 12:36:58 +00:00
parent a95cbb0f47
commit 32389e4422
9 changed files with 72 additions and 46 deletions

View File

@ -7,6 +7,6 @@ routine main
trashes a, z, n, ptr
{
ld y, 0
copy buf, ptr
copy ^buf, ptr
copy 123, [ptr] + y
}

View File

@ -3,7 +3,7 @@
from sixtypical.ast import Program, Routine, Block, Instr
from sixtypical.model import (
TYPE_BYTE, TYPE_BYTE_TABLE, BufferType, PointerType, VectorType, ExecutableType,
ConstantRef, LocationRef, IndirectRef,
ConstantRef, LocationRef, IndirectRef, AddressRef,
REG_A, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
)
@ -113,7 +113,7 @@ class Context(object):
def assert_meaningful(self, *refs, **kwargs):
exception_class = kwargs.get('exception_class', UnmeaningfulReadError)
for ref in refs:
if isinstance(ref, ConstantRef) or ref in self.routines:
if ref.is_constant() or ref in self.routines:
pass
elif isinstance(ref, LocationRef):
if ref not in self._meaningful:
@ -293,34 +293,38 @@ class Analyzer(object):
context.assert_meaningful(src)
elif opcode == 'copy':
# check that their types are compatible
# 1. check that their types are compatible
if isinstance(dest, IndirectRef):
if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
pass
else:
raise TypeMismatchError((src, dest))
elif src.type == dest.type:
pass
elif isinstance(src.type, ExecutableType) and \
isinstance(dest.type, VectorType):
pass
elif isinstance(src.type, BufferType) and \
isinstance(dest.type, PointerType):
pass
elif isinstance(src, AddressRef):
if isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType):
pass
else:
raise TypeMismatchError((src, dest))
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
if src.type == dest.type:
pass
elif isinstance(src.type, ExecutableType) and \
isinstance(dest.type, VectorType):
# if dealing with routines and vectors,
# check that they're not incompatible
if not (src.type.inputs <= dest.type.inputs):
raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs)
if not (src.type.outputs <= dest.type.outputs):
raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs)
if not (src.type.trashes <= dest.type.trashes):
raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes)
else:
raise TypeMismatchError((src, dest))
else:
raise TypeMismatchError((src, dest))
# if dealing with routines and vectors,
# check that they're not incompatible
if isinstance(src.type, ExecutableType) and \
isinstance(dest.type, VectorType):
if not (src.type.inputs <= dest.type.inputs):
raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs)
if not (src.type.outputs <= dest.type.outputs):
raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs)
if not (src.type.trashes <= dest.type.trashes):
raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes)
# 2. check that the context is meaningful
if isinstance(dest, IndirectRef):
context.assert_meaningful(src, REG_Y)

View File

@ -2,7 +2,7 @@
from sixtypical.ast import Program, Routine, Block, Instr
from sixtypical.model import (
ConstantRef, IndirectRef,
ConstantRef, LocationRef, IndirectRef, AddressRef,
TYPE_BIT, TYPE_BYTE, TYPE_WORD, BufferType, PointerType, RoutineType, VectorType,
REG_A, REG_X, REG_Y, FLAG_C
)
@ -284,6 +284,16 @@ class Compiler(object):
raise NotImplementedError((src, dest))
else:
raise NotImplementedError((src, dest))
elif isinstance(src, AddressRef) and isinstance(dest, LocationRef) and \
isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType):
src_label = self.labels[src.ref.name]
dest_label = self.labels[dest.name]
self.emitter.emit(LDA(Immediate(HighAddressByte(src_label))))
self.emitter.emit(STA(ZeroPage(dest_label)))
self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1))))
elif not isinstance(src, (ConstantRef, LocationRef)) or not isinstance(dest, LocationRef):
raise NotImplementedError((src, dest))
elif src.type == TYPE_BYTE and dest.type == TYPE_BYTE:
if isinstance(src, ConstantRef):
raise NotImplementedError
@ -308,14 +318,6 @@ class Compiler(object):
self.emitter.emit(STA(Absolute(dest_label)))
self.emitter.emit(LDA(Absolute(Offset(src_label, 1))))
self.emitter.emit(STA(Absolute(Offset(dest_label, 1))))
elif isinstance(src.type, BufferType) and isinstance(dest.type, PointerType):
# TODO: this maybe should not be the 'copy' opcode at all that means this
src_label = self.labels[src.name]
dest_label = self.labels[dest.name]
self.emitter.emit(LDA(Immediate(HighAddressByte(src_label))))
self.emitter.emit(STA(ZeroPage(dest_label)))
self.emitter.emit(LDA(Immediate(LowAddressByte(src_label))))
self.emitter.emit(STA(ZeroPage(Offset(dest_label, 1))))
elif isinstance(src.type, VectorType) and isinstance(dest.type, VectorType):
src_label = self.labels[src.name]
dest_label = self.labels[dest.name]

View File

@ -109,7 +109,7 @@ class IndirectRef(Ref):
return self.ref == other.ref
def __hash__(self):
return hash(hash('[]') ^ hash(self.ref))
return hash(self.__class__.name) ^ hash(self.ref)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.ref)
@ -122,6 +122,27 @@ class IndirectRef(Ref):
return False
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
class PartRef(Ref):
"""For 'low byte of' location and 'high byte of' location modifiers.

View File

@ -4,7 +4,7 @@ from sixtypical.ast import Program, Defn, Routine, Block, Instr
from sixtypical.model import (
TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE,
RoutineType, VectorType, ExecutableType, BufferType, PointerType,
LocationRef, ConstantRef, IndirectRef,
LocationRef, ConstantRef, IndirectRef, AddressRef,
)
from sixtypical.scanner import Scanner
@ -171,6 +171,9 @@ class Parser(object):
self.scanner.expect('+')
self.scanner.expect('y')
return IndirectRef(loc)
elif self.scanner.consume('^'):
loc = self.locexpr()
return AddressRef(loc)
else:
return self.locexpr()

View File

@ -29,7 +29,7 @@ class Scanner(object):
self.token = None
self.type = 'EOF'
return
if self.scan_pattern(r'\,|\@|\+|\:|\<|\>|\{|\}|\[|\]', 'operator'):
if self.scan_pattern(r'\,|\@|\+|\:|\<|\>|\{|\}|\[|\]|\^', 'operator'):
return
if self.scan_pattern(r'\d+', 'integer literal'):
return

View File

@ -1176,19 +1176,18 @@ Can't `copy` from a `word` to a `byte`.
Buffers and pointers.
Note that `copy buf, ptr` should probably be `copy ^buf, ptr` and `^buf` should not
be considered "reading" buf and should not require it in `inputs` for that reason.
Note that `^buf` is not considered "reading" buf, so does not require it in `inputs`.
TODO: It *should* require it in `outputs`.
| buffer[2048] buf
| pointer ptr
|
| routine main
| inputs buf
| outputs buf, y
| outputs y
| trashes a, z, n, ptr
| {
| ld y, 0
| copy buf, ptr
| copy ^buf, ptr
| copy 123, [ptr] + y
| }
= ok
@ -1199,11 +1198,9 @@ It does use `y`.
| pointer ptr
|
| routine main
| inputs buf
| outputs buf
| trashes a, z, n, ptr
| {
| copy buf, ptr
| copy ^buf, ptr
| copy 123, [ptr] + y
| }
? UnmeaningfulReadError

View File

@ -353,7 +353,7 @@ Buffers and pointers.
| trashes a, z, n, ptr
| {
| ld y, 0
| copy buf, ptr
| copy ^buf, ptr
| }
= 00c0a000a90b85fea9c085ff60
@ -363,12 +363,11 @@ Writing through a pointer.
| pointer ptr @ 254
|
| routine main
| inputs buf
| outputs buf, y
| trashes a, z, n, ptr
| {
| ld y, 0
| copy buf, ptr
| copy ^buf, ptr
| copy 123, [ptr] + y
| }
= 00c0a000a90f85fea9c085ffa97b91fe60

View File

@ -328,7 +328,7 @@ Buffers and pointers.
| pointer ptr
|
| routine main {
| copy buf, ptr
| copy ^buf, ptr
| copy 123, [ptr] + y
| }
= ok