mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +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
|
||||
----
|
||||
|
||||
* `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.
|
||||
|
||||
|
11
TODO.md
11
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
|
||||
|
@ -288,9 +288,9 @@ this mode is used.
|
||||
|
||||
copy <src-memory-location>, <dest-memory-location>
|
||||
|
||||
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.
|
||||
@ -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 <dest-memory-location>
|
||||
@ -395,12 +398,24 @@ 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.
|
||||
|
||||
Affects n, z, and c flags, requiring that they be in the WRITES,
|
||||
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 <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)
|
||||
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)
|
||||
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):
|
||||
|
@ -391,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(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 = {
|
||||
'a': CMP,
|
||||
'x': CPX,
|
||||
|
@ -1118,6 +1118,52 @@ Some rudimentary tests for `cmp`.
|
||||
| }
|
||||
? 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 ###
|
||||
|
||||
Some rudimentary tests for `and`.
|
||||
|
@ -385,6 +385,26 @@ Some instructions on tables. (3/3)
|
||||
= $081B DEC $081F,X
|
||||
= $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`.
|
||||
|
||||
| define main routine
|
||||
|
Loading…
Reference in New Issue
Block a user