git @ Cat's Eye Technologies SixtyPical / bf3f183
Merge branch 'develop-0.18' of https://github.com/catseye/SixtyPical into goto-at-end-of-block Chris Pressey 6 years ago
9 changed file(s) with 248 addition(s) and 15 deletion(s). Raw diff Collapse all Expand all
66 * Syntactically, `goto` may only appear at the end of a block.
77 It need no longer be the final instruction in a routine,
88 as long as the type context is consistent at every exit.
9 * `cmp` instruction can now perform a 16-bit unsigned comparison
10 of `word` memory locations (at the cost of trashing `a`.)
911 * Fixed pathological memory use in the lexical scanner - should
1012 be much less inefficient now when parsing large source files.
1113
00 TODO for SixtyPical
11 ===================
2
3 ### 16-bit `cmp`
4
5 This is because we don't actually want `low` and `high` address operators
6 that turn `word` type into `byte`.
7
8 This is because this immediately makes things harder (that is, effectively
9 impossible) to analyze.
10
11 16-bit `cmp` also benefits from some special differences between `cmp`
12 and `sub` on 6502, so it would be nice to capture them.
132
143 ### Save values to other-than-the-stack
154
287287
288288 copy <src-memory-location>, <dest-memory-location>
289289
290 Reads from src and writes to dest. Differs from `st` in that is able to
291 copy more general types of data (for example, vectors,) and it trashes the
292 `z` and `n` flags and the `a` register.
290 Reads from src and writes to dest. Differs from `ld` and `st` in that
291 it is able to copy more general types of data (for example, vectors,)
292 and it trashes the `z` and `n` flags and the `a` register.
293293
294294 * It is illegal if dest is read-only.
295295 * It is illegal if dest does not occur in the WRITES of the current routine.
375375
376376 dest and src continue to be initialized afterwards.
377377
378 In addition, if dest is of `word` type, then src must also be of `word`
379 type, and in this case this instruction trashes the `a` register.
380
378381 ### dec ###
379382
380383 dec <dest-memory-location>
394397
395398 Subtracts the contents of src from dest (without considering carry) but
396399 does not store the result anywhere, only sets the resulting flags.
400 This means that `z` is set if src and dest are equal,
401 and `c` is set if dest is greater than or equal to src
402 (`c` is unset if dest is less than src.)
397403
398404 * It is illegal if src OR dest is uninitialized.
399405
400406 Affects n, z, and c flags, requiring that they be in the WRITES,
401407 and initializing them afterwards.
408
409 In addition, if dest is of `word` type, then src must also be of `word`
410 type, and in this case this instruction trashes the `a` register.
411
412 Note that `cmp` is not suitable for making a
413 signed comparison; this article, which mentions
414 techniques that a SixtyPical compiler could use to
415 implement `cmp`, also explains why that is:
416 [Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html).
402417
403418 ### and, or, xor ###
404419
0 // Should print ENGGL
1
2 byte b
3
4 define chrout routine
5 inputs a
6 trashes a
7 @ 65490
8
9 define main routine
10 outputs b
11 trashes a, x, y, z, n, c, v
12 {
13 ld a, 40
14 st a, b
15
16 cmp a, b
17 if z {
18 ld a, 69 // E
19 call chrout
20 } else {
21 ld a, 78 // N
22 call chrout
23 }
24
25 ld a, 41
26 st a, b
27 ld a, 40
28
29 cmp a, b
30 if z {
31 ld a, 69 // E
32 call chrout
33 } else {
34 ld a, 78 // N
35 call chrout
36 }
37
38 ld a, 20
39 st a, b
40
41 ld a, 21
42
43 cmp a, b // 21 >= 20
44 if c {
45 ld a, 71 // G
46 call chrout
47 } else {
48 ld a, 76 // L
49 call chrout
50 }
51
52 ld a, 20
53
54 cmp a, b // 20 >= 20
55 if c {
56 ld a, 71 // G
57 call chrout
58 } else {
59 ld a, 76 // L
60 call chrout
61 }
62
63 ld a, 19
64
65 cmp a, b // 19 < 20
66 if c {
67 ld a, 71 // G
68 call chrout
69 } else {
70 ld a, 76 // L
71 call chrout
72 }
73 }
0 // Should print ENGGL
1
2 word w1
3 word w2
4
5 define chrout routine
6 inputs a
7 trashes a
8 @ 65490
9
10 define main routine
11 outputs w1, w2
12 trashes a, x, y, z, n, c, v
13 {
14 copy 4000, w1
15 copy 4000, w2
16
17 cmp w1, w2
18 if z {
19 ld a, 69 // E
20 call chrout
21 } else {
22 ld a, 78 // N
23 call chrout
24 }
25
26 copy 4000, w1
27 copy 4001, w2
28
29 cmp w1, w2
30 if z {
31 ld a, 69 // E
32 call chrout
33 } else {
34 ld a, 78 // N
35 call chrout
36 }
37
38 copy 20002, w1
39 copy 20001, w2
40
41 cmp w1, w2 // 20002 >= 20001
42 if c {
43 ld a, 71 // G
44 call chrout
45 } else {
46 ld a, 76 // L
47 call chrout
48 }
49
50 copy 20001, w1
51
52 cmp w1, w2 // 20001 >= 20001
53 if c {
54 ld a, 71 // G
55 call chrout
56 } else {
57 ld a, 76 // L
58 call chrout
59 }
60
61 copy 20000, w1
62
63 cmp w1, w2 // 20000 < 20001
64 if c {
65 ld a, 71 // G
66 call chrout
67 } else {
68 ld a, 76 // L
69 call chrout
70 }
71 }
560560 context.assert_meaningful(src, dest)
561561 if isinstance(src, IndexedRef):
562562 context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE)
563 else:
563 elif src.type == TYPE_BYTE:
564564 self.assert_type(TYPE_BYTE, src, dest)
565 else:
566 self.assert_type(TYPE_WORD, src, dest)
567 context.set_touched(REG_A)
568 context.set_unmeaningful(REG_A)
565569 context.set_written(FLAG_Z, FLAG_N, FLAG_C)
566570 elif opcode == 'and':
567571 if isinstance(src, IndexedRef):
390390
391391 def compile_cmp(self, instr, src, dest):
392392 """`instr` is only for reporting purposes"""
393 if isinstance(src, LocationRef) and src.type == TYPE_WORD:
394 src_label = self.get_label(src.name)
395 dest_label = self.get_label(dest.name)
396 self.emitter.emit(LDA(Absolute(dest_label)))
397 self.emitter.emit(CMP(Absolute(src_label)))
398 end_label = Label('end_label')
399 self.emitter.emit(BNE(Relative(end_label)))
400 self.emitter.emit(LDA(Absolute(Offset(dest_label, 1))))
401 self.emitter.emit(CMP(Absolute(Offset(src_label, 1))))
402 self.emitter.resolve_label(end_label)
403 return
393404 cls = {
394405 'a': CMP,
395406 'x': CPX,
11161116 | cmp a, 4
11171117 | }
11181118 ? UnmeaningfulReadError: a
1119
1120 `cmp` can work on words. In this case, it trashes `a`.
1121
1122 | word za
1123 | word zb
1124 |
1125 | define main routine
1126 | inputs za, zb
1127 | trashes a, z, c, n
1128 | {
1129 | cmp za, zb
1130 | }
1131 = ok
1132
1133 | word za
1134 | word zb
1135 |
1136 | define main routine
1137 | inputs za, zb
1138 | trashes a, z, n
1139 | {
1140 | cmp za, zb
1141 | }
1142 ? ForbiddenWriteError: c
1143
1144 | word za
1145 | word zb
1146 |
1147 | define main routine
1148 | inputs za, zb
1149 | trashes z, c, n
1150 | {
1151 | cmp za, zb
1152 | }
1153 ? ForbiddenWriteError: a
1154
1155 | word za
1156 | word zb
1157 |
1158 | define main routine
1159 | inputs za
1160 | trashes z, c, n
1161 | {
1162 | cmp za, zb
1163 | }
1164 ? UnmeaningfulReadError: zb
11191165
11201166 ### and ###
11211167
384384 = $081B DEC $081F,X
385385 = $081E RTS
386386
387 Compiling 16-bit `cmp`.
388
389 | word za @ 60001
390 | word zb : 3003
391 |
392 | define main routine
393 | inputs za, zb
394 | trashes a, z, c, n
395 | {
396 | cmp za, zb
397 | }
398 = $080D LDA $EA61
399 = $0810 CMP $081C
400 = $0813 BNE $081B
401 = $0815 LDA $EA62
402 = $0818 CMP $081D
403 = $081B RTS
404 = $081C .byte $BB
405 = $081D .byte $0B
406
387407 Compiling `if`.
388408
389409 | define main routine