`byte table` -> `byte[SIZE]`, and you can `reserve` them.
Cat's Eye Technologies
11 years ago
89 | 89 | (Same should apply for `repeat` and `with` and, really, many other cases |
90 | 90 | which there just aren't enough test cases for yet.) |
91 | 91 | |
92 | ### "It's a Partial Solution" ### | |
93 | ||
94 | SixtyPical does not attempt to force your typed, abstractly interpreted | |
95 | program to be absolutely watertight. In assembly language on an 8-bit | |
96 | microprocessor, you will sometimes _need_ to do dangerous and tricky things, | |
97 | like self-modifying code and cycle-counting, in order to accomplish a | |
98 | sophisticated effect, like a raster interrupt trick. | |
99 | ||
100 | For that reason, `sixtypical` does not attempt to emit a fully-formed | |
101 | Ophis assembler source. Instead, it expects you to mix its output with | |
102 | some raw Ophis assembler to make a complete program. This "mixin" may contain | |
103 | as much unchecked assembler code as you like. An example is provided in the | |
104 | `lib` directory which adds a prelude that makes the resulting program | |
105 | runnable from Commodore BASIC 2.0 and stores uninitialized data at `$C000`. | |
106 | ||
107 | In addition, various checks are not attempted (such as tracking the usage | |
108 | of an indirect indexed table) and other checks may be subverted (for example | |
109 | by `locate`ing two variables with two different types of storage at the same | |
110 | address.) | |
111 | ||
112 | In summary, SixtyPical helps you write a very-nearly-assembly-level program | |
113 | which is a bit more "solid" than raw assembly, but it still expects you to | |
114 | know what you're doing down there. | |
115 | ||
92 | 116 | For More Information |
93 | 117 | -------------------- |
94 | 118 | |
122 | 146 | ---- |
123 | 147 | |
124 | 148 | * Initial values for reserved tables |
125 | * give length for tables, must be there for reserved, if no init val | |
126 | 149 | * Character tables ("strings" to everybody else) |
127 | 150 | * Addressing modes — indexed mode on more instructions |
128 | 151 | * `jsr (vector)` |
115 | 115 | | assign word memstr 641 |
116 | 116 | | reserve vector v |
117 | 117 | | assign vector cinv 788 |
118 | | reserve byte table frequencies | |
119 | | assign byte table screen 1024 | |
118 | | reserve byte[16] frequencies | |
119 | | assign byte[256] screen 1024 | |
120 | 120 | | routine main { |
121 | 121 | | nop |
122 | 122 | | } |
222 | 222 | |
223 | 223 | We can absolute-indexed a byte table. |
224 | 224 | |
225 | | assign byte table screen 1024 | |
225 | | assign byte[256] screen 1024 | |
226 | 226 | | routine main { |
227 | 227 | | sta screen, x |
228 | 228 | | } |
295 | 295 | * `jsr`'ing indirectly to a vector (which is done with a fun |
296 | 296 | generated trick (NYI)) |
297 | 297 | |
298 | * `byte table`: a series of `byte`s contiguous in memory starting from the | |
299 | address. This is the only kind of address that can be used in | |
300 | indexed addressing. | |
298 | * `byte [SIZE]`: a series of `SIZE` `byte`s contiguous in memory starting | |
299 | from the address. This is the only kind of address that can be used in | |
300 | indexed addressing. `SIZE` has a minimum of 1 and a maximum of 256. | |
301 | 301 | |
302 | 302 | ### Blocks ### |
303 | 303 |
188 | 188 | = |
189 | 189 | = .data |
190 | 190 | = .space position 2 |
191 | ||
192 | Reserving and assigning byte tables. | |
193 | ||
194 | | reserve byte[16] frequencies | |
195 | | assign byte[256] screen $0400 | |
196 | | routine main { | |
197 | | lda #0 | |
198 | | ldy #0 | |
199 | | sta frequencies, y | |
200 | | sta screen, y | |
201 | | } | |
202 | = main: | |
203 | = lda #0 | |
204 | = ldy #0 | |
205 | = sta frequencies, y | |
206 | = sta screen, y | |
207 | = rts | |
208 | = | |
209 | = .data | |
210 | = .space frequencies 16 | |
211 | = .alias screen 1024 | |
212 |
149 | 149 | |
150 | 150 | | reserve word vword |
151 | 151 | | reserve byte vbyte |
152 | | assign byte table table 1024 | |
152 | | assign byte[256] table 1024 | |
153 | 153 | | routine main { |
154 | 154 | | lda #4 |
155 | 155 | | ldx #0 |
262 | 262 | |
263 | 263 | | reserve word vword |
264 | 264 | | reserve byte vbyte |
265 | | assign byte table table 1024 | |
265 | | assign byte[256] table 1024 | |
266 | 266 | | routine main { |
267 | 267 | | asl .a |
268 | 268 | | asl vbyte |
29 | 29 | where |
30 | 30 | checkInstr j@(COPY _ (Indexed (NamedLocation sz g) reg)) = |
31 | 31 | case lookupDecl p g of |
32 | Just (Assign _ ByteTable _) -> j | |
33 | Just (Reserve _ ByteTable _) -> j | |
32 | Just (Assign _ (ByteTable _) _) -> j | |
33 | Just (Reserve _ (ByteTable _) _) -> j | |
34 | 34 | Just _ -> (COPY A A) |
35 | 35 | Nothing -> (COPY A A) |
36 | 36 | checkInstr other = other |
157 | 157 | in |
158 | 158 | case (typeRx == typeRy, typeRx, typeRy) of |
159 | 159 | (True, _, _) -> constructor rx ry |
160 | (_, Byte, ByteTable) -> constructor rx ry | |
161 | (_, ByteTable, Byte) -> constructor rx ry | |
160 | (_, Byte, (ByteTable _)) -> constructor rx ry | |
161 | (_, (ByteTable _), Byte) -> constructor rx ry | |
162 | 162 | _ -> error ("incompatible types '" ++ (show typeRx) ++ "' and '" ++ (show typeRy) ++ "'") |
163 | 163 | resolve (NamedLocation Nothing name) = |
164 | 164 | case lookupDecl p name of |
29 | 29 | | typ == Word = name ++ ": .word " ++ (show val) |
30 | 30 | | typ == Vector = name ++ ": .word " ++ (show val) |
31 | 31 | |
32 | emitDecl p (Reserve name (ByteTable size) Nothing) = | |
33 | ".space " ++ name ++ " " ++ (show size) | |
34 | ||
32 | 35 | emitDecl p (Reserve name typ Nothing) |
33 | 36 | | typ == Byte = ".space " ++ name ++ " 1" |
34 | 37 | | typ == Word = ".space " ++ name ++ " 2" |
78 | 81 | emitInstr p r (COPY X A) = "txa" |
79 | 82 | emitInstr p r (COPY Y A) = "tya" |
80 | 83 | |
81 | emitInstr p r (COPY A (Indexed (NamedLocation (Just ByteTable) label) X)) = "sta " ++ label ++ ", x" | |
82 | emitInstr p r (COPY A (Indexed (NamedLocation (Just ByteTable) label) Y)) = "sta " ++ label ++ ", y" | |
83 | ||
84 | emitInstr p r (COPY (Indexed (NamedLocation (Just ByteTable) label) X) A) = "lda " ++ label ++ ", x" | |
85 | emitInstr p r (COPY (Indexed (NamedLocation (Just ByteTable) label) Y) A) = "lda " ++ label ++ ", y" | |
84 | emitInstr p r (COPY A (Indexed (NamedLocation (Just (ByteTable _)) label) X)) = "sta " ++ label ++ ", x" | |
85 | emitInstr p r (COPY A (Indexed (NamedLocation (Just (ByteTable _)) label) Y)) = "sta " ++ label ++ ", y" | |
86 | ||
87 | emitInstr p r (COPY (Indexed (NamedLocation (Just (ByteTable _)) label) X) A) = "lda " ++ label ++ ", x" | |
88 | emitInstr p r (COPY (Indexed (NamedLocation (Just (ByteTable _)) label) Y) A) = "lda " ++ label ++ ", y" | |
86 | 89 | |
87 | 90 | emitInstr p r (COPY A (IndirectIndexed (NamedLocation st label) Y)) = "sta (" ++ label ++ "), y" |
88 | 91 | emitInstr p r (COPY (IndirectIndexed (NamedLocation st label) Y) A) = "lda (" ++ label ++ "), y" |
22 | 22 | data StorageType = Byte |
23 | 23 | | Word |
24 | 24 | | Vector |
25 | | ByteTable | |
25 | | ByteTable DataValue | |
26 | 26 | deriving (Show, Ord, Eq) |
27 | 27 | |
28 | 28 | data StorageLocation = A |
13 | 13 | Decl := "reserve" StorageType LocationName [":" Literal] |
14 | 14 | | "assign" StorageType LocationName Literal |
15 | 15 | | "external" RoutineName Address. |
16 | StorageType := "byte" | "word" | "byte table" | "vector". | |
16 | StorageType := "byte" ["[" Literal "]"] | "word" | "vector". | |
17 | 17 | Routine := "routine" RoutineName ["outputs" "(" {LocationName} ")"] Block. |
18 | 18 | Block := "{" {Command} "}". |
19 | 19 | Command := "if" Branch Block "else" Block |
90 | 90 | addr <- literal_address |
91 | 91 | return $ External name addr |
92 | 92 | |
93 | get_storage "byte" = Byte | |
94 | get_storage "word" = Word | |
95 | get_storage "vector" = Vector | |
96 | get_storage "byte table" = ByteTable | |
93 | storage :: String -> StorageType -> Parser StorageType | |
94 | storage s t = do | |
95 | string s | |
96 | nspaces | |
97 | return t | |
98 | ||
99 | byte_table :: Parser StorageType | |
100 | byte_table = do | |
101 | string "byte" | |
102 | nspaces | |
103 | string "[" | |
104 | nspaces | |
105 | size <- literal_data_value | |
106 | string "]" | |
107 | nspaces | |
108 | return $ ByteTable size | |
97 | 109 | |
98 | 110 | storage_type :: Parser StorageType |
99 | storage_type = do | |
100 | s <- (try $ string "byte table") <|> (string "byte") <|> | |
101 | (string "word") <|> (string "vector") | |
102 | nspaces | |
103 | return $ get_storage s | |
111 | storage_type = (try $ byte_table) <|> (storage "byte" Byte) <|> | |
112 | (storage "word" Word) <|> (storage "vector" Vector) | |
104 | 113 | |
105 | 114 | routine :: Parser Routine |
106 | 115 | routine = do |