From 35a1053439adce04c21cdba0bba94f9b7cdfe379 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Wed, 12 Dec 2018 10:34:25 +0000 Subject: [PATCH] Support more modes on `add` and `sub`. --- HISTORY.md | 2 + doc/SixtyPical.md | 12 ++++- src/sixtypical/analyzer.py | 6 +++ src/sixtypical/compiler.py | 32 ++++++++++++ tests/SixtyPical Analysis.md | 58 ++++++++++++++++++++- tests/SixtyPical Compilation.md | 89 +++++++++++++++++++++++++++++---- 6 files changed, 184 insertions(+), 15 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 4ebbea9..03db443 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -12,6 +12,8 @@ History of SixtyPical * `cmp` instruction can now perform a 16-bit unsigned comparison of `word` memory locations and `word` literals (at the cost of trashing the `a` register.) +* `add` (resp. `sub`) now support adding (resp. subtracting) a + byte location or a byte literal from a byte location. * Fixed pathological memory use in the lexical scanner - should be much less inefficient now when parsing large source files. * Reorganized the examples in `eg/rudiments/` to make them diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index a4b4d97..d9b177d 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -333,8 +333,9 @@ this mode is used. Adds the contents of src to dest and stores the result in dest. -* It is illegal if src OR dest OR c is uninitialized. +* It is illegal if src OR dest OR `c` is uninitialized. * It is illegal if dest is read-only. +* It is illegal if dest is `x` or `y`. * It is illegal if dest does not occur in the WRITES of the current routine. Affects n, z, c, and v flags, requiring that they be in the WRITES, @@ -345,6 +346,9 @@ dest and src continue to be initialized afterwards. In addition, if dest is of `word` type, then src must also be of `word` type, and in this case this instruction trashes the `a` register. +In fact, this instruction trashes the `a` register in all cases except +when the dest is `a`. + NOTE: If dest is a pointer, the addition does not check if the result of the pointer arithmetic continues to be valid (within a buffer) or not. @@ -367,8 +371,9 @@ and initializing them afterwards. Subtracts the contents of src from dest and stores the result in dest. -* It is illegal if src OR dest OR c is uninitialized. +* It is illegal if src OR dest OR `c` is uninitialized. * It is illegal if dest is read-only. +* It is illegal if dest is `x` or `y`. * It is illegal if dest does not occur in the WRITES of the current routine. Affects n, z, c, and v flags, requiring that they be in the WRITES, @@ -379,6 +384,9 @@ dest and src continue to be initialized afterwards. In addition, if dest is of `word` type, then src must also be of `word` type, and in this case this instruction trashes the `a` register. +In fact, this instruction trashes the `a` register in all cases except +when the dest is `a`. + ### dec ### dec diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 9837424..a12680c 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -533,6 +533,9 @@ class Analyzer(object): context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) elif src.type == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) + if dest != REG_A: + context.set_touched(REG_A) + context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src) if dest.type == TYPE_WORD: @@ -551,6 +554,9 @@ class Analyzer(object): context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) elif src.type == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) + if dest != REG_A: + context.set_touched(REG_A) + context.set_unmeaningful(REG_A) else: self.assert_type(TYPE_WORD, src, dest) context.set_touched(REG_A) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 3659014..fe1e1c5 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -244,6 +244,8 @@ class Compiler(object): raise UnsupportedOpcodeError(instr) self.emitter.emit(op_cls(operand)) elif opcode == 'add': + if dest == REG_X or dest == REG_Y: + raise UnsupportedOpcodeError(instr) if dest == REG_A: if isinstance(src, ConstantRef): self.emitter.emit(ADC(Immediate(Byte(src.value)))) @@ -251,6 +253,20 @@ class Compiler(object): self.emitter.emit(ADC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name)))) else: self.emitter.emit(ADC(Absolute(self.get_label(src.name)))) + elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE: + if isinstance(src, ConstantRef): + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(dest_label))) + self.emitter.emit(ADC(Immediate(Byte(src.low_byte())))) + self.emitter.emit(STA(Absolute(dest_label))) + elif isinstance(src, LocationRef): + src_label = self.get_label(src.name) + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(dest_label))) + self.emitter.emit(ADC(Absolute(src_label))) + self.emitter.emit(STA(Absolute(dest_label))) + else: + raise UnsupportedOpcodeError(instr) elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) @@ -294,6 +310,8 @@ class Compiler(object): else: raise UnsupportedOpcodeError(instr) elif opcode == 'sub': + if dest == REG_X or dest == REG_Y: + raise UnsupportedOpcodeError(instr) if dest == REG_A: if isinstance(src, ConstantRef): self.emitter.emit(SBC(Immediate(Byte(src.value)))) @@ -301,6 +319,20 @@ class Compiler(object): self.emitter.emit(SBC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name)))) else: self.emitter.emit(SBC(Absolute(self.get_label(src.name)))) + elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE: + if isinstance(src, ConstantRef): + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(dest_label))) + self.emitter.emit(SBC(Immediate(Byte(src.low_byte())))) + self.emitter.emit(STA(Absolute(dest_label))) + elif isinstance(src, LocationRef): + src_label = self.get_label(src.name) + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(dest_label))) + self.emitter.emit(SBC(Absolute(src_label))) + self.emitter.emit(STA(Absolute(dest_label))) + else: + raise UnsupportedOpcodeError(instr) elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD: if isinstance(src, ConstantRef): dest_label = self.get_label(dest.name) diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 7990324..6d645d6 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -870,7 +870,7 @@ You can `add` a byte constant to a byte memory location. | byte lives | define main routine | inputs a, lives - | outputs lives + | outputs a, lives | trashes c, z, v, n | { | st off, c @@ -878,6 +878,33 @@ You can `add` a byte constant to a byte memory location. | } ? UnmeaningfulOutputError: a +You can `add` a byte memory location to another byte memory location. +This trashes `a`. + + | byte lives + | byte extra + | define main routine + | inputs a, lives, extra + | outputs lives + | trashes a, c, z, v, n + | { + | st off, c + | add lives, extra + | } + = ok + + | byte lives + | byte extra + | define main routine + | inputs a, lives, extra + | outputs a, lives + | trashes c, z, v, n + | { + | st off, c + | add lives, extra + | } + ? UnmeaningfulOutputError: a + You can `add` a word constant to a word memory location. | word score @@ -1040,7 +1067,7 @@ You can `sub` a byte constant from a byte memory location. | byte lives | define main routine | inputs a, lives - | outputs lives + | outputs a, lives | trashes c, z, v, n | { | st on, c @@ -1048,6 +1075,33 @@ You can `sub` a byte constant from a byte memory location. | } ? UnmeaningfulOutputError: a +You can `sub` a byte memory location from another byte memory location. +This trashes `a`. + + | byte lives + | byte extra + | define main routine + | inputs a, lives, extra + | outputs lives + | trashes a, c, z, v, n + | { + | st on, c + | sub lives, extra + | } + = ok + + | byte lives + | byte extra + | define main routine + | inputs a, lives, extra + | outputs a, lives + | trashes c, z, v, n + | { + | st on, c + | sub lives, extra + | } + ? UnmeaningfulOutputError: a + You can `sub` a word constant from a word memory location. | word score diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index 1d25e49..c3a4ec7 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -1030,9 +1030,11 @@ Copying to and from a vector table. Various modes of `add`. | byte lives + | byte extra | word score + | word bonus | define main routine - | inputs lives, score + | inputs lives, score, extra, bonus | outputs lives, score | trashes a, x, y, c, z, v, n | { @@ -1042,19 +1044,84 @@ Various modes of `add`. | st off, c | add a, 7 | add a, lives - | // add x, 7 - | // add y, 7 | add lives, 2 + | add lives, extra | add score, 1999 + | add score, bonus | } - = $080D CLC - = $080E LDA $081F - = $0811 ADC #$CF - = $0813 STA $081F - = $0816 LDA $0820 - = $0819 ADC #$07 - = $081B STA $0820 - = $081E RTS + = $080D LDA #$00 + = $080F LDX #$00 + = $0811 LDY #$00 + = $0813 CLC + = $0814 ADC #$07 + = $0816 ADC $084D + = $0819 LDA $084D + = $081C ADC #$02 + = $081E STA $084D + = $0821 LDA $084D + = $0824 ADC $084E + = $0827 STA $084D + = $082A LDA $084F + = $082D ADC #$CF + = $082F STA $084F + = $0832 LDA $0850 + = $0835 ADC #$07 + = $0837 STA $0850 + = $083A LDA $084F + = $083D ADC $0851 + = $0840 STA $084F + = $0843 LDA $0850 + = $0846 ADC $0852 + = $0849 STA $0850 + = $084C RTS + +Various modes of `sub`. + + | byte lives + | byte extra + | word score + | word bonus + | define main routine + | inputs lives, score, extra, bonus + | outputs lives, score + | trashes a, x, y, c, z, v, n + | { + | ld a, 0 + | ld x, 0 + | ld y, 0 + | st on, c + | sub a, 7 + | sub a, lives + | sub lives, 2 + | sub lives, extra + | sub score, 1999 + | sub score, bonus + | } + = $080D LDA #$00 + = $080F LDX #$00 + = $0811 LDY #$00 + = $0813 SEC + = $0814 SBC #$07 + = $0816 SBC $084D + = $0819 LDA $084D + = $081C SBC #$02 + = $081E STA $084D + = $0821 LDA $084D + = $0824 SBC $084E + = $0827 STA $084D + = $082A LDA $084F + = $082D SBC #$CF + = $082F STA $084F + = $0832 LDA $0850 + = $0835 SBC #$07 + = $0837 STA $0850 + = $083A LDA $084F + = $083D SBC $0851 + = $0840 STA $084F + = $0843 LDA $0850 + = $0846 SBC $0852 + = $0849 STA $0850 + = $084C RTS ### word operations