From ca1c877a608e3193729e569fc1571684cc420562 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 9 Feb 2018 11:23:18 +0000 Subject: [PATCH] Support indirect refs in st, e.g. `st a, [ptr] + y`. --- HISTORY.md | 5 +++-- doc/SixtyPical.md | 15 ++++++++++++++- src/sixtypical/analyzer.py | 18 ++++++++++++++---- src/sixtypical/compiler.py | 23 +++++++++++++++-------- src/sixtypical/parser.py | 7 ++----- tests/SixtyPical Analysis.md | 19 +++++++++++++++++++ tests/SixtyPical Compilation.md | 25 +++++++++++++++++++++++++ 7 files changed, 92 insertions(+), 20 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 70a9244..24c3593 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,8 +4,9 @@ History of SixtyPical 0.12 ---- -* `copy` is now understood to trash `a`, thus `copy ..., a` is not valid. - Indirect addressing is supported in `ld`, as in `ld a, [ptr] + y`, to compensate. +* `copy` is now understood to trash `a`, thus it is not valid to use it in `copy`. + To compensate, indirect addressing is supported in `ld` and `st`, for example, + as `ld a, [ptr] + y` and `st a, [ptr] + y`. * Implements the "union rule for trashes" when analyzing `if` blocks. * Even if we `goto` another routine, we can't trash an output. * Fixed bug where `trash` was not marking the location as being virtually altered. diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index a200c7b..9dae554 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -240,7 +240,7 @@ underlying opcodes. There is another mode of `ld` which reads into `a` indirectly through a pointer. - copy [] + y, + ld a, [] + y The memory location in this syntax must be a pointer. @@ -266,6 +266,19 @@ changed by this instruction (unless of course dest is a flag.) If and only if dest is a byte table, the index-memory-location must be given. +There is another mode of `st` which write `a` into memory, indirectly through +a pointer. + + st a, [] + y + +The memory location in this syntax must be a pointer. + +This syntax copies the constents of the `a` register into +the contents of memory at the pointer (offset by the `y` register). + +In addition to the constraints above, `y` must be initialized before +this mode is used. + ### copy ### copy , diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index fc3f2f6..b63ff59 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -273,18 +273,28 @@ class Analyzer(object): context.assert_meaningful(src) context.set_written(dest, FLAG_Z, FLAG_N) elif opcode == 'st': - if instr.index: - if src.type == TYPE_BYTE and TableType.is_a_table_type(dest.type, TYPE_BYTE): + if isinstance(dest, IndexedRef): + if src.type == TYPE_BYTE and TableType.is_a_table_type(dest.ref.type, TYPE_BYTE): pass else: raise TypeMismatchError((src, dest)) - context.assert_meaningful(instr.index) + context.assert_meaningful(dest.index) + context.set_written(dest.ref) + elif isinstance(dest, IndirectRef): + # copying this analysis from the matching branch in `copy`, below + if isinstance(dest.ref.type, PointerType) and src.type == TYPE_BYTE: + pass + else: + raise TypeMismatchError((src, dest)) + context.assert_meaningful(dest.ref, REG_Y) + context.set_written(dest.ref) elif src.type != dest.type: raise TypeMismatchError('%r and %r in %s' % (src, dest, self.current_routine.name) ) + else: + context.set_written(dest) context.assert_meaningful(src) - context.set_written(dest) elif opcode == 'add': context.assert_meaningful(src, dest, FLAG_C) if src.type == TYPE_BYTE: diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 72b7775..96bb121 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -137,8 +137,6 @@ class Compiler(object): self.emitter.emit(LDA(AbsoluteY(self.labels[src.name]))) elif isinstance(src, IndirectRef) and isinstance(src.ref.type, PointerType): self.emitter.emit(LDA(IndirectY(self.labels[src.ref.name]))) - elif isinstance(src, IndirectRef) and src.index == REG_Y: - self.emitter.emit(LDA(AbsoluteY(self.labels[src.name]))) else: self.emitter.emit(LDA(Absolute(self.labels[src.name]))) elif dest == REG_X: @@ -172,14 +170,23 @@ class Compiler(object): REG_X: STX, REG_Y: STY }.get(src, None) - mode_cls = { - REG_X: AbsoluteX, - REG_Y: AbsoluteY, - None: Absolute - }.get(instr.index, None) + + if isinstance(dest, IndexedRef): + mode_cls = { + REG_X: AbsoluteX, + REG_Y: AbsoluteY, + }[dest.index] + label = self.labels[dest.ref.name] + elif isinstance(dest, IndirectRef) and isinstance(dest.ref.type, PointerType): + mode_cls = IndirectY + label = self.labels[dest.ref.name] + else: + mode_cls = Absolute + label = self.labels[dest.name] + if op_cls is None or mode_cls is None: raise UnsupportedOpcodeError(instr) - self.emitter.emit(op_cls(mode_cls(self.labels[dest.name]))) + self.emitter.emit(op_cls(mode_cls(label))) elif opcode == 'add': if dest == REG_A: if isinstance(src, ConstantRef): diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index f0a2b57..640557d 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -339,11 +339,8 @@ class Parser(object): self.scanner.scan() src = self.locexpr() self.scanner.expect(',') - dest = self.locexpr() - index = None - if self.scanner.consume('+'): - index = self.locexpr() - return Instr(opcode=opcode, dest=dest, src=src, index=index) + dest = self.indlocexpr() + return Instr(opcode=opcode, dest=dest, src=src, index=None) elif self.scanner.token in ("shl", "shr", "inc", "dec"): opcode = self.scanner.token self.scanner.scan() diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 39c8603..641628a 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1763,6 +1763,25 @@ not `copy`. | } = ok +Write the `a` register through a pointer. Note that this is done with `st`, +not `copy`. + + | buffer[2048] buf + | pointer ptr + | byte foo + | + | routine main + | inputs buf + | outputs buf + | trashes a, y, z, n, ptr + | { + | ld y, 0 + | copy ^buf, ptr + | ld a, 255 + | st a, [ptr] + y + | } + = ok + ### routines ### Routines are constants. You need not, and in fact cannot, specify a constant diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index df9ae65..5570fda 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -858,6 +858,31 @@ Read through a pointer, into a byte storage location, or the `a` register. = $081C LDA ($FE),Y = $081E RTS +Write the `a` register through a pointer. + + | buffer[2048] buf + | pointer ptr @ 254 + | byte foo + | + | routine main + | inputs buf + | outputs buf + | trashes a, y, z, n, ptr + | { + | ld y, 0 + | copy ^buf, ptr + | ld a, 255 + | st a, [ptr] + y + | } + = $080D LDY #$00 + = $080F LDA #$1C + = $0811 STA $FE + = $0813 LDA #$08 + = $0815 STA $FF + = $0817 LDA #$FF + = $0819 STA ($FE),Y + = $081B RTS + Add a word memory location, and a literal word, to a pointer, and then read through it. Note that this is *not* range-checked. (Yet.)