Initial revision
[ssr] / StraySrc / Libraries / BAS / src / s / aofGen
1 ;
2 ; aofGen.s
3 ;
4 ; Generate AOF files from BASIC
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's BASIC Assembler Supplement.
12 ;
13 ; BAS is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; BAS is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with BAS. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard Header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET sh.bas
37 GET sh.basTalk
38 GET sh.flex
39 GET sh.insert
40 GET sh.lit
41 GET sh.messages
42 GET sh.string
43 GET sh.workspace
44
45 ;----- Main code ------------------------------------------------------------
46
47 AREA |BAS$$Code|,CODE,READONLY
48
49 ; --- aof_init ---
50 ;
51 ; On entry: R7 == address of workspace
52 ; R8-R12 set up by BASIC
53 ;
54 ; On exit: --
55 ;
56 ; CALL syntax: asmCode%
57 ;
58 ; Use: Initialises workspace for generation of AOF code. Remembers
59 ; that code generation will start at asmCode%.
60
61 EXPORT aof_init
62 aof_init ROUT
63
64 STMFD R13!,{R0-R6,R9,R10,R12,R14}
65 STR R12,[R7,#:INDEX:be__line] ;Store line value
66 MOV R12,R7 ;Get my workspace address
67
68 LDR R14,aof__objHead ;Load the header area address
69 CMP R14,#0 ;Is it created already?
70 ADRNEL R0,msg_errInitTwice ;Yes -- point to error
71 SWINE OS_GenerateError ;And inform the user
72
73 ; --- First, save the start address ---
74
75 SUBS R10,R10,#1 ;Decrement argument counter
76 BCC bas_badCall ;If none there, complain
77 LDMIA R9!,{R0,R1} ;Load the argument types
78 BL bTalk_load ;Load value into R2
79 STR R2,aof__base ;Save this base address
80
81 ; --- Set up initial indices ---
82
83 MOV R0,#0 ;Zero some locations
84 STR R0,aof__area ;No current area either
85 STR R0,aof__pass ;Not done any passes yet
86 STR R0,aof__relocCount ;Clear the flags word
87
88 ; --- Now initialise our memory structures ---
89
90 MOV R2,#0 ;Initial space used
91 MOV R3,#256 ;Initial space allocated
92 MOV R1,#256 ;Allocate this space
93
94 ADR R0,aof__objHead ;Point to header area block
95 BL flex_alloc ;Allocate the block
96 STMCCIB R0,{R2,R3} ;Save values after it
97 ADRCC R0,aof__objReloc ;Point to relocation block
98 BLCC flex_alloc ;Allocate the block
99 STMCCIB R0,{R2,R3} ;Save values after it
100 ADRCC R0,aof__objSymT ;Point to symbol table block
101 BLCC flex_alloc ;Allocate the block
102 STMCCIB R0,{R2,R3} ;Save values after it
103 ADRCC R0,aof__objStrT ;Point to string table block
104 BLCC flex_alloc ;Allocate the block
105 STMCCIB R0,{R2,R3} ;Save values after it
106 ADRCC R0,aof__imports ;Point to import table block
107 BLCC flex_alloc ;Allocate the block
108 STMCCIB R0,{R2,R3} ;Save values after it
109 ADRCC R0,aof__noReloc ;Point to non-reloc anchor
110 BLCC flex_alloc ;Allocate the block
111 STMCCIB R0,{R2,R3} ;Save values after it
112 BCS bas_noMem ;If no memory, complain
113
114 ; --- Build the header chunk ---
115
116 LDR R0,aof__objHead ;Find the header area
117 LDR R1,=&C5E2D080 ;The really odd magic number
118 MOV R2,#150 ;Version of AOF we like
119 MOV R3,#0 ;No areas yet
120 MOV R4,#0 ;No symbols either
121 MOV R5,#0 ;No entry area yet
122 MOV R6,#0 ;No entry offset, then
123 STMIA R0,{R1-R6} ;Build most of the header
124 MOV R14,#24 ;Now used 24 bytes
125 STR R14,aof__objHead+4 ;Save this in the info
126
127 MOV R14,#4 ;Length of string table
128 LDR R0,aof__objStrT ;Find the string table
129 STR R14,[R0,#0] ;Save that in the string tbl
130 STR R14,aof__objStrT+4 ;And as the size used
131
132 BL lit_init ;Initialise Literal Manager
133
134 LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
135
136 LTORG
137
138 ; --- aof_pass ---
139 ;
140 ; On entry: --
141 ;
142 ; On exit: --
143 ;
144 ; Use: Signals the start of a new assembly pass.
145
146 EXPORT aof_pass
147
148 aof_pass ROUT
149
150 STMFD R13!,{R0,R1,R12,R14} ;Save some registers
151 STR R12,[R7,#:INDEX:be__line] ;Store line value
152 MOV R12,R7 ;Find my workspace
153
154 ; --- Bump the pass counter ---
155
156 LDR R1,aof__pass ;Load the pass counter
157 ADD R1,R1,#1 ;Increment it
158 CMP R1,#2 ;Is this the second pass?
159 BLEQ lit_ltorg ;Yes -- insert lit pool
160 STR R1,aof__pass ;And store it back again
161 BNE %10aof_pass ;No -- skip ahead then
162
163 ; --- Make sure the AREA addresses are OK ---
164
165 LDR R0,aof__area ;Load the number of AREAs
166 CMP R0,#0 ;Are there any defined?
167 ADREQL R0,msg_errNoAreas ;No -- point to an error
168 SWIEQ OS_GenerateError ;And raise an error
169 LDR R14,aof__objHead ;Find the header chunk
170 LDR R14,[R14,#24+16] ;Load base of first AREA
171 CMP R14,#&FC000000 ;Is this an OK value
172 ADRNEL R0,msg_errNotInArea ;No -- point to error
173 SWINE OS_GenerateError ;And raise it
174
175 ; --- Work out end address ---
176
177 BL aof__findArea ;Look up its header info
178 LDR R14,be__percents ;Load % variable base address
179 LDR R1,[R14,#('P'-'A')*4] ;Load current location count
180 ADD R1,R1,#3 ;Word align this nicely
181 BIC R1,R1,#3 ;To keep link happy
182 STR R1,aof__limit ;Save as the code limit
183 LDR R14,[R0,#16] ;Load AREA base address
184 SUB R1,R1,R14 ;Work out the AREA's size
185 STR R1,[R0,#8] ;Store it in the block
186
187 ; --- Now set up O% and P% correctly ---
188
189 10aof_pass LDR R0,aof__base ;Load assembly base address
190 LDR R14,be__percents ;Load % variable base address
191 STR R0,[R14,#('O'-'A')*4] ;Save in correct variable
192 MOV R0,#&FC000000 ;Start assembly here (!)
193 STR R0,[R14,#('P'-'A')*4] ;Save that in P%
194
195 LDMFD R13!,{R0,R1,R12,PC}^ ;And return to caller
196
197 LTORG
198
199 ; --- aof_firstPass ---
200 ;
201 ; On entry: --
202 ;
203 ; On exit: CS if on first pass, CC otherwise
204 ;
205 ; Use: Informs the caller whether we're on the first or second pass.
206
207 EXPORT aof_firstPass
208 aof_firstPass ROUT
209
210 STMFD R13!,{R14} ;Save a register
211 LDR R14,aof__pass ;Which pass are we on?
212 CMP R14,#1 ;Is this the first one?
213 LDMFD R13!,{R14} ;Restore link register
214 ORRLES PC,R14,#C_flag ;Yes -- return CS then
215 BICGTS PC,R14,#C_flag ;No -- return CC then
216
217 LTORG
218
219 ; --- aof_ensure ---
220 ;
221 ; On entry: R0 == address of anchor and size info
222 ; R1 == free space required
223 ;
224 ; On exit: R0 == address of first free byte in area
225 ;
226 ; Use: Ensures that there is the requested quantity of memory free
227 ; in the given block. If not, bas_noMem is called.
228
229 EXPORT aof_ensure
230 aof_ensure ROUT
231
232 STMFD R13!,{R1,R2,R14} ;Save some registers
233 LDMIB R0,{R2,R14} ;Load used and size words
234 ADD R1,R1,R2 ;Find new total size
235 STR R1,[R0,#4] ;Save this back
236 ADD R1,R1,#255 ;Align up to next 256
237 BIC R1,R1,#255 ;For niceness's sake
238 CMP R1,R14 ;Do we already have enough?
239 BHI %50aof_ensure ;No -- allocate some more
240 10aof_ensure STR R1,[R0,#8] ;Save new total size
241 LDR R0,[R0,#0] ;Load address of block
242 ADD R0,R0,R2 ;Point to first free byte
243 LDMFD R13!,{R1,R2,PC}^ ;And return to caller
244
245 50aof_ensure BL flex_extend ;No -- then extend the block
246 BCS bas_noMem ;If we couldn't, we die
247 B %10aof_ensure ;Rejoin the main program
248
249 LTORG
250
251 ; --- aof__addString ---
252 ;
253 ; On entry: R0 == pointer to string to add
254 ;
255 ; On exit: R0 == offset of string in string table
256 ;
257 ; Use: Adds a string to the string table chunk and returns its
258 ; offset.
259
260 aof__addString ROUT
261
262 STMFD R13!,{R1,R2,R14} ;Save some registers
263 LDR R2,aof__objStrT+4 ;Load free offset
264 FSAVE R0 ;Save the string address
265 BL str_len ;Find the string length
266 ADD R1,R0,#1 ;Remember the terminator
267 ADR R0,aof__objStrT ;Point to string table anchor
268 BL aof_ensure ;Make sure there's enough
269 FLOAD R1 ;Load the source string
270 BL str_cpy ;Copy string into area
271 MOV R0,R2 ;Return offset in R0
272 LDMFD R13!,{R1,R2,PC}^ ;Return to caller
273
274 LTORG
275
276 ; --- aof_area ---
277 ;
278 ; On entry: R0 == AREA attributes word
279 ; R7 == address of workspace
280 ; R8-R12 set up by BASIC
281 ;
282 ; On exit: --
283 ;
284 ; CALL syntax: name$
285 ;
286 ; Use: Makes a new AREA start at the current location.
287
288 EXPORT aof_area
289 aof_area ROUT
290
291 STMFD R13!,{R0-R6,R9,R10,R12,R14}
292 BL insert_align ;Word align current position
293 BL lit_ltorg ;Insert a literal pool
294 STR R12,[R7,#:INDEX:be__line] ;Store line value
295 MOV R12,R7 ;Find workspace address
296 BL aof_firstPass ;Which pass am I on?
297 BCC %90aof_area ;If not the first, quit now
298
299 ; --- Insert new AREA block in header ---
300
301 MOV R3,R0 ;Keep the AREA attributes
302 BL str_buffer ;Find a string buffer
303 BL bas_argString ;Read the AREA's name
304 MOV R0,R1 ;Point to the string
305 BL aof__addString ;Put it in the string table
306 MOV R2,R0 ;Keep the string offset
307
308 ADR R0,aof__objHead ;Find the header chunk
309 MOV R1,#20 ;Want 20 bytes of data
310 BL aof_ensure ;Make sure it's there
311
312 MOV R4,#0 ;Don't know the size yet
313 MOV R5,#0 ;Don't know about relocations
314 LDR R14,be__percents ;Find the % variables
315 LDR R6,[R14,#('P'-'A')*4] ;Load current loc counter
316 STMIA R0,{R2-R6} ;Save this in the header
317
318 ; --- Now try to fix up old AREA ---
319
320 LDR R14,aof__area ;Which area are we on?
321 CMP R14,#0 ;Is this the dummy area?
322 LDRNE R5,[R0,#-4] ;No -- load old start pos
323 SUBNE R5,R6,R5 ;Get the AREA's size
324 STRNE R5,[R0,#-12] ;Save the AREA's size
325
326 ADD R14,R14,#1 ;Increment AREA count
327 STR R14,aof__area ;And save that back
328
329 LDR R14,aof__relocCount ;Load current flags
330 CMP R14,#0 ;Is relocation enabled?
331 BEQ %90aof_area ;Relocation enabled -- skip
332 MOV R14,#0 ;Clear the counter nicely
333 STR R14,aof__relocCount ;Save counter back again
334
335 ; --- If noReloc is at current address, remove it ---
336
337 LDR R2,be__percents ;Find the % variables
338 LDR R2,[R2,#('O'-'A')*4] ;Load current address
339 ADR R0,aof__noReloc ;Find noreloc table
340 LDMIA R0,{R0,R1} ;Load the size and base
341 SUB R1,R1,#4 ;Find the end value
342 LDR R14,[R0,R1] ;Load the value out
343 CMP R14,R2 ;Is this a match?
344 STREQ R1,aof__noReloc+4 ;Yes -- chop one off size
345
346 90aof_area LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
347
348 LTORG
349
350 ; --- aof_entry ---
351 ;
352 ; On entry: --
353 ;
354 ; On exit: --
355 ;
356 ; Use: Sets the image entry point to be the current location.
357
358 EXPORT aof_entry
359 aof_entry ROUT
360
361 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
362 STR R12,[R7,#:INDEX:be__line] ;Store line value
363 MOV R12,R7 ;Find my workspace address
364 BL insert_align ;Word align current pos
365 BL aof_firstPass ;Is this the first pass?
366 BCC %90aof_entry ;No -- then do nothing
367
368 ; --- Make sure we have an AREA ---
369
370 LDR R14,aof__area ;Find the current AREA
371 CMP R14,#0 ;Is this sensible?
372 ADREQL R0,msg_errNoArea ;No -- then point to error
373 SWIEQ OS_GenerateError ;And report an error
374
375 ; --- Set up the entry AREA number ---
376
377 LDR R0,aof__objHead ;Find the header chunk
378 LDR R1,[R0,#16] ;Load current entry area
379 CMP R1,#0 ;Is this defined yet?
380 ADRNEL R0,msg_errMultiEntry ;Yes -- point to error
381 SWINE OS_GenerateError ;And report an error
382 STR R14,[R0,#16] ;Save our AREA number
383
384 ; --- Work out the entry offset ---
385
386 ADD R14,R14,R14,LSL #2 ;Multiply index by 5
387 MOV R14,R14,LSL #2 ;Multiply index by 4 (x20)
388 ADD R14,R14,#20 ;Get offset of AREA start
389 LDR R1,[R0,R14] ;Load AREA start address
390 LDR R2,be__percents ;Find the % variables
391 LDR R2,[R2,#('P'-'A')*4] ;Get current location ptr
392 SUB R1,R1,R2 ;Get offset into AREA
393 STR R1,[R0,#20] ;Save the entry offset
394
395 90aof_entry LDMFD R13!,{R0-R2,R12,PC}^ ;Return to caller
396
397 LTORG
398
399 ; --- aof_import ---
400 ;
401 ; On entry: R0 == pointer to variable name
402 ; R1 == pointer to symbol name
403 ; R3 == attribute bits (not including bits 0,1)
404 ;
405 ; On exit: --
406 ;
407 ; Use: Imports a symbol, and sets the given variable to point to
408 ; it. If the symbol is already imported, another alias is
409 ; set up, but no actual symbol is created.
410
411 EXPORT aof_import
412 aof_import ROUT
413
414 STMFD R13!,{R0-R6,R14} ;Save some registers
415 FSAVE R0 ;Save pointer to alias
416
417 ; --- See if it's already been IMPORTed ---
418
419 ADR R2,aof__imports ;Find the symbol table
420 LDMIA R2,{R2,R5} ;Load address and size
421 ADD R5,R2,R5 ;Find limit address
422 LDR R4,aof__objStrT ;And find the string table
423 LDR R6,aof__objSymT ;And the symbol table
424
425 00aof_import CMP R2,R5 ;Reached the end yet?
426 BCS %10aof_import ;Yes -- carry on then
427 LDR R0,[R2],#4 ;Load the symbol index
428 LDR R0,[R6,R0] ;Load the name offset
429 ADD R0,R4,R0 ;Find the string address
430 BL str_cmp ;Does the string match?
431 BNE %00aof_import ;No -- ignore it then
432
433 ; --- Found a match -- use this symbol then ---
434
435 LDR R14,aof__imports ;Find the base of the table
436 SUB R2,R2,R14 ;Turn address into offset
437 B %20aof_import ;Rejoin the main routine
438
439 ; --- Couldn't find the symbol -- create it then ---
440
441 10aof_import MOV R0,R1 ;Point to the symbol name
442 BL aof__addString ;Put it in the string table
443 MOV R2,R0 ;Remember string's offset
444 ADR R0,aof__objSymT ;Point to symbol table
445 MOV R1,#16 ;Size of a symbol
446 BL aof_ensure ;Make that amount of space
447
448 ORR R3,R3,#2 ;Get the symbol attributes
449 MOV R4,#0 ;Symbol has no sensible value
450 MOV R5,#0 ;Symbol has no area name
451 STMIA R0,{R2-R5} ;Save symbol definition
452
453 ; --- Now set up the imports table ---
454
455 SUB R2,R0,R6 ;Get the symbol table offset
456 ADR R0,aof__imports ;Point to imports table
457 MOV R1,#4 ;Entries are 4 bytes each
458 BL aof_ensure ;Get the memory I want
459 STR R2,[R0],#4 ;Save the symbol index
460
461 ; --- Work out the import entry offset ---
462
463 LDR R2,aof__imports ;Find the imports table base
464 SUB R2,R0,R2 ;Find the table offset
465
466 ; --- Write this into the variable ---
467
468 20aof_import RSB R2,R2,#&FD000000 ;Work out the dummy value
469 FLOAD R0 ;Get variable name back
470 BL bTalk_create ;Create the variable
471 BL bTalk_store ;Save the value in it
472
473 LDMFD R13!,{R0-R6,PC}^ ;Return to caller
474
475 LTORG
476
477 ; --- aof_iImport ---
478 ;
479 ; On entry: R0 == WEAK flag
480 ; R7 == address of workspace
481 ; R8-R12 set up by BASIC
482 ;
483 ; On exit: --
484 ;
485 ; CALL syntax: name$,alias$
486 ;
487 ; Use: Imports a symbol name$, and makes the variable whose name
488 ; is in alias$ refer to it.
489
490 EXPORT aof_iImport
491 aof_iImport ROUT
492
493 STMFD R13!,{R0,R1,R9,R10,R12,R14}
494 STR R12,[R7,#:INDEX:be__line] ;Store line value
495 MOV R12,R7 ;Get my workspace address
496 BL aof_firstPass ;Is this the first pass?
497 BCC %90aof_iImport ;No -- ignore it then
498
499 MOV R3,R0,LSL #4 ;Set up WEAK bit
500 BL str_buffer ;Find a string buffer
501 BL bas_argString ;Read variable name string
502 MOV R0,R1 ;Pass this in R0
503 BL str_buffer ;Find another string buffer
504 BL bas_argString ;Read symbol name string
505 BL aof_import ;Import this symbol
506
507 90aof_iImport LDMFD R13!,{R0,R1,R9,R10,R12,PC}^
508
509 LTORG
510
511 ; --- aof__findArea ---
512 ;
513 ; On entry: R0 == index of AREA
514 ;
515 ; On exit: R0 == pointer to AREA description in header chunk
516 ;
517 ; Use: Locates a given AREA's data.
518
519 aof__findArea ROUT
520
521 STMFD R13!,{R14} ;Save a register
522 LDR R14,aof__objHead ;Find the header chunk
523 ADD R0,R0,R0,LSL #2 ;Multiply index by 5
524 ADD R0,R14,R0,LSL #2 ;And again by 4 (x20)
525 ADD R0,R0,#4 ;Add on a bit to find block
526 LDMFD R13!,{PC}^ ;Return to caller
527
528 LTORG
529
530 ; --- aof__findSym ---
531 ;
532 ; On entry: R0 == symbol value
533 ;
534 ; On exit: CS if symbol recognised, and
535 ; VS if symbol is external reference, and
536 ; R0 == index of symbol in symbol table
537 ; R1 corrupted
538 ; else VC if symbol is internal reference, and
539 ; R0 == offset of symbol within AREA
540 ; R1 == AREA index
541 ; else CC if symbol is absolute (i.e. not recognised) and
542 ; R0 preserved
543 ; R1 corrupted
544 ;
545 ; Use: Looks up a 32-bit value and tries to interpret it as a
546 ; symbol, returning information about it as required. This
547 ; routine attempts to be as quick as it can, but it can't
548 ; promise anything.
549
550 aof__findSym ROUT
551
552 ; --- Make sure it can be anything other than absolute ---
553
554 MOV R1,R0,LSR #24 ;Get the top byte
555 CMP R1,#&FC ;Is this our magic range?
556 BICNES PC,R14,#C_flag ;No -- clear C and exit
557
558 ; --- See if it's an external symbol ---
559
560 LDR R1,aof__objSymT+4 ;Get size of symbol table
561 RSB R1,R1,#&FD000000 ;Work out lowest import addr
562 CMP R0,R1 ;Is this an imported symbol?
563 BCS %50aof__findSym ;Yes -- find symbol index
564
565 ; --- See if it's an internal reference ---
566
567 LDR R1,aof__limit ;Load the limit address
568 CMP R0,R1 ;Is this within the code?
569 BICCSS PC,R14,#C_flag ;No -- then ignore it
570
571 ; --- Work out which AREA it's in ---
572
573 BIC R14,R14,#V_flag ;Clear V for internal ref
574 ORR R14,R14,#C_flag ;Set C for symbol match
575 STMFD R13!,{R2,R14} ;Save some registers
576 SUB R0,R0,#&FC000000 ;Get the symbol's offset
577 MOV R1,#1 ;Start at index 1
578 LDR R2,aof__objHead ;Find the header chunk
579 ADD R2,R2,#24 ;Find first AREA block
580 10aof__findSym LDR R14,[R2,#8] ;Load the AREA's size
581 CMP R0,R14 ;Is this within the AREA?
582 LDMCCFD R13!,{R2,PC}^ ;Yes -- then return it
583 SUB R0,R0,R14 ;Move into next AREA
584 ADD R1,R1,#1 ;Increment AREA index
585 ADD R2,R2,#20 ;Move to next AREA block
586 B %10aof__findSym ;And loop back round again
587
588 ; --- Find the appropriate symbol ---
589
590 50aof__findSym RSB R0,R0,#&FD000000 ;Find the import table index
591 LDR R1,aof__imports ;Find the import table
592 SUB R0,R0,#4 ;Compensate for strangeness
593 LDR R0,[R1,R0] ;Load the symbol index
594 MOV R0,R0,LSR #4 ;And divide by symbol size
595 ORRS PC,R14,#C_flag + V_flag ;Return, setting C and V
596
597 LTORG
598
599 ; --- aof_export ---
600 ;
601 ; On entry: R0 == STRONG flag
602 ; R7 == pointer to workspace
603 ; R8-R12 as set up by BASIC
604 ;
605 ; On exit: --
606 ;
607 ; CALL syntax: alias$,name$
608 ;
609 ; Use: Exports the value held in the given alias as the symbol
610 ; name$.
611
612 EXPORT aof_export
613 aof_export ROUT
614
615 STMFD R13!,{R0-R6,R9,R10,R12,R14}
616 STR R12,[R7,#:INDEX:be__line] ;Store line value
617 MOV R12,R7 ;Find my workspace address
618 BL aof_firstPass ;Is this the first pass?
619 BCS %90aof_export ;Yes -- may not be set up
620 MOV R3,R0,LSL #5 ;Keep the STRONG flag safe
621
622 ; --- Put the symbol name in the string table ---
623
624 BL str_buffer ;Get a string buffer
625 BL bas_argString ;Read the symbol name out
626 MOV R0,R1 ;Point to the symbol name
627 BL aof__addString ;Put it in the string table
628 MOV R4,R0 ;Remember this offset
629
630 ; --- Now find the symbol value ---
631
632 BL str_buffer ;Get a string buffer
633 BL bas_argString ;Read the string's value
634 MOV R0,R1 ;Point to the string
635 BL bTalk_lvblnk ;Find the lvalue
636 BL bTalk_load ;And load its value
637
638 ; --- Create a block for the symbol ---
639
640 ADR R0,aof__objSymT ;Point to the symbol table
641 MOV R1,#16 ;Make space for a symbol
642 BL aof_ensure ;Make sure there's space
643 MOV R6,R0 ;Remember this address
644
645 ; --- Now build the symbol ---
646
647 MOV R0,R2 ;Get the symbol value
648 BL aof__findSym ;Work out its meaning
649 BCC %20aof_export ;If it's absolute, skip on
650 ADRVSL R0,msg_errExpImported ;If imported, say it's silly
651 SWIVS OS_GenerateError ;And complain to the user
652
653 ; --- Create a program-relative symbol ---
654
655 MOV R2,R4 ;Get the symbol name offset
656 ORR R3,R3,#3 ;Get the symbol attributes
657 MOV R4,R0 ;Get the symbol offset
658 MOV R0,R1 ;Put AREA index in R0
659 BL aof__findArea ;Find the AREA data
660 LDR R5,[R0,#0] ;Get the AREA's name offset
661 STMIA R6,{R2-R5} ;Save the symbol info
662 B %90aof_export ;Return to caller
663
664 ; --- Create an absolute symbol ---
665
666 20aof_export MOV R2,R4 ;Get the symbol name offset
667 ORR R3,R3,#&07 ;Get the symbol attributes
668 MOV R4,R0 ;Get the symbol value
669 MOV R5,#0 ;Say that the AREA is 0
670 STMIA R6,{R2-R5} ;Save the symbol info
671
672 90aof_export LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
673
674 LTORG
675
676 ; --- aof_reloc ---
677 ;
678 ; On entry: R7 == workspace address
679 ;
680 ; On exit: --
681 ;
682 ; Use: Marks the current address as being the start of a relocation
683 ; block. If a relocation block is current, this is a no-op.
684
685 EXPORT aof_reloc
686 aof_reloc ROUT
687
688 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
689 STR R12,[R7,#:INDEX:be__line] ;Store line value
690 MOV R12,R7 ;Find my workspace pointer
691 BL insert_align ;Word align current pos
692
693 ; --- Only accept reloc/noReloc directives on first pass ---
694
695 BL aof_firstPass ;Is this the first pass?
696 LDMCCFD R13!,{R0-R2,R12,PC}^ ;No -- do nothing then
697
698 ; --- Check that we're alternating states ---
699
700 LDR R14,aof__relocCount ;Load current counter
701 SUBS R14,R14,#1 ;Decrement counter
702 STRGE R14,aof__relocCount ;If was >0, store it
703 LDMNEFD R13!,{R0-R2,R12,PC}^ ;If state still same, return
704
705 ; --- Check we need to do this ---
706 ;
707 ; If the last entry is at the current address, we remove it
708 ; and return.
709
710 LDR R2,be__percents ;Load the percents table
711 LDR R2,[R2,#('O'-'A')*4] ;Load current real address
712 ADR R0,aof__noReloc ;Point to noReloc table
713 LDMIA R0,{R1,R14} ;Load size and address
714 SUBS R14,R14,#4 ;Find previous entry
715 BLT %10aof_reloc ;If none defined, skip on
716 LDR R1,[R1,R14] ;Load the value out
717 CMP R1,R2 ;Do the entries match?
718 STREQ R14,aof__noReloc+4 ;Yes -- decrement used size
719 LDMEQFD R13!,{R0-R2,R12,PC}^ ;And return to caller
720
721 ; --- Add in the item ---
722
723 10aof_reloc MOV R1,#4 ;Entries are 4 bytes each
724 BL aof_ensure ;Extend the table
725 STR R2,[R0],#4 ;Save this in the table
726
727 LDMFD R13!,{R0-R2,R12,PC}^ ;And return to caller
728
729 LTORG
730
731 ; --- aof_noReloc ---
732 ;
733 ; On entry: R7 == workspace address
734 ;
735 ; On exit: --
736 ;
737 ; Use: Marks the current address as being the start of a non-
738 ; relocation block. If a non-relocation block is current,
739 ; this is a no-op.
740
741 EXPORT aof_noReloc
742 aof_noReloc ROUT
743
744 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
745 STR R12,[R7,#:INDEX:be__line] ;Store line value
746 MOV R12,R7 ;Find my workspace pointer
747 BL insert_align ;Word align current pos
748
749 ; --- Only accept reloc/noReloc directives on first pass ---
750
751 BL aof_firstPass ;Is this the first pass?
752 LDMCCFD R13!,{R0-R2,R12,PC}^ ;No -- do nothing then
753
754 ; --- Check that we're alternating states ---
755
756 LDR R14,aof__relocCount ;Load current counter value
757 ADD R14,R14,#1 ;Increment the value
758 STR R14,aof__relocCount ;Save value back again
759 CMP R14,#1 ;Was relocation enabled?
760 LDMNEFD R13!,{R0-R2,R12,PC}^ ;No -- return to caller
761
762 ; --- Check we need to do this ---
763 ;
764 ; If the last entry is at the current address, we remove it
765 ; and return.
766
767 LDR R2,be__percents ;Load the percents table
768 LDR R2,[R2,#('O'-'A')*4] ;Load current real address
769 ADR R0,aof__noReloc ;Point to noReloc table
770 LDMIA R0,{R1,R14} ;Load size and address
771 SUBS R14,R14,#4 ;Find previous entry
772 BLT %10aof_noReloc ;If none defined, skip on
773 LDR R1,[R1,R14] ;Load the value out
774 CMP R1,R2 ;Do the entries match?
775 STREQ R14,aof__noReloc+4 ;Yes -- decrement used size
776 LDMEQFD R13!,{R0-R2,R12,PC}^ ;And return to caller
777
778 ; --- Add in the item ---
779
780 10aof_noReloc MOV R1,#4 ;Entries are 4 bytes each
781 BL aof_ensure ;Extend the table
782 STR R2,[R0],#4 ;Save this in the table
783
784 LDMFD R13!,{R0-R2,R12,PC}^ ;And return to caller
785
786 LTORG
787
788 ; --- aof_save ---
789 ;
790 ; On entry: R7 == workspace address
791 ; R8-R12 set up by BASIC
792 ;
793 ; On exit: --
794 ;
795 ; CALL syntax: file$
796 ;
797 ; Use: Saves the current AOF file. It also resets all the AOF
798 ; state, so that another AOF file can be built subsequently.
799
800 EXPORT aof_save
801 aof_save ROUT
802
803 STMFD R13!,{R0-R12,R14} ;Save loads of registers
804 STR R12,[R7,#:INDEX:be__line] ;Store line value
805 MOV R12,R7 ;Find my workspace pointer
806
807 BL aof_firstPass ;Is this the first pass?
808 ADRCSL R0,msg_errNotDone ;Yes -- point to error
809 SWICS OS_GenerateError ;And make an error
810
811 BL lit_end ;Turn off the literal system
812
813 ADR R0,aof__noReloc ;Point to noReloc table
814 MOV R1,#4 ;Entries are 4 bytes each
815 BL aof_ensure ;Extend the table
816 MOV R14,#-1 ;Add a terminator
817 STR R14,[R0],#4 ;Save this in the table
818
819 MOV R0,#0 ;Zero NOINIT size count
820 STMFD R13!,{R0,R9,R10} ;Save argument pointers
821
822 ; --- Build relocation directives ---
823 ;
824 ; Also fix up relocation counts for area defs
825
826 MOV R11,#1 ;Current AREA number
827 LDR R10,aof__objHead ;Find the header chunk
828 ADD R10,R10,#24 ;Point to first AREA info
829 LDR R9,aof__area ;Load the number of AREAs
830 LDR R8,aof__base ;Find the code base address
831 LDR R4,aof__noReloc ;Find non-relocation block
832 LDR R3,[R4],#4 ;Load next value out
833
834 05aof_save SUBS R9,R9,#1 ;Decrement the AREA counter
835 BCC %20aof_save ;If all done, skip onwards
836 STMFD R13!,{R9} ;Save AREA counter
837 MOV R9,R3 ;Look after next reloc value
838 MOV R7,#0 ;No relocations created yet
839 LDR R6,[R10,#8] ;Load the AREA size
840 MOV R5,#-4 ;Start at offset 0
841
842 LDR R14,[R10,#4] ;Load AREA attributes
843 TST R14,#&1000 ;Is it NOINITed?
844 BEQ %10aof_save ;No -- deal with normally
845
846 LDR R14,[R13,#4] ;Load current NOINIT size
847 ADD R14,R14,R6 ;Add on size of this AREA
848 STR R14,[R13,#4] ;Save new size back again
849 ADD R8,R8,R6 ;Move pointer past AREA
850 B %19aof_save ;And skip out relocations
851
852 ; --- Scan an AREA for relocations ---
853
854 07aof_save ADD R6,R6,#4 ;Decremented down below
855 CMP R8,R9 ;Is this in reloc block?
856 LDRCS R9,[R4],#4 ;Yes -- load next value
857 BCS %10aof_save ;And relocate data nicely
858
859 ADD R14,R8,R6 ;Find end of AREA
860 CMP R14,R9 ;Any data to relocate?
861 ADDCC R8,R8,R6 ;No -- skip on to AREA end
862 BCC %19aof_save ;And move to next AREA
863
864 SUB R14,R9,R8 ;Find out how much to skip
865 ADD R8,R8,R14 ;Move on AREA address
866 ADD R5,R5,R14 ;And move on the offset
867 SUB R6,R6,R14 ;And decrement AREA size
868 LDR R9,[R4],#4 ;Load next reloc value
869
870 10aof_save SUBS R6,R6,#4 ;Decrement AREA size
871 BCC %19aof_save ;If all done, move to next
872
873 CMP R8,R9 ;Is this in non-reloc block?
874 LDRCS R9,[R4],#4 ;Yes -- load next value
875 BCS %07aof_save ;And skip on until reloc
876
877 LDR R0,[R8],#4 ;Load the next word out
878 ADD R5,R5,#4 ;Bump current offset
879
880 AND R14,R0,#&0E000000 ;Get opcode field
881 CMP R14,#&0A000000 ;Is it a branch or BL?
882 BEQ %15aof_save ;Yes -- handle this then
883
884 BL aof__findSym ;Try and interpret the value
885 BCC %10aof_save ;If no match, ignore it
886 BVS %13aof_save ;If symbol relocation, skip
887
888 ; --- Build an internal additive relocation ---
889
890 STR R0,[R8,#-4] ;Save offset back into code
891 SUB R3,R1,#1 ;And the AREA index
892 ADR R0,aof__objReloc ;Point to relocation chunk
893 MOV R1,#8 ;Need 8 bytes for relocation
894 BL aof_ensure ;Make sure there's enough
895 ORR R14,R3,#&82000000 ;Set up relocation info
896 STMIA R0,{R5,R14} ;Make the directive
897 ADD R7,R7,#1 ;Bump the relocation count
898 B %10aof_save ;Go back round for more
899
900 ; --- Build a symbol additive relocation ---
901
902 13aof_save MOV R14,#0 ;Make word reference symbol
903 STR R14,[R8,#-4] ;By zeroing the word
904 MOV R3,R0 ;Look after symbol index
905 ADR R0,aof__objReloc ;Point to relocation chunk
906 MOV R1,#8 ;Need 8 bytes for relocation
907 BL aof_ensure ;Make sure there's enough
908 ORR R14,R3,#&000A0000 ;Set up relocation info
909 STMIA R0,{R5,R14} ;Make the directive
910 ADD R7,R7,#1 ;Bump the relocation count
911 B %10aof_save ;Go back round for more
912
913 ; --- Handle a B or BL instruction ---
914
915 15aof_save AND R2,R0,#&FF000000 ;Get condition and type
916 BIC R0,R0,#&FF000000 ;Get branch offset value
917 ADD R0,R0,#2 ;Add on the required offset
918 LDR R3,[R10,#16] ;Load the AREA base address
919 ADD R3,R3,R5 ;Add on current offset
920 ADD R0,R3,R0,LSL #2 ;Work out branch destination
921 BL aof__findSym ;Look up the symbol type
922 BCC %10aof_save ;It's absolute -- ignore it
923 BVS %17aof_save ;It's symbol relative -- skip
924
925 ; --- Handle an internal PCRelative relocation ---
926
927 CMP R1,R11 ;Is it to this AREA?
928 BEQ %10aof_save ;Yes -- don't bother then
929
930 SUB R0,R0,R3 ;Work out the branch offset
931 MOV R0,R0,LSR #2 ;Shift it right by 2 nicely
932 SUB R0,R0,#2 ;And account for pipeline
933 BIC R0,R0,#&FF000000 ;Clear the top bits
934 ORR R0,R0,R2 ;And put in old opcode bits
935 STR R0,[R8,#-4] ;Write this instruction back
936 SUB R3,R1,#1 ;Look after AREA index
937 ADR R0,aof__objReloc ;Point to relocation chunk
938 MOV R1,#8 ;Need 8 bytes for relocation
939 BL aof_ensure ;Make sure there's enough
940 ORR R14,R3,#&86000000 ;Set up relocation flags
941 STMIA R0,{R5,R14} ;Save relocation directive
942 ADD R7,R7,#1 ;Bump the relocation count
943 B %10aof_save ;And try the next word
944
945 ; --- Handle a symbol PCRelative relocation ---
946
947 17aof_save STR R2,[R8,#-4] ;B/BL all bits zero
948 MOV R3,R0 ;Keep the symbol index
949 ADR R0,aof__objReloc ;Point to relocation chunk
950 MOV R1,#8 ;Need 8 bytes for relocation
951 BL aof_ensure ;Make sure there's enough
952 ORR R14,R3,#&000E0000 ;Set up relocation flags
953 STMIA R0,{R5,R14} ;Save relocation directive
954 ADD R7,R7,#1 ;Bump the relocation count
955 B %10aof_save ;And try the next word
956
957 ; --- Reached end of the AREA ---
958
959 19aof_save STR R7,[R10,#12] ;Save the relocation count
960 MOV R14,#0 ;A zero word
961 STR R14,[R10,#16] ;Write over reserved word
962 ADD R10,R10,#20 ;Move to next AREA block
963 ADD R11,R11,#1 ;Increment the AREA counter
964 MOV R3,R9 ;Look after noReloc address
965 LDMFD R13!,{R9} ;Load the AREA countdown
966 B %05aof_save ;And branch back for the rest
967
968 ; --- Work out chunk file header format ---
969 ;
970 ; Pointless comment for separation, 'cos Tim said so.
971
972 20aof_save LDMFD R13!,{R4} ;Load NOINIT size
973 SUB R13,R13,#5*4*4 + 3*4 ;Allocate space from stack
974 MOV R14,R13 ;Point to base of this area
975
976 LDR R0,=&C3CBC6C5 ;Strange magic guard word
977 MOV R1,#5 ;We have 5 chunks
978 MOV R2,#5 ;We will always have 5 chunks
979 STMIA R14!,{R0-R2} ;Save this away
980
981 LDR R0,aof__objName ;Load string `OBJ_'
982 MOV R2,#5*4*4 + 3*4 ;Where the chunks start
983
984 ; --- Set up the OBJ_IDFN entry ---
985
986 LDR R1,aof__idfnName ;Load string `IDFN'
987 MOV R3,# ? aof__objIdfn ;Find length of identifier
988 STMIA R14!,{R0-R3} ;Save chunk information
989 ADD R2,R2,R3 ;Work out next offset
990 ADD R2,R2,#3 ;Size may not be word aligned
991 BIC R2,R2,#3 ;It is now
992
993 ; --- Set up the OBJ_HEAD entry ---
994
995 LDR R1,aof__headName ;Load string `HEAD'
996 LDR R3,aof__objHead+4 ;Point to header anchor
997 STMIA R14!,{R0-R3} ;Save chunk information
998 ADD R2,R2,R3 ;Work out next offset
999
1000 ; --- Set up the OBJ_AREA entry ---
1001
1002 LDR R1,aof__areaName ;Load string `AREA'
1003 LDR R3,aof__objReloc+4 ;Load size of reloc block
1004 SUB R3,R3,R4 ;Subtract NOINIT size
1005 LDR R4,aof__limit ;Load end of code
1006 BIC R4,R4,#&FF000000 ;Mask off strange marker bits
1007 ADD R3,R3,R4 ;And work out chunk size
1008
1009 STMIA R14!,{R0-R3} ;Save chunk information
1010 ADD R2,R2,R3 ;Work out next offset
1011
1012 ; --- Set up the OBJ_SYMT entry ---
1013
1014 LDR R1,aof__symTName ;Load string `SYMT'
1015 LDR R3,aof__objSymT+4 ;Point to table anchor
1016 STMIA R14!,{R0-R3} ;Save chunk information
1017 ADD R2,R2,R3 ;Work out next offset
1018
1019 ; --- Set up the OBJ_STRT entry ---
1020
1021 LDR R1,aof__strTName ;Load string `STRT'
1022 LDR R3,aof__objStrT+4 ;Point to table anchor
1023 STMIA R14!,{R0-R3} ;Save chunk information
1024 ADD R2,R2,R3 ;Work out next offset
1025 ADD R2,R2,#3 ;Size may not be word aligned
1026 BIC R2,R2,#3 ;It is now
1027
1028 ; --- Open the output file ---
1029
1030 LDMIA R14,{R9,R10} ;Load BASIC's arguments
1031 BL str_buffer ;Find a string buffer
1032 BL bas_argString ;Copy the name string here
1033 MOV R10,R1 ;Look after name pointer
1034 MOV R0,#&8C ;Make lots of errors
1035 SWI OS_Find ;Open the file
1036 MOV R11,R0 ;Look after the file handle
1037
1038 ; --- Write individual chunks to output file ---
1039
1040 MOV R0,#2 ;Write bytes to file
1041 MOV R1,R11 ;Get the file handle
1042 MOV R2,R13 ;Point to header block
1043 MOV R3,#5*4*4 + 3*4 ;Size of the header block
1044 SWI XOS_GBPB ;Write that out to the file
1045 BVS %90aof_save ;If that failed, tidy up
1046
1047 ADR R2,aof__objIdfn ;Point to identification str
1048 MOV R3,# ? aof__objIdfn ;And read the length of it
1049 ADD R3,R3,#3 ;Word align this size
1050 BIC R3,R3,#3 ;To keep everything nice
1051 SWI XOS_GBPB ;Write that out to the file
1052 BVS %90aof_save ;If that failed, tidy up
1053
1054 ; --- Set up the header and write it ---
1055
1056 ADR R2,aof__objHead ;Point to header chunk data
1057 LDMIA R2,{R2,R3} ;Load address and size
1058 LDR R14,aof__area ;Get the number of AREAs
1059 STR R14,[R2,#8] ;Save this in the header
1060 LDR R14,aof__objSymT+4 ;Load symbol table size
1061 MOV R14,R14,LSR #4 ;Divide by symbol block size
1062 STR R14,[R2,#12] ;Save this in the header
1063 SWI XOS_GBPB ;Write that out to the file
1064 BVS %90aof_save ;If that failed, tidy up
1065
1066 ; --- Write the AREA chunk (yuk) ---
1067
1068 LDR R5,aof__base ;Find AREA data base address
1069 LDR R6,aof__objHead ;Find the header chunk
1070 ADD R6,R6,#24 ;Find the first AREA block
1071 LDR R7,aof__objReloc ;Find the relocation chunk
1072 LDR R8,aof__area ;Get the AREAs counter
1073
1074 50aof_save SUBS R8,R8,#1 ;Decrement AREA counter
1075 BCC %60aof_save ;If all done, skip onwards
1076
1077 LDR R14,[R6,#4] ;Load AREA attributes
1078
1079 MOV R2,R5 ;Point to AREA base
1080 LDR R3,[R6,#8] ;Load AREA size
1081 ADD R5,R5,R3 ;Move on the AREA pointer
1082 TST R14,#&1000 ;Should we include the data?
1083 SWIEQ XOS_GBPB ;Write bytes to file
1084 BVS %90aof_save ;If that failed, tidy up
1085
1086 MOV R2,R7 ;Point to relocation data
1087 LDR R3,[R6,#12] ;Load number of relocations
1088 MOV R3,R3,LSL #3 ;Multiply by directive size
1089 ADD R7,R7,R3 ;Move on relocation pointer
1090 TST R14,#&1000 ;Should we include the data?
1091 SWIEQ XOS_GBPB ;Write bytes to file
1092 BVS %90aof_save ;If that failed, tidy up
1093
1094 ADD R6,R6,#20 ;Move on to next AREA
1095 B %50aof_save ;And go round for the rest
1096
1097 ; --- And now for the rest ---
1098
1099 60aof_save ADR R2,aof__objSymT ;Point to symbol table data
1100 LDMIA R2,{R2,R3} ;Load address and size
1101 SWI XOS_GBPB ;Write that out to the file
1102 BVS %90aof_save ;If that failed, tidy up
1103
1104 ADR R2,aof__objStrT ;Point to string table data
1105 LDMIA R2,{R2,R3} ;Load address and size
1106 STR R3,[R2,#0] ;Fill in the size word
1107 ADD R3,R3,#3 ;Word align this size
1108 BIC R3,R3,#3 ;To keep everything nice
1109 SWI XOS_GBPB ;Write that out to the file
1110 BVS %90aof_save ;If that failed, tidy up
1111
1112 ; --- Close the file ---
1113
1114 MOV R0,#0 ;Close a file
1115 MOV R1,R11 ;Get the file handle
1116 SWI OS_Find ;Close the file
1117 ADD R13,R13,#5*4*4 + 3*4 ;Reclaim that stack space
1118
1119 MOV R0,#9 ;Stamp the file
1120 MOV R1,R10 ;Point to the filename
1121 SWI OS_File ;Update the datestamp
1122
1123 ; --- Free all of our flex blocks ---
1124
1125 ADR R0,aof__objHead ;Point to header anchor
1126 BL flex_free ;Free it
1127 ADR R0,aof__objSymT ;Point to symbol table anchor
1128 BL flex_free ;Free it
1129 ADR R0,aof__objStrT ;Point to string table anchor
1130 BL flex_free ;Free it
1131 ADR R0,aof__objReloc ;Point to reloc chunk anchor
1132 BL flex_free ;Free it
1133 ADR R0,aof__imports ;Point to import table anchor
1134 BL flex_free ;Free it
1135 ADR R0,aof__noReloc ;Point to non-reloc anchor
1136 BL flex_free ;Free it
1137 MOV R14,#0 ;Say we're now happy again
1138 STR R14,aof__objHead ;By zeroing header pointer
1139 BL flex_compact ;Ensure heap is compacted
1140
1141 ADD R13,R13,#8 ;Skip past saved R9, R10
1142 LDMFD R13!,{R0-R12,PC}^ ;Return to caller finally
1143
1144 ; --- Something went wrong during the write ---
1145
1146 90aof_save MOV R9,R0 ;Keep the error pointer
1147 MOV R0,#0 ;Close the file
1148 MOV R1,R11 ;Get the file handle
1149 SWI OS_Find ;Try hard to close the file
1150 MOV R0,#6 ;Delete named object
1151 MOV R1,R10 ;Point to the file name
1152 SWI OS_File ;Delete it happily
1153 MOV R0,R9 ;Point to the error again
1154 SWI OS_GenerateError ;And raise the error
1155
1156 aof__objName DCB "OBJ_"
1157 aof__idfnName DCB "IDFN"
1158 aof__headName DCB "HEAD"
1159 aof__areaName DCB "AREA"
1160 aof__symTName DCB "SYMT"
1161 aof__strTName DCB "STRT"
1162
1163 aof__objIdfn DCB "Straylight Basic Assembler Supplement v. 1.00",0
1164 ALIGN
1165
1166 LTORG
1167
1168 ;----- That's all, folks ----------------------------------------------------
1169
1170 END