diff --git a/HISTORY.md b/HISTORY.md index 4308bc4..2493386 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,6 +15,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 2298e53..39ed406 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 6612e45..4493d7c 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -852,6 +852,59 @@ Can't `add` to a memory location that isn't writeable. | } ? ForbiddenWriteError: a +You can `add` a byte constant to a byte memory location. + + | byte lives + | define main routine + | inputs a, lives + | outputs lives + | trashes a, c, z, v, n + | { + | st off, c + | add lives, 3 + | } + = ok + +`add`ing a byte constant to a byte memory location trashes `a`. + + | byte lives + | define main routine + | inputs a, lives + | outputs a, lives + | trashes c, z, v, n + | { + | st off, c + | add lives, 3 + | } + ? 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 @@ -996,6 +1049,59 @@ Can't `sub` to a memory location that isn't writeable. | } ? ForbiddenWriteError: a +You can `sub` a byte constant from a byte memory location. + + | byte lives + | define main routine + | inputs a, lives + | outputs lives + | trashes a, c, z, v, n + | { + | st on, c + | sub lives, 3 + | } + = ok + +`sub`ing a byte constant from a byte memory location trashes `a`. + + | byte lives + | define main routine + | inputs a, lives + | outputs a, lives + | trashes c, z, v, n + | { + | st on, c + | sub lives, 3 + | } + ? 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 e00f954..c3a4ec7 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -1025,6 +1025,104 @@ Copying to and from a vector table. = $0842 JMP ($0846) = $0845 RTS +### add, sub + +Various modes of `add`. + + | 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 off, c + | add a, 7 + | add a, lives + | add lives, 2 + | add lives, extra + | add score, 1999 + | add score, bonus + | } + = $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 Adding a constant word to a word memory location.