mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-29 18:49:22 +00:00
Merge pull request #15 from catseye/16-bit-compare
16-bit compare instruction
This commit is contained in:
commit
f99cf47661
@ -4,6 +4,8 @@ History of SixtyPical
|
|||||||
0.18
|
0.18
|
||||||
----
|
----
|
||||||
|
|
||||||
|
* `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
|
* 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.
|
||||||
|
|
||||||
|
11
TODO.md
11
TODO.md
@ -1,17 +1,6 @@
|
|||||||
TODO for SixtyPical
|
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
|
### Save values to other-than-the-stack
|
||||||
|
|
||||||
Allow
|
Allow
|
||||||
|
@ -288,9 +288,9 @@ this mode is used.
|
|||||||
|
|
||||||
copy <src-memory-location>, <dest-memory-location>
|
copy <src-memory-location>, <dest-memory-location>
|
||||||
|
|
||||||
Reads from src and writes to dest. Differs from `st` in that is able to
|
Reads from src and writes to dest. Differs from `ld` and `st` in that
|
||||||
copy more general types of data (for example, vectors,) and it trashes the
|
it is able to copy more general types of data (for example, vectors,)
|
||||||
`z` and `n` flags and the `a` register.
|
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 is read-only.
|
||||||
* It is illegal if dest does not occur in the WRITES of the current routine.
|
* It is illegal if dest does not occur in the WRITES of the current routine.
|
||||||
@ -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>
|
||||||
@ -395,12 +398,24 @@ and initializing them afterwards.
|
|||||||
|
|
||||||
Subtracts the contents of src from dest (without considering carry) but
|
Subtracts the contents of src from dest (without considering carry) but
|
||||||
does not store the result anywhere, only sets the resulting flags.
|
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.
|
* It is illegal if src OR dest is uninitialized.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
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 `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:
|
||||||
|
[Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html).
|
||||||
|
|
||||||
### and, or, xor ###
|
### and, or, xor ###
|
||||||
|
|
||||||
and <dest-memory-location>, <src-memory-location>
|
and <dest-memory-location>, <src-memory-location>
|
||||||
|
74
eg/rudiments/cmp-byte.60p
Normal file
74
eg/rudiments/cmp-byte.60p
Normal file
@ -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 >= 20
|
||||||
|
if c {
|
||||||
|
ld a, 71 // G
|
||||||
|
call chrout
|
||||||
|
} else {
|
||||||
|
ld a, 76 // L
|
||||||
|
call chrout
|
||||||
|
}
|
||||||
|
|
||||||
|
ld a, 19
|
||||||
|
|
||||||
|
cmp a, b // 19 < 20
|
||||||
|
if c {
|
||||||
|
ld a, 71 // G
|
||||||
|
call chrout
|
||||||
|
} else {
|
||||||
|
ld a, 76 // L
|
||||||
|
call chrout
|
||||||
|
}
|
||||||
|
}
|
72
eg/rudiments/cmp-word.60p
Normal file
72
eg/rudiments/cmp-word.60p
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Should print ENGGL
|
||||||
|
|
||||||
|
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 20002, w1
|
||||||
|
copy 20001, w2
|
||||||
|
|
||||||
|
cmp w1, w2 // 20002 >= 20001
|
||||||
|
if c {
|
||||||
|
ld a, 71 // G
|
||||||
|
call chrout
|
||||||
|
} else {
|
||||||
|
ld a, 76 // L
|
||||||
|
call chrout
|
||||||
|
}
|
||||||
|
|
||||||
|
copy 20001, w1
|
||||||
|
|
||||||
|
cmp w1, w2 // 20001 >= 20001
|
||||||
|
if c {
|
||||||
|
ld a, 71 // G
|
||||||
|
call chrout
|
||||||
|
} else {
|
||||||
|
ld a, 76 // L
|
||||||
|
call chrout
|
||||||
|
}
|
||||||
|
|
||||||
|
copy 20000, w1
|
||||||
|
|
||||||
|
cmp w1, w2 // 20000 < 20001
|
||||||
|
if c {
|
||||||
|
ld a, 71 // G
|
||||||
|
call chrout
|
||||||
|
} else {
|
||||||
|
ld a, 76 // L
|
||||||
|
call chrout
|
||||||
|
}
|
||||||
|
}
|
@ -505,8 +505,12 @@ 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)
|
||||||
|
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)
|
context.set_written(FLAG_Z, FLAG_N, FLAG_C)
|
||||||
elif opcode == 'and':
|
elif opcode == 'and':
|
||||||
if isinstance(src, IndexedRef):
|
if isinstance(src, IndexedRef):
|
||||||
|
@ -391,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(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(dest_label, 1))))
|
||||||
|
self.emitter.emit(CMP(Absolute(Offset(src_label, 1))))
|
||||||
|
self.emitter.resolve_label(end_label)
|
||||||
|
return
|
||||||
cls = {
|
cls = {
|
||||||
'a': CMP,
|
'a': CMP,
|
||||||
'x': CPX,
|
'x': CPX,
|
||||||
|
@ -1118,6 +1118,52 @@ Some rudimentary tests for `cmp`.
|
|||||||
| }
|
| }
|
||||||
? UnmeaningfulReadError: a
|
? UnmeaningfulReadError: a
|
||||||
|
|
||||||
|
`cmp` can work on words. In this case, it trashes `a`.
|
||||||
|
|
||||||
|
| word za
|
||||||
|
| word zb
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
|
| inputs za, zb
|
||||||
|
| trashes a, z, c, n
|
||||||
|
| {
|
||||||
|
| cmp za, zb
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
|
||||||
|
| word za
|
||||||
|
| word zb
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
|
| inputs za, zb
|
||||||
|
| trashes a, z, n
|
||||||
|
| {
|
||||||
|
| cmp za, zb
|
||||||
|
| }
|
||||||
|
? ForbiddenWriteError: c
|
||||||
|
|
||||||
|
| word za
|
||||||
|
| word zb
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
|
| inputs za, zb
|
||||||
|
| trashes z, c, n
|
||||||
|
| {
|
||||||
|
| cmp za, zb
|
||||||
|
| }
|
||||||
|
? ForbiddenWriteError: a
|
||||||
|
|
||||||
|
| word za
|
||||||
|
| word zb
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
|
| inputs za
|
||||||
|
| trashes z, c, n
|
||||||
|
| {
|
||||||
|
| cmp za, zb
|
||||||
|
| }
|
||||||
|
? UnmeaningfulReadError: zb
|
||||||
|
|
||||||
### and ###
|
### and ###
|
||||||
|
|
||||||
Some rudimentary tests for `and`.
|
Some rudimentary tests for `and`.
|
||||||
|
@ -385,6 +385,26 @@ Some instructions on tables. (3/3)
|
|||||||
= $081B DEC $081F,X
|
= $081B DEC $081F,X
|
||||||
= $081E RTS
|
= $081E RTS
|
||||||
|
|
||||||
|
Compiling 16-bit `cmp`.
|
||||||
|
|
||||||
|
| word za @ 60001
|
||||||
|
| word zb : 3003
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
|
| inputs za, zb
|
||||||
|
| trashes a, z, c, n
|
||||||
|
| {
|
||||||
|
| cmp za, zb
|
||||||
|
| }
|
||||||
|
= $080D LDA $EA61
|
||||||
|
= $0810 CMP $081C
|
||||||
|
= $0813 BNE $081B
|
||||||
|
= $0815 LDA $EA62
|
||||||
|
= $0818 CMP $081D
|
||||||
|
= $081B RTS
|
||||||
|
= $081C .byte $BB
|
||||||
|
= $081D .byte $0B
|
||||||
|
|
||||||
Compiling `if`.
|
Compiling `if`.
|
||||||
|
|
||||||
| define main routine
|
| define main routine
|
||||||
|
Loading…
Reference in New Issue
Block a user