Initial revision
[ssr] / StraySrc / Libraries / BAS / src / README
CommitLineData
2ee739cc 1BAS -- 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
25LICENCE
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
45AOF 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
182LITERALS 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
245READING 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
265OTHER 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
301BUILDING 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
322WHAT 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_____________________________________________________________________________