2ee739cc |
1 | BAS -- the Basic Assembler Supplement |
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
3 | |
4 | Once upon a time, this was meant to be a commercial Straylight |
5 | product. I never got around to writing the documentation. |
6 | |
7 | BAS is Yet Another tool for people who use the BASIC assembler. The |
8 | odd thing is that Straylight use Acorn's `objasm' assembler for all |
9 | our `real' work. The idea was to produce a procedure library for |
10 | generating linkable AOF code from BASIC, and the functionality grew |
11 | from there. Features are: |
12 | |
13 | * Generates AOF version 2 object code. |
14 | * Handles literal pools. (I'll come to them.) |
15 | * Translates (a simple subset of) objasm header files. |
16 | * A small collection of other tools. |
17 | |
18 | BAS is almost entirely written in assembler, with a BASIC procedure |
19 | library thrown in. You don't need to worry about that -- the code |
20 | is tacked on the end of the BASIC file, so it all comes as one |
21 | package. |
22 | |
23 | _____________________________________________________________________________ |
24 | |
25 | LICENCE |
26 | |
27 | BAS is Free Software; you can redistribute it and/or modify |
28 | it under the terms of the GNU General Public License as published by |
29 | the Free Software Foundation; either version 2, or (at your option) |
30 | any later version. |
31 | |
32 | BAS is distributed in the hope that it will be useful, but WITHOUT |
33 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
34 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
35 | License for more details. |
36 | |
37 | You should have received a copy of the GNU General Public License |
38 | along with BAS; if not, write to the Free Software Foundation, Inc., |
39 | 675 Mass Ave, Cambridge, MA 02139, USA. |
40 | |
41 | Of course, you can do what you like with the output of BAS. |
42 | |
43 | _____________________________________________________________________________ |
44 | |
45 | AOF CODE GENERATION |
46 | |
47 | I'll assume you understand how linkable objects work. We'll be |
48 | here all day if you don't. |
49 | |
50 | All code must be in an `area'. You start an area by saying |
51 | |
52 | FNarea("NAME", "ATTRIBUTES") |
53 | |
54 | The name can be anything you like; common names are `C$$Code' for |
55 | C code, and similar. Dollars are popular for some reason. |
56 | |
57 | The attributes define properties of areas, which in turn affect |
58 | positioning and access permissions. We've tried to use the same |
59 | names as Objasm here: |
60 | |
61 | CODE -- area contains code (implies `READONLY') |
62 | COMDEF -- definitons for a common area |
63 | COMMON -- overlay areas with this name |
64 | (implies `NOINIT') |
65 | NOINIT -- initialise this area with zeros |
66 | READONLY -- I don't need to write to this area |
67 | DEBUG -- contains debugging information |
68 | |
69 | By default, areas with the same name are concatenated. You get |
70 | given symbols `NAME$$Base' and `NAME$$Limit' to tell you the |
71 | boundaries of the complete area called `NAME', which is useful for |
72 | building tables. |
73 | |
74 | Attribute names can be separated by anything you like -- they're |
75 | parsed by the BASIC library using INSTR. Objasm uses commas, so |
76 | I tend to too. |
77 | |
78 | A program generating AOF code will usually look something like this: |
79 | |
80 | LIBRARY "libs:BAS" |
81 | PROCbas_init |
82 | |
83 | PROCbas_aofInit(SIZE) |
84 | FOR o%=4 TO 6 STEP 2 |
85 | [ opt o% |
86 | FNpass |
87 | |
88 | FNarea("Foo$$Code", "CODE, READONLY") |
89 | ... |
90 | |
91 | ] |
92 | NEXT |
93 | PROCbas_aofSave / PROCbas_aofSaveAs(FILENAME) |
94 | |
95 | Here, `SIZE' is the amount of space to reserve for the code, and |
96 | `FILENAME' is the name to save it as. The PROCbas_aofSave function |
97 | uses the value of <BAS$Output> as a default filename: this allows |
98 | you to declare an alias |
99 | |
100 | Set Alias$BasAsm Set BAS$Output %1|mBASIC -quit %0 |
101 | |
102 | which you can use in Makefiles. |
103 | |
104 | You're not limited to one assembly per source file -- you can create |
105 | any number of object files, although each one must start with a |
106 | call to PROCbas_aofInit and end with PROCbas_aofSave[As]. |
107 | |
108 | Note that you must begin each assembly by calling FNpass -- this |
109 | will set the P% and O% variables appropriately for the assembly, and |
110 | make sure that the BAS code understands where you are in the |
111 | assembly. |
112 | |
113 | You can export a synbol (so that other object files can see it) by |
114 | calling FNexport; for example: |
115 | |
116 | FNexport("hello") |
117 | .hello stmfd r13!,{r0,r14} |
118 | ldr r0,FNlitsz("Hello, world") |
119 | swi "OS_Write0" |
120 | ldmfd r13!,{r0,pc}^ |
121 | FNltorg |
122 | |
123 | Because AOF allows a wider range of identifiers than BASIC, you can |
124 | `alias' names as you export them; for example: |
125 | |
126 | FNexport("foo", "My$$FooishThing") |
127 | |
128 | takes the value represented in the BASIC variable `foo' and exports |
129 | it as `My$$FooishThing' in an object file. |
130 | |
131 | You import values in the same way: |
132 | |
133 | FNimport("malloc") |
134 | FNexport("xmalloc") |
135 | |
136 | .xmalloc |
137 | stmfd r13!,{r1-r3,r12,r14} |
138 | bl malloc |
139 | cmp r0,#0 |
140 | ldmnefd r13!,{r1-r3,r12,r14} |
141 | ldr r0,FNliterr(1,"Not enough memory") |
142 | swi "OS_GenerateError" |
143 | |
144 | FNltorg |
145 | |
146 | (I'll explain the FNlit... and FNltorg macros later. Bear with me.) |
147 | |
148 | You can also FNimportAs a symbol with a funny name: |
149 | |
150 | FNimportAs("Image$$RW$$Limit","program_end") |
151 | |
152 | fetches the limit of the read-write area of the image, telling you |
153 | where the program ends. This is quite handy. |
154 | |
155 | |
156 | How this all works is possibly interesting. It (ab)uses offset |
157 | assembly, directing output (O%) to a buffer BAS allocates for you, |
158 | and starting P% at &FC000000, which is an illegal instruction, and |
159 | hopefully unlikely to appear in `real' code. Once the assembly's |
160 | finished, BAS runs through and picks out references to things in |
161 | with addresses &FCxxxxxx and creates relocation directives for them |
162 | in the AOF file. Imported things get given addresses &FDxxxxxx. |
163 | Assuming these values don't appear in genuine code, we're OK. Just |
164 | in case you want to make arbitrary data appear in the object, BAS |
165 | has directives for disabling and reenabling relocation: |
166 | |
167 | FNnoreloc |
168 | ... |
169 | FNreloc |
170 | |
171 | won't munge anything between them. |
172 | |
173 | Finally, the call |
174 | |
175 | FNentry |
176 | |
177 | marks the entry point in an AIF program -- execution will start |
178 | here. That's all there is to it. |
179 | |
180 | _____________________________________________________________________________ |
181 | |
182 | LITERALS AND LITERAL POOLS |
183 | |
184 | Data like strings and absolute addresses are a pain in the BASIC |
185 | assembler -- you have to make up labels for them, and then reference |
186 | them. BAS tries to handle this sort of thing for you, which is |
187 | rather more pleasant of it. |
188 | |
189 | At any point in an assembly, BAS is building a `literal pool'. You |
190 | create a literal using one of the supplied directives, and BAS is |
191 | responsible for putting it in a literal pool; it gives you the |
192 | address at which the literal will be placed in the finished output. |
193 | The current literal pool will be written to the assembly when you |
194 | call FNltorg. A literal pool is also written at the very end of |
195 | the assembly. |
196 | |
197 | Essentially, then |
198 | |
199 | adr r0,FNlitsz("Hello, world") |
200 | ... |
201 | FNltorg |
202 | |
203 | is equivalent to |
204 | |
205 | adr r0,hello_string |
206 | ... |
207 | .hello_string |
208 | equs "Hello, world" + CHR$(0) |
209 | |
210 | The literal creation macros provided are: |
211 | |
212 | * FNlitw(WORD) stores a 32-bit value WORD at a word-aligned |
213 | address, e.g., |
214 | |
215 | FNimportAs("Image$$RW$$Limit", "prog_end") |
216 | ldr r0,FNlitw(prog_end) |
217 | |
218 | puts the address of the end of the program in R0. |
219 | |
220 | * FNlits(STRING) stores a string, unterminated, and non-word- |
221 | aligned. This isn't very useful. |
222 | |
223 | * FNlitmagic(STRING) stores an unterminated string at a word- |
224 | aligned address. This is for things like |
225 | |
226 | ldr r1,FNlitmagic("TASK") |
227 | |
228 | so you don't have to remember that this is &4B534154. I |
229 | remember it anyway. |
230 | |
231 | * FNlitsz(STRING) stores a null-terminated string at a non-word- |
232 | aligned address. This is useful for all kinds of messages. |
233 | |
234 | * FNliterr(NUM, STRING) stores a RISC OS error block at a word- |
235 | aligned address. |
236 | |
237 | If you need some kind of structure which isn't provided, you can |
238 | build it yourself. PROClitStart informs BAS that it's meant to |
239 | assemble a literal; FNliteral completes the literal, returning |
240 | the address where BAS will eventually put it. FNlitAlign does |
241 | the same job, only it word-aligns the literal. |
242 | |
243 | _____________________________________________________________________________ |
244 | |
245 | READING OBJASM HEADERS |
246 | |
247 | FNget(FILENAME) reads an Objasm-format header file. It's not perfect |
248 | but it tries hard. |
249 | |
250 | Objasm directives supported are: `^', `#'. `EQU', and `IMPORT'. |
251 | This is hopefully enough for most purposes. The `*' synonym for |
252 | `EQU' is also supported. |
253 | |
254 | BAS can't understand Objasm macros. Instead, it understands `active |
255 | comments'. The only one implemented is `LIB': |
256 | |
257 | ;+ LIB FILENAME |
258 | |
259 | which loads the BASIC procedure library FILENAME. A BAS macro |
260 | library `foo' must contain a function FNfoo_test, which is used by |
261 | BAS to see whether the library is loaded. |
262 | |
263 | _____________________________________________________________________________ |
264 | |
265 | OTHER USEFUL TOYS |
266 | |
267 | BAS defines a whole slew of constants: |
268 | |
269 | * r0-r15, R0-R15, a1-a4, v1-v6, sb, sl, fp, sp, SP, lr, LR, |
270 | lk, LK, pc and PC are all set to the appropriate register |
271 | numbers. |
272 | |
273 | * EQ, NE etc. are set to the appropriate condition code values. |
274 | |
275 | FNalign aligns the output position to a word boundary, padding with |
276 | zero bytes. FNreserve(SIZE) writes SIZE zero bytes to the output. |
277 | |
278 | FNbin(FILENAME) inserts the contents of the file FILENAME into the |
279 | output, protecting it from relocation. FNfSize(FILENAME) returns |
280 | the size of the file FILENAME. This can be handy for setting up |
281 | sprite areas. |
282 | |
283 | FNws_start clears a storage-area counter to zero. FNws_base(VALUE) |
284 | sets the counter to VALUE. FNws_align word-aligns the counter. |
285 | FNws(SIZE) returns the counter, and increases it by SIZE. FNws_word, |
286 | and FNws_byte are equivalent to FNws(4) and FNws(1) respectively. |
287 | These are useful for laying out workspace areas and data structures. |
288 | |
289 | FNadrl(REG, ADDR) assembles a long ADR; FNadrccl(COND, REG, ADDR) |
290 | assembles a conditional long ADR. FNaddl(REG, BASE, OFFSET) |
291 | assembles a long ADD; FNaddccl(COND, REG, BASE, OFFSET) does the |
292 | same conditionally. |
293 | |
294 | FNldrl(REG, ADDR) assembles a long LDR; FNldrccl(COND, REG, ADDR) |
295 | assembles a conditional long LDR. FNldrrl(REG, BASE, OFFSET) |
296 | assembles a long non-PC-relative LDR; |
297 | FNldrrccl(COND, REG, BASE, OFFSET) does that conditionally. |
298 | |
299 | _____________________________________________________________________________ |
300 | |
301 | BUILDING BAS FROM SOURCES |
302 | |
303 | This is quite involved. You need to have: |
304 | |
305 | * Acorn Desktop Assembler or later |
306 | |
307 | * An implementation of `sed' -- I recommend the port of GNU sed. |
308 | |
309 | * Straylight's basic library set (`header', `swis' and `stream') |
310 | available from the same place you got this from. |
311 | |
312 | * A copy of Cy Booker's `ccrunch' BASIC compressor. If you don't |
313 | have this, edit `remnames' and remove the `ccrunch' line -- the |
314 | BAS output file will be a little larger, but that's OK. |
315 | |
316 | Build the ARM code part by running the Makefile. Now run `Setup' |
317 | to mangle the nice BASIC library part, and to tack the code on |
318 | the end. That should be it. |
319 | |
320 | _____________________________________________________________________________ |
321 | |
322 | WHAT USE IS BAS? |
323 | |
324 | Dunno. Straylight were hoping to sell it for maybe fifteen quid a |
325 | go. We use it in-house for building simple AOF-outputting tools; |
326 | our message-file and template-file compilers are BAS-based, for |
327 | example. (These are available as part of the SDLS and Sapphire |
328 | packages, if they're out yet.) |
329 | |
330 | _____________________________________________________________________________ |