Low and high address operators, parsing and execution thereof.
Chris Pressey
6 years ago
44 | 44 | For 0.7: |
45 | 45 | |
46 | 46 | * `low` and `high` address operators (turn `word` type into `byte`.) |
47 | * `word table` type. | |
48 | 47 | |
49 | 48 | For 0.8: |
50 | 49 | |
50 | * `word table` type. | |
51 | * `vector table` type. | |
51 | 52 | * zero-page memory locations. |
52 | 53 | * indirect addressing. |
53 | 54 | |
54 | 55 | For 0.9 |
55 | 56 | |
56 | * save registers on stack or in memory (the preserves them = not trashed) | |
57 | * save registers on stack or in memory (this preserves them = not trashed) | |
57 | 58 | |
58 | 59 | At some point... |
59 | 60 |
394 | 394 | ------- |
395 | 395 | |
396 | 396 | Program ::= {Defn} {Routine}. |
397 | Defn ::= Type Ident<new> [Constraints] ["@" WordConst]. | |
397 | Defn ::= Type Ident<new> [Constraints] (":" Literal | "@" LitWord). | |
398 | 398 | Type ::= "byte" ["table"] | "vector" |
399 | 399 | Constrnt::= ["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs]. |
400 | Routine ::= "routine" Ident<new> Constraints (Block | "@" WordConst). | |
400 | Routine ::= "routine" Ident<new> Constraints (Block | "@" LitWord). | |
401 | 401 | LocExprs::= LocExpr {"," LocExpr}. |
402 | LocExpr ::= Register | Flag | LitByte | Ident. | |
402 | LocExpr ::= Register | Flag | Literal | ("<" | ">") Ident. | |
403 | 403 | Register::= "a" | "x" | "y". |
404 | 404 | Flag ::= "c" | "z" | "n" | "v". |
405 | Literal ::= LitByte | LitWord. | |
405 | 406 | LitByte ::= "0" ... "255". |
406 | 407 | LitWord ::= "0" ... "65535". |
407 | 408 | Block ::= "{" {Instr} "}". |
1 | 1 | |
2 | 2 | from sixtypical.ast import Program, Routine, Block, Instr |
3 | 3 | from sixtypical.model import ( |
4 | ConstantRef, LocationRef, | |
4 | ConstantRef, LocationRef, PartRef, | |
5 | 5 | REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C |
6 | 6 | ) |
7 | 7 | |
20 | 20 | return ref.value |
21 | 21 | elif isinstance(ref, LocationRef): |
22 | 22 | return self._store[ref.name] |
23 | elif isinstance(ref, PartRef): | |
24 | value = self.get(ref.ref) | |
25 | if ref.height == 0: | |
26 | return value & 255 | |
27 | elif ref.height == 1: | |
28 | return (value >> 8) & 255 | |
29 | else: | |
30 | raise NotImplementedError | |
23 | 31 | else: |
24 | 32 | raise ValueError(ref) |
25 | 33 | |
26 | 34 | def set(self, ref, value): |
35 | if isinstance(ref, PartRef): | |
36 | old = self.get(ref.ref) | |
37 | if ref.height == 0: | |
38 | value = (old & (255 << 8)) | value | |
39 | elif ref.height == 1: | |
40 | value = (value << 8) | (old & 255) | |
41 | else: | |
42 | raise NotImplementedError | |
43 | ref = ref.ref | |
27 | 44 | assert isinstance(ref, LocationRef) |
28 | 45 | self._store[ref.name] = value |
29 | 46 |
89 | 89 | return isinstance(self.type, RoutineType) |
90 | 90 | |
91 | 91 | |
92 | class PartRef(Ref): | |
93 | """For 'low byte of' location and 'high byte of' location modifiers. | |
94 | ||
95 | height=0 = low byte, height=1 = high byte. | |
96 | ||
97 | """ | |
98 | def __init__(self, ref, height): | |
99 | assert isinstance(ref, Ref) | |
100 | assert ref.type == TYPE_WORD | |
101 | self.ref = ref | |
102 | self.height = height | |
103 | self.type = TYPE_BYTE | |
104 | ||
105 | def __eq__(self, other): | |
106 | return isinstance(other, PartRef) and ( | |
107 | other.height == self.height and other.ref == self.ref | |
108 | ) | |
109 | ||
110 | def __hash__(self): | |
111 | return hash(self.ref) ^ hash(self.height) ^ hash(self.type) | |
112 | ||
113 | def __repr__(self): | |
114 | return '%s(%r, %r)' % (self.__class__.__name__, self.ref, self.height) | |
115 | ||
116 | def is_constant(self): | |
117 | return self.ref.is_constant() | |
118 | ||
119 | ||
92 | 120 | class ConstantRef(Ref): |
93 | 121 | def __init__(self, type, value): |
94 | 122 | self.type = type |
3 | 3 | from sixtypical.model import ( |
4 | 4 | TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE, |
5 | 5 | RoutineType, VectorType, ExecutableType, |
6 | LocationRef, ConstantRef | |
6 | LocationRef, ConstantRef, PartRef | |
7 | 7 | ) |
8 | 8 | from sixtypical.scanner import Scanner |
9 | 9 | |
141 | 141 | self.scanner.scan() |
142 | 142 | return loc |
143 | 143 | else: |
144 | op = None | |
145 | if self.scanner.consume('<'): | |
146 | op = '<' | |
147 | elif self.scanner.consume('>'): | |
148 | op = '>' | |
144 | 149 | loc = self.lookup(self.scanner.token) |
150 | if op == '<': | |
151 | loc = PartRef(loc, 0) | |
152 | elif op == '>': | |
153 | loc = PartRef(loc, 1) | |
145 | 154 | self.scanner.scan() |
146 | 155 | return loc |
147 | 156 |
28 | 28 | self.token = None |
29 | 29 | self.type = 'EOF' |
30 | 30 | return |
31 | if self.scan_pattern(r'\,|\@|\+|\:|\{|\}', 'operator'): | |
31 | if self.scan_pattern(r'\,|\@|\+|\:|\<|\>|\{|\}', 'operator'): | |
32 | 32 | return |
33 | 33 | if self.scan_pattern(r'\d+', 'integer literal'): |
34 | 34 | return |
416 | 416 | = y: 5 |
417 | 417 | = z: 0 |
418 | 418 | |
419 | Copy word to word. | |
420 | ||
421 | | word foo : 2000 | |
422 | | word bar | |
423 | | | |
424 | | routine main { | |
425 | | copy foo, bar | |
426 | | } | |
427 | = a: 0 | |
428 | = bar: 2000 | |
429 | = c: 0 | |
430 | = foo: 2000 | |
431 | = n: 0 | |
432 | = v: 0 | |
433 | = x: 0 | |
434 | = y: 0 | |
435 | = z: 0 | |
436 | ||
437 | Load and store low byte, high byte of word. | |
438 | ||
439 | | word foo : 511 | |
440 | | | |
441 | | routine main { | |
442 | | ld x, <foo | |
443 | | ld y, >foo | |
444 | | ld a, 2 | |
445 | | st a, <foo | |
446 | | ld a, 1 | |
447 | | st a, >foo | |
448 | | } | |
449 | = a: 1 | |
450 | = c: 0 | |
451 | = foo: 258 | |
452 | = n: 0 | |
453 | = v: 0 | |
454 | = x: 255 | |
455 | = y: 1 | |
456 | = z: 0 | |
457 | ||
419 | 458 | Indirect call. |
420 | 459 | |
421 | 460 | | vector foo outputs x trashes z, n |
142 | 142 | | } |
143 | 143 | = ok |
144 | 144 | |
145 | Cannot have both initial value and explicit address. | |
146 | ||
147 | | byte screen : 3 @ 1024 | |
148 | | | |
149 | | routine main { | |
150 | | ld a, lives | |
151 | | st a, lives | |
152 | | } | |
153 | ? SyntaxError | |
154 | ||
145 | 155 | User-defined locations of other types. |
146 | 156 | |
147 | 157 | | byte table screen @ 1024 |
153 | 163 | | } |
154 | 164 | = ok |
155 | 165 | |
156 | Initialized memory locations. | |
157 | ||
158 | | byte lives : 3 | |
159 | | | |
160 | | routine main { | |
161 | | ld a, lives | |
162 | | st a, lives | |
163 | | } | |
164 | = ok | |
165 | ||
166 | Cannot have both initial value and explicit address. | |
167 | ||
168 | | byte screen : 3 @ 1024 | |
169 | | | |
170 | | routine main { | |
171 | | ld a, lives | |
172 | | st a, lives | |
173 | | } | |
174 | ? SyntaxError | |
166 | Referencing low and high byte of a word. | |
167 | ||
168 | | word r1 | |
169 | | | |
170 | | routine main { | |
171 | | ld x, <r1 | |
172 | | ld y, >r1 | |
173 | | } | |
174 | = ok | |
175 | 175 | |
176 | 176 | Can't access an undeclared memory location. |
177 | 177 |