1
0
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:
Chris Pressey 2018-11-29 17:46:48 +00:00 committed by GitHub
commit f99cf47661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 248 additions and 15 deletions

View File

@ -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
View File

@ -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

View File

@ -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
View 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
View 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
}
}

View File

@ -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):

View File

@ -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,

View File

@ -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`.

View File

@ -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