1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-02-21 04:29:14 +00:00

If add and sub can work on words, then cmp can work on words too.

This commit is contained in:
Chris Pressey 2018-11-23 23:00:41 +00:00
parent a765a50c1e
commit dcc944d732
8 changed files with 32 additions and 70 deletions

View File

@ -4,8 +4,8 @@ History of SixtyPical
0.18 0.18
---- ----
* Added `compare` instruction, which is like `cmp` but can * `cmp` instruction can now perform a 16-bit unsigned comparison
directly compare two `word` memory locations (trashing `a`.) of `word` memory locations (at the cost of trashing `a`.)
* Fixed pathological memory use in the lexical scanner - should * Fixed pathological memory use in the lexical scanner - should
be much less inefficient now when parsing large source files. be much less inefficient now when parsing large source files.

View File

@ -376,6 +376,9 @@ and initializing them afterwards.
dest and src continue to be initialized 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 ###
dec <dest-memory-location> dec <dest-memory-location>
@ -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, Affects n, z, and c flags, requiring that they be in the WRITES,
and initializing them afterwards. 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 <dest-memory-location>, <src-memory-location> Note that, like `cmp` is not suitable for making a
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
signed comparison; this article, which mentions signed comparison; this article, which mentions
techniques that a SixtyPical compiler could use to 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). [Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html).
### and, or, xor ### ### and, or, xor ###

View File

@ -505,11 +505,9 @@ class Analyzer(object):
context.assert_meaningful(src, dest) context.assert_meaningful(src, dest)
if isinstance(src, IndexedRef): if isinstance(src, IndexedRef):
context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE)
else: elif src.type == TYPE_BYTE:
self.assert_type(TYPE_BYTE, src, dest) self.assert_type(TYPE_BYTE, src, dest)
context.set_written(FLAG_Z, FLAG_N, FLAG_C) else:
elif opcode == 'compare':
context.assert_meaningful(src, dest)
self.assert_type(TYPE_WORD, src, dest) self.assert_type(TYPE_WORD, src, dest)
context.set_touched(REG_A) context.set_touched(REG_A)
context.set_unmeaningful(REG_A) context.set_unmeaningful(REG_A)

View File

@ -325,8 +325,6 @@ class Compiler(object):
raise UnsupportedOpcodeError(instr) raise UnsupportedOpcodeError(instr)
elif opcode == 'cmp': elif opcode == 'cmp':
self.compile_cmp(instr, instr.src, instr.dest) 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',): elif opcode in ('and', 'or', 'xor',):
cls = { cls = {
'and': AND, 'and': AND,
@ -393,6 +391,17 @@ class Compiler(object):
def compile_cmp(self, instr, src, dest): def compile_cmp(self, instr, src, dest):
"""`instr` is only for reporting purposes""" """`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 = { cls = {
'a': CMP, 'a': CMP,
'x': CPX, 'x': CPX,
@ -408,23 +417,6 @@ class Compiler(object):
else: else:
self.emitter.emit(cls(Absolute(self.get_label(src.name)))) 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): def compile_inc(self, instr, dest):
"""`instr` is only for reporting purposes""" """`instr` is only for reporting purposes"""
if dest == REG_X: if dest == REG_X:

View File

@ -463,14 +463,6 @@ class Parser(object):
dest = self.indlocexpr() dest = self.indlocexpr()
instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
return instr 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"): elif self.scanner.consume("with"):
self.scanner.expect("interrupts") self.scanner.expect("interrupts")
self.scanner.expect("off") self.scanner.expect("off")

View File

@ -1118,9 +1118,7 @@ Some rudimentary tests for `cmp`.
| } | }
? UnmeaningfulReadError: a ? UnmeaningfulReadError: a
### compare ### `cmp` can work on words. In this case, it trashes `a`.
Some rudimentary tests for `compare`.
| word za | word za
| word zb | word zb
@ -1129,7 +1127,7 @@ Some rudimentary tests for `compare`.
| inputs za, zb | inputs za, zb
| trashes a, z, c, n | trashes a, z, c, n
| { | {
| compare za, zb | cmp za, zb
| } | }
= ok = ok
@ -1140,7 +1138,7 @@ Some rudimentary tests for `compare`.
| inputs za, zb | inputs za, zb
| trashes a, z, n | trashes a, z, n
| { | {
| compare za, zb | cmp za, zb
| } | }
? ForbiddenWriteError: c ? ForbiddenWriteError: c
@ -1151,7 +1149,7 @@ Some rudimentary tests for `compare`.
| inputs za, zb | inputs za, zb
| trashes z, c, n | trashes z, c, n
| { | {
| compare za, zb | cmp za, zb
| } | }
? ForbiddenWriteError: a ? ForbiddenWriteError: a
@ -1162,7 +1160,7 @@ Some rudimentary tests for `compare`.
| inputs za | inputs za
| trashes z, c, n | trashes z, c, n
| { | {
| compare za, zb | cmp za, zb
| } | }
? UnmeaningfulReadError: zb ? UnmeaningfulReadError: zb

View File

@ -385,7 +385,7 @@ Some instructions on tables. (3/3)
= $081B DEC $081F,X = $081B DEC $081F,X
= $081E RTS = $081E RTS
Compiling `compare`. Compiling 16-bit `cmp`.
| word za @ 60001 | word za @ 60001
| word zb : 3003 | word zb : 3003
@ -394,7 +394,7 @@ Compiling `compare`.
| inputs za, zb | inputs za, zb
| trashes a, z, c, n | trashes a, z, c, n
| { | {
| compare za, zb | cmp za, zb
| } | }
= $080D LDA $081C = $080D LDA $081C
= $0810 CMP $EA61 = $0810 CMP $EA61

View File

@ -586,16 +586,6 @@ Buffers and pointers.
| } | }
= ok = 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. Routines can be defined in a new style.
| typedef routine | typedef routine