4 ; Generate AOF files from BASIC
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's BASIC Assembler Supplement.
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)
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.
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.
27 ;----- Standard Header ------------------------------------------------------
34 ;----- External dependencies ------------------------------------------------
45 ;----- Main code ------------------------------------------------------------
47 AREA |BAS$$Code|,CODE,READONLY
51 ; On entry: R7 == address of workspace
52 ; R8-R12 set up by BASIC
56 ; CALL syntax: asmCode%
58 ; Use: Initialises workspace for generation of AOF code. Remembers
59 ; that code generation will start at asmCode%.
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
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
73 ; --- First, save the start address ---
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
81 ; --- Set up initial indices ---
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
88 ; --- Now initialise our memory structures ---
90 MOV R2,#0 ;Initial space used
91 MOV R3,#256 ;Initial space allocated
92 MOV R1,#256 ;Allocate this space
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
114 ; --- Build the header chunk ---
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
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
132 BL lit_init ;Initialise Literal Manager
134 LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
144 ; Use: Signals the start of a new assembly pass.
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
154 ; --- Bump the pass counter ---
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
163 ; --- Make sure the AREA addresses are OK ---
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
175 ; --- Work out end address ---
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
187 ; --- Now set up O% and P% correctly ---
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%
195 LDMFD R13!,{R0,R1,R12,PC}^ ;And return to caller
199 ; --- aof_firstPass ---
203 ; On exit: CS if on first pass, CC otherwise
205 ; Use: Informs the caller whether we're on the first or second pass.
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
221 ; On entry: R0 == address of anchor and size info
222 ; R1 == free space required
224 ; On exit: R0 == address of first free byte in area
226 ; Use: Ensures that there is the requested quantity of memory free
227 ; in the given block. If not, bas_noMem is called.
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
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
251 ; --- aof__addString ---
253 ; On entry: R0 == pointer to string to add
255 ; On exit: R0 == offset of string in string table
257 ; Use: Adds a string to the string table chunk and returns its
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
278 ; On entry: R0 == AREA attributes word
279 ; R7 == address of workspace
280 ; R8-R12 set up by BASIC
286 ; Use: Makes a new AREA start at the current location.
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
299 ; --- Insert new AREA block in header ---
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
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
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
318 ; --- Now try to fix up old AREA ---
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
326 ADD R14,R14,#1 ;Increment AREA count
327 STR R14,aof__area ;And save that back
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
335 ; --- If noReloc is at current address, remove it ---
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
346 90aof_area LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
356 ; Use: Sets the image entry point to be the current location.
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
368 ; --- Make sure we have an AREA ---
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
375 ; --- Set up the entry AREA number ---
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
384 ; --- Work out the entry offset ---
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
395 90aof_entry LDMFD R13!,{R0-R2,R12,PC}^ ;Return to caller
401 ; On entry: R0 == pointer to variable name
402 ; R1 == pointer to symbol name
403 ; R3 == attribute bits (not including bits 0,1)
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.
414 STMFD R13!,{R0-R6,R14} ;Save some registers
415 FSAVE R0 ;Save pointer to alias
417 ; --- See if it's already been IMPORTed ---
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
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
433 ; --- Found a match -- use this symbol then ---
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
439 ; --- Couldn't find the symbol -- create it then ---
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
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
453 ; --- Now set up the imports table ---
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
461 ; --- Work out the import entry offset ---
463 LDR R2,aof__imports ;Find the imports table base
464 SUB R2,R0,R2 ;Find the table offset
466 ; --- Write this into the variable ---
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
473 LDMFD R13!,{R0-R6,PC}^ ;Return to caller
477 ; --- aof_iImport ---
479 ; On entry: R0 == WEAK flag
480 ; R7 == address of workspace
481 ; R8-R12 set up by BASIC
485 ; CALL syntax: name$,alias$
487 ; Use: Imports a symbol name$, and makes the variable whose name
488 ; is in alias$ refer to it.
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
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
507 90aof_iImport LDMFD R13!,{R0,R1,R9,R10,R12,PC}^
511 ; --- aof__findArea ---
513 ; On entry: R0 == index of AREA
515 ; On exit: R0 == pointer to AREA description in header chunk
517 ; Use: Locates a given AREA's data.
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
530 ; --- aof__findSym ---
532 ; On entry: R0 == symbol value
534 ; On exit: CS if symbol recognised, and
535 ; VS if symbol is external reference, and
536 ; R0 == index of symbol in symbol table
538 ; else VC if symbol is internal reference, and
539 ; R0 == offset of symbol within AREA
541 ; else CC if symbol is absolute (i.e. not recognised) and
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
552 ; --- Make sure it can be anything other than absolute ---
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
558 ; --- See if it's an external symbol ---
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
565 ; --- See if it's an internal reference ---
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
571 ; --- Work out which AREA it's in ---
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
588 ; --- Find the appropriate symbol ---
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
601 ; On entry: R0 == STRONG flag
602 ; R7 == pointer to workspace
603 ; R8-R12 as set up by BASIC
607 ; CALL syntax: alias$,name$
609 ; Use: Exports the value held in the given alias as the symbol
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
622 ; --- Put the symbol name in the string table ---
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
630 ; --- Now find the symbol value ---
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
638 ; --- Create a block for the symbol ---
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
645 ; --- Now build the symbol ---
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
653 ; --- Create a program-relative symbol ---
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
664 ; --- Create an absolute symbol ---
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
672 90aof_export LDMFD R13!,{R0-R6,R9,R10,R12,PC}^
678 ; On entry: R7 == workspace address
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.
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
693 ; --- Only accept reloc/noReloc directives on first pass ---
695 BL aof_firstPass ;Is this the first pass?
696 LDMCCFD R13!,{R0-R2,R12,PC}^ ;No -- do nothing then
698 ; --- Check that we're alternating states ---
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
705 ; --- Check we need to do this ---
707 ; If the last entry is at the current address, we remove it
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
721 ; --- Add in the item ---
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
727 LDMFD R13!,{R0-R2,R12,PC}^ ;And return to caller
731 ; --- aof_noReloc ---
733 ; On entry: R7 == workspace address
737 ; Use: Marks the current address as being the start of a non-
738 ; relocation block. If a non-relocation block is current,
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
749 ; --- Only accept reloc/noReloc directives on first pass ---
751 BL aof_firstPass ;Is this the first pass?
752 LDMCCFD R13!,{R0-R2,R12,PC}^ ;No -- do nothing then
754 ; --- Check that we're alternating states ---
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
762 ; --- Check we need to do this ---
764 ; If the last entry is at the current address, we remove it
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
778 ; --- Add in the item ---
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
784 LDMFD R13!,{R0-R2,R12,PC}^ ;And return to caller
790 ; On entry: R7 == workspace address
791 ; R8-R12 set up by BASIC
797 ; Use: Saves the current AOF file. It also resets all the AOF
798 ; state, so that another AOF file can be built subsequently.
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
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
811 BL lit_end ;Turn off the literal system
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
819 MOV R0,#0 ;Zero NOINIT size count
820 STMFD R13!,{R0,R9,R10} ;Save argument pointers
822 ; --- Build relocation directives ---
824 ; Also fix up relocation counts for area defs
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
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
842 LDR R14,[R10,#4] ;Load AREA attributes
843 TST R14,#&1000 ;Is it NOINITed?
844 BEQ %10aof_save ;No -- deal with normally
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
852 ; --- Scan an AREA for relocations ---
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
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
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
870 10aof_save SUBS R6,R6,#4 ;Decrement AREA size
871 BCC %19aof_save ;If all done, move to next
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
877 LDR R0,[R8],#4 ;Load the next word out
878 ADD R5,R5,#4 ;Bump current offset
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
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
888 ; --- Build an internal additive relocation ---
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
900 ; --- Build a symbol additive relocation ---
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
913 ; --- Handle a B or BL instruction ---
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
925 ; --- Handle an internal PCRelative relocation ---
927 CMP R1,R11 ;Is it to this AREA?
928 BEQ %10aof_save ;Yes -- don't bother then
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
945 ; --- Handle a symbol PCRelative relocation ---
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
957 ; --- Reached end of the AREA ---
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
968 ; --- Work out chunk file header format ---
970 ; Pointless comment for separation, 'cos Tim said so.
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
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
981 LDR R0,aof__objName ;Load string `OBJ_'
982 MOV R2,#5*4*4 + 3*4 ;Where the chunks start
984 ; --- Set up the OBJ_IDFN entry ---
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
993 ; --- Set up the OBJ_HEAD entry ---
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
1000 ; --- Set up the OBJ_AREA entry ---
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
1009 STMIA R14!,{R0-R3} ;Save chunk information
1010 ADD R2,R2,R3 ;Work out next offset
1012 ; --- Set up the OBJ_SYMT entry ---
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
1019 ; --- Set up the OBJ_STRT entry ---
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
1028 ; --- Open the output file ---
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
1038 ; --- Write individual chunks to output file ---
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
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
1054 ; --- Set up the header and write it ---
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
1066 ; --- Write the AREA chunk (yuk) ---
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
1074 50aof_save SUBS R8,R8,#1 ;Decrement AREA counter
1075 BCC %60aof_save ;If all done, skip onwards
1077 LDR R14,[R6,#4] ;Load AREA attributes
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
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
1094 ADD R6,R6,#20 ;Move on to next AREA
1095 B %50aof_save ;And go round for the rest
1097 ; --- And now for the rest ---
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
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
1112 ; --- Close the file ---
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
1119 MOV R0,#9 ;Stamp the file
1120 MOV R1,R10 ;Point to the filename
1121 SWI OS_File ;Update the datestamp
1123 ; --- Free all of our flex blocks ---
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
1141 ADD R13,R13,#8 ;Skip past saved R9, R10
1142 LDMFD R13!,{R0-R12,PC}^ ;Return to caller finally
1144 ; --- Something went wrong during the write ---
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
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"
1163 aof__objIdfn DCB "Straylight Basic Assembler Supplement v. 1.00",0
1168 ;----- That's all, folks ----------------------------------------------------