From e74c7f2b31613c489ea7c92fdde1a29c331857cb Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 23 Nov 2018 22:09:28 +0000 Subject: [PATCH 1/6] Initial attempt at 16-bit compare. Not super well tested yet. --- doc/SixtyPical.md | 20 +++++++++++--- src/sixtypical/analyzer.py | 6 +++++ src/sixtypical/compiler.py | 19 +++++++++++++ src/sixtypical/parser.py | 8 ++++++ tests/SixtyPical Analysis.md | 48 +++++++++++++++++++++++++++++++++ tests/SixtyPical Compilation.md | 20 ++++++++++++++ tests/SixtyPical Syntax.md | 10 +++++++ 7 files changed, 128 insertions(+), 3 deletions(-) diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index 1955fe8..be9d072 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -288,9 +288,9 @@ this mode is used. copy , -Reads from src and writes to dest. Differs from `st` in that is able to -copy more general types of data (for example, vectors,) and it trashes the -`z` and `n` flags and the `a` register. +Reads from src and writes to dest. Differs from `ld` and `st` in that +it is able to copy more general types of data (for example, vectors,) +and it trashes the `z` and `n` flags and the `a` register. * It is illegal if dest is read-only. * It is illegal if dest does not occur in the WRITES of the current routine. @@ -401,6 +401,20 @@ does not store the result anywhere, only sets the resulting flags. Affects n, z, and c flags, requiring that they be in the WRITES, and initializing them afterwards. +### compare ### + + compare , + +Subtracts the contents of src from dest, discarding the result +and only setting the resulting flags. Differs from `cmp` in +that it is able to work on more general types of data (notably, +words) and it trashes the `a` register. + +* It is illegal if src OR dest is uninitialized. + +Affects n, z, and c flags, requiring that they be in the WRITES, +and initializing them afterwards. + ### and, or, xor ### and , diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 98959e1..4b32631 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -508,6 +508,12 @@ class Analyzer(object): else: self.assert_type(TYPE_BYTE, src, dest) context.set_written(FLAG_Z, FLAG_N, FLAG_C) + elif opcode == 'compare': + context.assert_meaningful(src, dest) + self.assert_type(TYPE_WORD, src, dest) + context.set_touched(REG_A) + context.set_unmeaningful(REG_A) + context.set_written(FLAG_Z, FLAG_N, FLAG_C) elif opcode == 'and': if isinstance(src, IndexedRef): context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 3061443..d3a9f31 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -325,6 +325,8 @@ class Compiler(object): raise UnsupportedOpcodeError(instr) elif opcode == 'cmp': self.compile_cmp(instr, instr.src, instr.dest) + elif opcode == 'compare': + self.compile_compare(instr, instr.src, instr.dest) elif opcode in ('and', 'or', 'xor',): cls = { 'and': AND, @@ -406,6 +408,23 @@ class Compiler(object): else: self.emitter.emit(cls(Absolute(self.get_label(src.name)))) + def compile_compare(self, instr, src, dest): + """`instr` is only for reporting purposes""" + if not isinstance(src, LocationRef) or not isinstance(dest, LocationRef): + raise UnsupportedOpcodeError(instr) + if src.type != TYPE_WORD or dest.type != TYPE_WORD: + raise UnsupportedOpcodeError(instr) + + src_label = self.get_label(src.name) + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(src_label))) + self.emitter.emit(CMP(Absolute(dest_label))) + end_label = Label('end_label') + self.emitter.emit(BNE(Relative(end_label))) + self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) + self.emitter.emit(CMP(Absolute(Offset(dest_label, 1)))) + self.emitter.resolve_label(end_label) + def compile_inc(self, instr, dest): """`instr` is only for reporting purposes""" if dest == REG_X: diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 07f6f1c..4440142 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -463,6 +463,14 @@ class Parser(object): dest = self.indlocexpr() instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) return instr + elif self.scanner.token in ("compare",): + opcode = self.scanner.token + self.scanner.scan() + dest = self.locexpr() + self.scanner.expect(',') + src = self.indexed_locexpr() + instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) + return instr elif self.scanner.consume("with"): self.scanner.expect("interrupts") self.scanner.expect("off") diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index b393e07..3d689e3 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1118,6 +1118,54 @@ Some rudimentary tests for `cmp`. | } ? UnmeaningfulReadError: a +### compare ### + +Some rudimentary tests for `compare`. + + | word za + | word zb + | + | define main routine + | inputs za, zb + | trashes a, z, c, n + | { + | compare za, zb + | } + = ok + + | word za + | word zb + | + | define main routine + | inputs za, zb + | trashes a, z, n + | { + | compare za, zb + | } + ? ForbiddenWriteError: c + + | word za + | word zb + | + | define main routine + | inputs za, zb + | trashes z, c, n + | { + | compare za, zb + | } + ? ForbiddenWriteError: a + + | word za + | word zb + | + | define main routine + | inputs za + | trashes z, c, n + | { + | compare za, zb + | } + ? UnmeaningfulReadError: zb + ### and ### Some rudimentary tests for `and`. diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index 87984df..40943e2 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -385,6 +385,26 @@ Some instructions on tables. (3/3) = $081B DEC $081F,X = $081E RTS +Compiling `compare`. + + | word za @ 60001 + | word zb : 3003 + | + | define main routine + | inputs za, zb + | trashes a, z, c, n + | { + | compare za, zb + | } + = $080D LDA $081C + = $0810 CMP $EA61 + = $0813 BNE $081B + = $0815 LDA $081D + = $0818 CMP $EA62 + = $081B RTS + = $081C .byte $BB + = $081D .byte $0B + Compiling `if`. | define main routine diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index 3409e63..253f66f 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -586,6 +586,16 @@ Buffers and pointers. | } = ok +Comparison of words. + + | word za + | word zb + | + | define main routine inputs za, zb { + | compare za, zb + | } + = ok + Routines can be defined in a new style. | typedef routine From a765a50c1e7da2a0c7766732eaefb05efd12edc0 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 23 Nov 2018 22:23:41 +0000 Subject: [PATCH 2/6] Notes on `compare`. --- HISTORY.md | 2 ++ TODO.md | 11 ----------- doc/SixtyPical.md | 6 ++++++ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 1376472..3d6fd45 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,8 @@ History of SixtyPical 0.18 ---- +* Added `compare` instruction, which is like `cmp` but can + directly compare two `word` memory locations (trashing `a`.) * Fixed pathological memory use in the lexical scanner - should be much less inefficient now when parsing large source files. diff --git a/TODO.md b/TODO.md index 908f893..e69cb35 100644 --- a/TODO.md +++ b/TODO.md @@ -1,17 +1,6 @@ TODO for SixtyPical =================== -### 16-bit `cmp` - -This is because we don't actually want `low` and `high` address operators -that turn `word` type into `byte`. - -This is because this immediately makes things harder (that is, effectively -impossible) to analyze. - -16-bit `cmp` also benefits from some special differences between `cmp` -and `sub` on 6502, so it would be nice to capture them. - ### Save values to other-than-the-stack Allow diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index be9d072..ef63f87 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -415,6 +415,12 @@ words) and it trashes the `a` register. Affects n, z, and c flags, requiring that they be in the WRITES, and initializing them afterwards. +Note that, like `cmp`, `compare` is not suitable for making a +signed comparison; this article, which mentions +techniques that a SixtyPical compiler could use to +implement `compare`, also explains why that is: +[Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html). + ### and, or, xor ### and , From dcc944d732e4be70be6318c16a0431a67276881f Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 23 Nov 2018 23:00:41 +0000 Subject: [PATCH 3/6] If add and sub can work on words, then cmp can work on words too. --- HISTORY.md | 4 ++-- doc/SixtyPical.md | 22 +++++++--------------- src/sixtypical/analyzer.py | 12 +++++------- src/sixtypical/compiler.py | 30 +++++++++++------------------- src/sixtypical/parser.py | 8 -------- tests/SixtyPical Analysis.md | 12 +++++------- tests/SixtyPical Compilation.md | 4 ++-- tests/SixtyPical Syntax.md | 10 ---------- 8 files changed, 32 insertions(+), 70 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 3d6fd45..32f6915 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,8 +4,8 @@ History of SixtyPical 0.18 ---- -* Added `compare` instruction, which is like `cmp` but can - directly compare two `word` memory locations (trashing `a`.) +* `cmp` instruction can now perform a 16-bit unsigned comparison + of `word` memory locations (at the cost of trashing `a`.) * Fixed pathological memory use in the lexical scanner - should be much less inefficient now when parsing large source files. diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index ef63f87..151fca3 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -376,6 +376,9 @@ and initializing them afterwards. 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. + ### dec ### dec @@ -401,24 +404,13 @@ does not store the result anywhere, only sets the resulting flags. Affects n, z, and c flags, requiring that they be in the WRITES, and initializing them afterwards. -### compare ### +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. - compare , - -Subtracts the contents of src from dest, discarding the result -and only setting the resulting flags. Differs from `cmp` in -that it is able to work on more general types of data (notably, -words) and it trashes the `a` register. - -* It is illegal if src OR dest is uninitialized. - -Affects n, z, and c flags, requiring that they be in the WRITES, -and initializing them afterwards. - -Note that, like `cmp`, `compare` is not suitable for making a +Note that, like `cmp` is not suitable for making a signed comparison; this article, which mentions techniques that a SixtyPical compiler could use to -implement `compare`, also explains why that is: +implement `cmp`, also explains why that is: [Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html). ### and, or, xor ### diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 4b32631..97f6e50 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -505,14 +505,12 @@ class Analyzer(object): context.assert_meaningful(src, dest) if isinstance(src, IndexedRef): context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) - else: + elif src.type == TYPE_BYTE: self.assert_type(TYPE_BYTE, src, dest) - context.set_written(FLAG_Z, FLAG_N, FLAG_C) - elif opcode == 'compare': - context.assert_meaningful(src, dest) - self.assert_type(TYPE_WORD, src, dest) - context.set_touched(REG_A) - context.set_unmeaningful(REG_A) + else: + self.assert_type(TYPE_WORD, src, dest) + context.set_touched(REG_A) + context.set_unmeaningful(REG_A) context.set_written(FLAG_Z, FLAG_N, FLAG_C) elif opcode == 'and': if isinstance(src, IndexedRef): diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index d3a9f31..8d6ed5d 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -325,8 +325,6 @@ class Compiler(object): raise UnsupportedOpcodeError(instr) elif opcode == 'cmp': self.compile_cmp(instr, instr.src, instr.dest) - elif opcode == 'compare': - self.compile_compare(instr, instr.src, instr.dest) elif opcode in ('and', 'or', 'xor',): cls = { 'and': AND, @@ -393,6 +391,17 @@ class Compiler(object): def compile_cmp(self, instr, src, dest): """`instr` is only for reporting purposes""" + if isinstance(src, LocationRef) and src.type == TYPE_WORD: + src_label = self.get_label(src.name) + dest_label = self.get_label(dest.name) + self.emitter.emit(LDA(Absolute(src_label))) + self.emitter.emit(CMP(Absolute(dest_label))) + end_label = Label('end_label') + self.emitter.emit(BNE(Relative(end_label))) + self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) + self.emitter.emit(CMP(Absolute(Offset(dest_label, 1)))) + self.emitter.resolve_label(end_label) + return cls = { 'a': CMP, 'x': CPX, @@ -408,23 +417,6 @@ class Compiler(object): else: self.emitter.emit(cls(Absolute(self.get_label(src.name)))) - def compile_compare(self, instr, src, dest): - """`instr` is only for reporting purposes""" - if not isinstance(src, LocationRef) or not isinstance(dest, LocationRef): - raise UnsupportedOpcodeError(instr) - if src.type != TYPE_WORD or dest.type != TYPE_WORD: - raise UnsupportedOpcodeError(instr) - - src_label = self.get_label(src.name) - dest_label = self.get_label(dest.name) - self.emitter.emit(LDA(Absolute(src_label))) - self.emitter.emit(CMP(Absolute(dest_label))) - end_label = Label('end_label') - self.emitter.emit(BNE(Relative(end_label))) - self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) - self.emitter.emit(CMP(Absolute(Offset(dest_label, 1)))) - self.emitter.resolve_label(end_label) - def compile_inc(self, instr, dest): """`instr` is only for reporting purposes""" if dest == REG_X: diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 4440142..07f6f1c 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -463,14 +463,6 @@ class Parser(object): dest = self.indlocexpr() instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) return instr - elif self.scanner.token in ("compare",): - opcode = self.scanner.token - self.scanner.scan() - dest = self.locexpr() - self.scanner.expect(',') - src = self.indexed_locexpr() - instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) - return instr elif self.scanner.consume("with"): self.scanner.expect("interrupts") self.scanner.expect("off") diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 3d689e3..e6dab0a 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1118,9 +1118,7 @@ Some rudimentary tests for `cmp`. | } ? UnmeaningfulReadError: a -### compare ### - -Some rudimentary tests for `compare`. +`cmp` can work on words. In this case, it trashes `a`. | word za | word zb @@ -1129,7 +1127,7 @@ Some rudimentary tests for `compare`. | inputs za, zb | trashes a, z, c, n | { - | compare za, zb + | cmp za, zb | } = ok @@ -1140,7 +1138,7 @@ Some rudimentary tests for `compare`. | inputs za, zb | trashes a, z, n | { - | compare za, zb + | cmp za, zb | } ? ForbiddenWriteError: c @@ -1151,7 +1149,7 @@ Some rudimentary tests for `compare`. | inputs za, zb | trashes z, c, n | { - | compare za, zb + | cmp za, zb | } ? ForbiddenWriteError: a @@ -1162,7 +1160,7 @@ Some rudimentary tests for `compare`. | inputs za | trashes z, c, n | { - | compare za, zb + | cmp za, zb | } ? UnmeaningfulReadError: zb diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index 40943e2..d7e057c 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -385,7 +385,7 @@ Some instructions on tables. (3/3) = $081B DEC $081F,X = $081E RTS -Compiling `compare`. +Compiling 16-bit `cmp`. | word za @ 60001 | word zb : 3003 @@ -394,7 +394,7 @@ Compiling `compare`. | inputs za, zb | trashes a, z, c, n | { - | compare za, zb + | cmp za, zb | } = $080D LDA $081C = $0810 CMP $EA61 diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index 253f66f..3409e63 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -586,16 +586,6 @@ Buffers and pointers. | } = ok -Comparison of words. - - | word za - | word zb - | - | define main routine inputs za, zb { - | compare za, zb - | } - = ok - Routines can be defined in a new style. | typedef routine From 2d767e9fe77d396cc5222be57ae0272ada31fbae Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 23 Nov 2018 23:11:06 +0000 Subject: [PATCH 4/6] Add example program that suggests we've got the arguments backwards. --- eg/rudiments/cmp.60p | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 eg/rudiments/cmp.60p diff --git a/eg/rudiments/cmp.60p b/eg/rudiments/cmp.60p new file mode 100644 index 0000000..23ec7ee --- /dev/null +++ b/eg/rudiments/cmp.60p @@ -0,0 +1,74 @@ +// Should print ENLGG + +word w1 +word w2 + +define chrout routine + inputs a + trashes a + @ 65490 + +define main routine + outputs w1, w2 + trashes a, x, y, z, n, c, v +{ + copy 4000, w1 + copy 4000, w2 + + cmp w1, w2 + if z { + ld a, 69 // E + call chrout + } else { + ld a, 78 // N + call chrout + } + + copy 4000, w1 + copy 4001, w2 + + cmp w1, w2 + if z { + ld a, 69 // E + call chrout + } else { + ld a, 78 // N + call chrout + } + + copy 20000, w1 + copy 20001, w2 + + cmp w1, w2 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } + + copy 20001, w1 + copy 20001, w2 + + cmp w1, w2 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } + + copy 20002, w1 + copy 20001, w2 + + cmp w1, w2 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } +} From 046e43cd668e86057443f03ec1c87f91f20a5435 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Tue, 27 Nov 2018 13:05:19 +0000 Subject: [PATCH 5/6] Add another example. Even more convincing that the order is wrong. --- eg/rudiments/cmp-byte.60p | 74 ++++++++++++++++++++++++++ eg/rudiments/{cmp.60p => cmp-word.60p} | 14 +++-- 2 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 eg/rudiments/cmp-byte.60p rename eg/rudiments/{cmp.60p => cmp-word.60p} (87%) diff --git a/eg/rudiments/cmp-byte.60p b/eg/rudiments/cmp-byte.60p new file mode 100644 index 0000000..c2613d9 --- /dev/null +++ b/eg/rudiments/cmp-byte.60p @@ -0,0 +1,74 @@ +// Should print ENGGL + +byte b + +define chrout routine + inputs a + trashes a + @ 65490 + +define main routine + outputs b + trashes a, x, y, z, n, c, v +{ + ld a, 40 + st a, b + + cmp a, b + if z { + ld a, 69 // E + call chrout + } else { + ld a, 78 // N + call chrout + } + + ld a, 41 + st a, b + ld a, 40 + + cmp a, b + if z { + ld a, 69 // E + call chrout + } else { + ld a, 78 // N + call chrout + } + + ld a, 20 + st a, b + + ld a, 21 + + cmp a, b // 21 >= 20 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } + + ld a, 20 + + cmp a, b // 20 >= 21 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } + + ld a, 19 + + cmp a, b // 19 < 21 + if c { + ld a, 71 // G + call chrout + } else { + ld a, 76 // L + call chrout + } +} diff --git a/eg/rudiments/cmp.60p b/eg/rudiments/cmp-word.60p similarity index 87% rename from eg/rudiments/cmp.60p rename to eg/rudiments/cmp-word.60p index 23ec7ee..ffbd46a 100644 --- a/eg/rudiments/cmp.60p +++ b/eg/rudiments/cmp-word.60p @@ -1,4 +1,4 @@ -// Should print ENLGG +// Should print ENGGL word w1 word w2 @@ -36,10 +36,10 @@ define main routine call chrout } - copy 20000, w1 + copy 20002, w1 copy 20001, w2 - cmp w1, w2 + cmp w1, w2 // 20002 >= 20001 if c { ld a, 71 // G call chrout @@ -49,9 +49,8 @@ define main routine } copy 20001, w1 - copy 20001, w2 - cmp w1, w2 + cmp w1, w2 // 20001 >= 20001 if c { ld a, 71 // G call chrout @@ -60,10 +59,9 @@ define main routine call chrout } - copy 20002, w1 - copy 20001, w2 + copy 20000, w1 - cmp w1, w2 + cmp w1, w2 // 20000 < 20001 if c { ld a, 71 // G call chrout From 94ee042a1e93457d1e9152a85ab0b78e8241e8df Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Tue, 27 Nov 2018 13:12:55 +0000 Subject: [PATCH 6/6] Fix order of operands in word-sized `cmp`. --- doc/SixtyPical.md | 5 ++++- eg/rudiments/cmp-byte.60p | 4 ++-- src/sixtypical/compiler.py | 8 ++++---- tests/SixtyPical Compilation.md | 8 ++++---- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index 151fca3..a4b4d97 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -398,6 +398,9 @@ and initializing them afterwards. Subtracts the contents of src from dest (without considering carry) but does not store the result anywhere, only sets the resulting flags. +This means that `z` is set if src and dest are equal, +and `c` is set if dest is greater than or equal to src +(`c` is unset if dest is less than src.) * It is illegal if src OR dest is uninitialized. @@ -407,7 +410,7 @@ and initializing them 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. -Note that, like `cmp` is not suitable for making a +Note that `cmp` is not suitable for making a signed comparison; this article, which mentions techniques that a SixtyPical compiler could use to implement `cmp`, also explains why that is: diff --git a/eg/rudiments/cmp-byte.60p b/eg/rudiments/cmp-byte.60p index c2613d9..fdccd48 100644 --- a/eg/rudiments/cmp-byte.60p +++ b/eg/rudiments/cmp-byte.60p @@ -52,7 +52,7 @@ define main routine ld a, 20 - cmp a, b // 20 >= 21 + cmp a, b // 20 >= 20 if c { ld a, 71 // G call chrout @@ -63,7 +63,7 @@ define main routine ld a, 19 - cmp a, b // 19 < 21 + cmp a, b // 19 < 20 if c { ld a, 71 // G call chrout diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 8d6ed5d..a2b983d 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -394,12 +394,12 @@ class Compiler(object): if isinstance(src, LocationRef) and src.type == TYPE_WORD: src_label = self.get_label(src.name) dest_label = self.get_label(dest.name) - self.emitter.emit(LDA(Absolute(src_label))) - self.emitter.emit(CMP(Absolute(dest_label))) + self.emitter.emit(LDA(Absolute(dest_label))) + self.emitter.emit(CMP(Absolute(src_label))) end_label = Label('end_label') self.emitter.emit(BNE(Relative(end_label))) - self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) - self.emitter.emit(CMP(Absolute(Offset(dest_label, 1)))) + self.emitter.emit(LDA(Absolute(Offset(dest_label, 1)))) + self.emitter.emit(CMP(Absolute(Offset(src_label, 1)))) self.emitter.resolve_label(end_label) return cls = { diff --git a/tests/SixtyPical Compilation.md b/tests/SixtyPical Compilation.md index d7e057c..d61ef30 100644 --- a/tests/SixtyPical Compilation.md +++ b/tests/SixtyPical Compilation.md @@ -396,11 +396,11 @@ Compiling 16-bit `cmp`. | { | cmp za, zb | } - = $080D LDA $081C - = $0810 CMP $EA61 + = $080D LDA $EA61 + = $0810 CMP $081C = $0813 BNE $081B - = $0815 LDA $081D - = $0818 CMP $EA62 + = $0815 LDA $EA62 + = $0818 CMP $081D = $081B RTS = $081C .byte $BB = $081D .byte $0B