summaryrefslogtreecommitdiffstats
path: root/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S
diff options
context:
space:
mode:
authorSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
committerSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
commit33613a85afc4b1481367fbe92a17ee59c240250b (patch)
tree670b842326116b376b505ec2263878912fca97e2 /Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S
downloadStudium-master.tar.gz
Studium-master.tar.bz2
add new repoHEADmaster
Diffstat (limited to 'Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S')
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S391
1 files changed, 391 insertions, 0 deletions
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S
new file mode 100644
index 0000000..4aeb6e4
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/OVERLAY/OVERMGRS.S
@@ -0,0 +1,391 @@
+; AUTHORS: L.Smith, J. Sutton
+;
+; DATE: Last edit 16-Mar-90 (ECN)
+;
+; VERSION: 0.07
+;
+; DESCRIPTION: Overlay Manager
+;
+; CHANGES: 28-Feb-90 LDS
+; Fixed a bug in check_for_invalidated_returns whereby a return
+; handler was allocated on return rather than just on call.
+;
+; 16-Mar-90 ECN
+; Use OS_GetEnv to read the overlay directory instead of Obey$Dir
+; which doesn't work if the image is not executed from an obey file.
+;
+; Tidied up the behaviour of "Disk not present errors". The previous
+; version just splatted a message all over the desktop. The new
+; version only prompt for disk insertion if executing outside the
+; desktop (inside the desktop the wimp will prompt the user).
+;
+; Tidied up the generation of errors and exit from application.
+; Previously either gave a trap or stiffed the machine.
+;
+;;; Copyright (C) Advanced RISC Machines Ltd., 1991
+
+ EXPORT |Image$$overlay_init|
+ EXPORT |Image$$load_seg|
+
+; pointers to start and end of workspace area supplied by the linker
+ IMPORT |Overlay$$Data$$Base|
+ IMPORT |Overlay$$Data$$Limit|
+ IMPORT |Image$$RO$$Limit|
+ IMPORT |Image$$RW$$Base|
+ IMPORT |Image$$ZI$$Base|
+ IMPORT MemCopy
+ IMPORT LoadOverlaySegment
+ IMPORT SevereErrorHandler, WEAK
+
+ZeroInitCodeOffset EQU 64
+
+; Why does the linker need to generate this zero init area, why can't the
+; Overlay Manager define it itself??? ECN.
+;
+; Layout of workspace allocated by the linker pointed to by Overlay$$Data
+; This area is automatically zero-initialised AFTER overlay_init is called
+; offsets are prefixed with Work_
+ ^ 0
+Work_HStack # 4 ; top of stack of allocated handlers
+Work_HFree # 4 ; head of free-list
+Work_RSave # 9*4 ; for R0-R8
+Work_LRSave # 4 ; saved lr
+Work_PCSave # 4 ; saved PC
+Work_PSRSave # 4 ; saved CPSR
+Work_ReturnHandlersArea EQU @ ; rest of this memory is treated as heap
+ ; space for the return handlers
+Work_MinSize EQU @ + 32 * RHandl_Size
+
+; Return handler. 1 is allocated per inter-segment procedure call
+; allocated and free lists of handlers are pointed to from HStack and HFree
+; offsets are prefixed with RHandl_
+ ^ 0
+RHandl_Branch # 4 ; BL load_seg_and_ret
+RHandl_RealLR # 4 ; space for the real return address
+RHandl_Segment # 4 ; -> PCIT section of segment to load
+RHandl_Link # 4 ; -> next in stack order
+RHandl_Size EQU @
+
+; set up by check_for_invalidated_returns.
+
+; PCITSection. 1 per segment stored in root segment, allocated by linker
+; offsets are prefixed with PCITSect_
+ ^ 0
+PCITSect_Vecsize # 4 ; .-4-EntryV ; size of entry vector
+PCITSect_Base # 4 ; used by load_segment; not initialised
+PCITSect_Limit # 4 ; used by load_segment; not initialised
+PCITSect_Name # 11 ; <11 bytes> ; 10-char segment name + NUL in 11 bytes
+PCITSect_Flags # 1 ; ...and a flag byte
+PCITSect_ClashSz # 4 ; PCITEnd-.-4 ; size of table following
+PCITSect_Clashes # 4 ; >table of pointers to clashing segments
+
+; Stack structure (all offsets are negative)
+; defined in procedure call standard
+; offsets are prefixed with Stack_
+ ^ 0
+Stack_SaveMask # -4
+Stack_LRReturn # -4
+Stack_SPReturn # -4
+Stack_FPReturn # -4
+
+; the code and private workspace area
+ AREA OverLayMgrArea, PIC, CODE , READONLY
+
+STRLR STR lr, [pc, #-8] ; a word that is to be matched in PCITs
+
+; Store 2 words which are the addresses of the start and end of the workspace
+WorkSpace DCD |Overlay$$Data$$Base|
+WorkSpaceEnd DCD |Overlay$$Data$$Limit|
+InitFlag DCD InitDoneFlag
+
+|Image$$overlay_init| ROUT
+; Initialise overlay manager.
+; In the AIF format this is is called from offset 8 in header. This routine has
+; to pass control to the zero initialisation code.
+; In Non AIF formats this routine has to be called explicitly e.g. from
+; a customised rtstand.s .
+;
+; In the AIF example the entire root segment is copied to the load address.
+;
+; In the non AIF example only the RW part of the root is copied.
+;
+ LDR ip,WorkSpace
+ IF :DEF:AIF_EXAMPLE
+ STR lr,[ip,#Work_LRSave]
+
+ ADD ip,ip,#Work_RSave
+ STMIA ip,{r0-r3}
+
+;
+; Look at the AIF header and add compute the total size of the AIF header
+;
+ SUB r1,lr,#0xC
+
+ LDR r0,[r1,#0x28]
+
+ LDR r2,[r1,#0x14]
+ LDR r3,[r1,#0x18]
+ ADD r2,r2,r3
+ LDR r3,[r1,#0x1C]
+ ADD r2,r2,r3
+
+;
+; A system specific Memory Copy call. r0 is the destination area.
+; r1 is the source area.
+; r2 is the block size in bytes.
+;
+ BL MemCopy
+ LDR ip,WorkSpace
+ LDR lr,[ip,#Work_LRSave]
+ ADD ip,ip,#Work_RSave
+ SUB lr,lr,#12
+ LDR lr,[lr,#0x28]
+ ADD lr,lr,#12
+ LDMIA ip,{r0-r3}
+;
+; Return to the Zero Initialisation Code in the AIF header.
+;
+ ADD pc,lr,#ZeroInitCodeOffset-12
+ ELSE
+ LDR ip,WorkSpace
+ ADD ip,ip,#Work_RSave
+ STMIA ip,{r0-r2,lr}
+
+ LDR r0,=|Image$$RW$$Base|
+ LDR r1,=|Image$$RO$$Limit|
+ LDR r2,=|Image$$ZI$$Base|
+ SUB r2,r2,r0
+ BL MemCopy
+
+ LDR ip,WorkSpace
+ ADD ip,ip,#Work_RSave
+ LDMIA ip,{r0-r2,PC}
+ ENDIF
+
+ DCD 0 ; Not needed for a real system but needed when using ARMSD
+ ; is used to simulate a ROMN based system.
+; entry point
+|Image$$load_seg| ROUT
+; called when segment has been called but is not loaded
+; presume ip is corruptible by this
+ LDR ip, WorkSpace
+ ADD ip, ip, #Work_RSave
+ STMIA ip, {r0-r8} ; save working registers
+ MRS r4, CPSR ; Save status register -it'll get stored in the
+ ; workspace later.
+; (save in my workspace because stack is untouchable during procedure call)
+ LDR r0, InitFlag
+ LDRB r1, [r0]
+ CMP r1, #0
+ BNE InitDone
+
+;Initialise Return Handlers on first call to this routine
+ MOV r1, #1
+ STRB r1, [r0] ; set InitDone flag
+ LDR r0, WorkSpace
+; r0 points to workspace
+; corrupts r0-r3,lr
+; create and initialise return handler linked list
+ MOV r2, #0
+ STR r2, [r0, #Work_HStack] ; initialise start of handler list with NULL
+ ADD r1, r0, #Work_ReturnHandlersArea ; Start of heap space
+ STR r1, [r0, #Work_HFree] ; Start of list of free handlers point to heap space
+ LDR r0, WorkSpaceEnd ; for test in loop to make sure..
+ SUBS r0, r0, #RHandl_Size ; ..I dont overrun in init
+01 ADD r3, r1, #RHandl_Size ; next handler
+; set up link to point to next handler (in fact consecutive locations)
+ STR r3, [r1, #RHandl_Link]
+ MOV r1, r3 ; next handler
+ CMP r1, r0 ; test for end of workspace
+ BLT %BT01
+ SUB r1, r1, #RHandl_Size ; previous handler
+ STR r2, [r1, #RHandl_Link] ; NULL-terminate list
+
+InitDone
+ LDR r3, WorkSpace
+ STR r4, [r3, #Work_PSRSave] ; CPSR read into R4 before the InitDone
+ ; test.
+ MOV r8,lr ;
+ LDR r0, [r8, #-8] ; saved r14... (is end of PCIT)
+ STR r0, [r3, #Work_LRSave] ; ...save it here ready for retry
+ LDR r0, STRLR ; look for this...
+ SUB r1, r8, #8 ; ... starting at last overwrite
+01 LDR r2, [r1, #-4]!
+ CMP r2, r0 ; must stop on guard word...
+ BNE %B01
+ ADD r1, r1, #4 ; gone one too far...
+ STR r1, [r3, #Work_PCSave] ; where to resume at
+
+load_segment
+
+; ip -> the register save area; r8 -> the PCIT section of the segment to load.
+; First re-initialise the PCIT section (if any) which clashes with this one...
+
+ ADD r1, r8, #PCITSect_Clashes
+ LDR r0, [r8, #PCITSect_ClashSz]
+01 SUBS r0, r0, #4
+ BLT Done_Reinit ; nothing left to do
+ LDR r7, [r1], #4 ; a clashing segment...
+ LDRB r2, [r7, #PCITSect_Flags] ; its flags (0 if unloaded)
+ CMPS r2, #0 ; is it loaded?
+ BEQ %B01 ; no, so look again
+
+; clashing segment is loaded (clearly, there can only be 1 such segment)
+; mark it as unloaded and reinitialise its PCIT
+; r7 -> PCITSection of clashing loaded segment
+
+ MOV r0, #0
+ STRB r0, [r7, #PCITSect_Flags] ; mark as unloaded
+ LDR r0, [r7, #PCITSect_Vecsize]
+ SUB r1, r7, #4 ; end of vector
+ LDR r2, STRLR ; init value to store in the vector...
+02 STR r2, [r1, #-4]! ;>
+ SUBS r0, r0, #4 ;> loop to initialise the PCIT segment
+ BGT %B02 ;>
+; Now we check the chain of call frames on the stack for return addresses
+
+; which have been invalidated by loading this segment and install handlers
+; for each invalidated return.
+; Note: r8 identifies the segment being loaded; r7 the segment being unloaded.
+
+ BL check_for_invalidated_returns
+Done_Reinit
+
+; All segment clashes have now been dealt with, as have the re-setting
+; of the segment-loaded flags and the intercepting of invalidated returns.
+; So, now load the required segment.
+
+Retry
+;
+; Call a routine to load the overlay segment.
+; First parameter is the length of the segment name.
+; The second parameter is the address of the segment name
+; The third parameter is the base address of the segement.
+; The routine returns the segment length in r0.
+;
+ MOV r0,#12
+ ADD r1, r8, #PCITSect_Name
+ LDR r2, [ r8, #PCITSect_Base]
+ BL LoadOverlaySegment
+
+ TEQ r0,#0
+ MOVEQ r0,#2
+ BEQ SevereErrorHandler
+
+ LDR ip,WorkSpace
+ ADD ip,ip,#Work_RSave
+;
+; Mark the segment as loaded.
+;
+ MOV r1,#1
+ STRB r1, [r8, #PCITSect_Flags]
+
+ LDR r2, [r8, #PCITSect_Base]
+ ADD r0, r2, r0 ; start + length = end of file
+
+; The segment's entry vector is at the end of the segment...
+; ...copy it to the PCIT section identified by r8.
+
+ LDR r1, [r8, #PCITSect_Vecsize]
+ SUB r3, r8, #8 ; end of entry vector...
+ MOV r4, #0 ; for data initialisation
+01 LDR r2, [r0, #-4]! ;>loop to copy
+ STR r4, [r0] ; (zero-init possible data section)
+ STR r2, [r3], #-4 ;>the segment's PCIT
+ SUBS r1, r1, #4 ;>section into the
+ BGT %B01 ;>global PCIT
+
+; Finally, continue, unabashed...
+
+ LDR r3, WorkSpace
+ LDR r3, [r3,#Work_PSRSave]
+ MSR CPSR,r3
+
+ LDMIA ip, {r0-r8, lr, pc}
+
+load_seg_and_ret
+; presume ip is corruptible by this
+ LDR ip, WorkSpace
+ ADD ip, ip, #Work_RSave
+ STMIA ip, {r0-r8} ; save working registers
+; (save in my workspace because stack is untouchable during procedure call)
+ LDR r3, WorkSpace
+ MRS r8, CPSR
+ STR r8, [r3, #Work_PSRSave]
+
+; lr points to the return handler
+ MOV r8, lr
+ ; load return handler fields RealLR, Segment, Link
+ LDMIA r8, {r0, r1, r2}
+ SUB r8, r8, #4 ; point to true start of return handler before BL
+ STR r0, [r3, #Work_LRSave]
+ STR r0, [r3, #Work_PCSave]
+; Now unchain the handler and return it to the free pool
+; HStack points to this handler
+ LDR r0, [r3, #Work_HStack]
+ CMPS r0, r8
+ MOVNE r0, #1
+ BNE SevereErrorHandler
+ STR r2, [r3, #Work_HStack] ; new top of handler stack
+ LDR r2, [r3, #Work_HFree]
+ STR r2, [r8, #RHandl_Link] ; Link -> old HFree
+ STR r8, [r3, #Work_HFree] ; new free list
+ MOV r8, r1 ; segment to load
+ B load_segment
+
+check_for_invalidated_returns
+; Note: r8 identifies the segment being loaded; r7 the segment being unloaded.
+; Note: check for returns invalidated by a call NOT for returns invalidated by
+; a return! In the 2nd case, the saved LR and saved PC are identical.
+ LDR r5, WorkSpace
+ ADD r6, r5, #Work_LRSave ; 1st location to check
+ LDMIA r6, {r0, r1} ; saved LR & PC
+ CMPS r0, r1
+ MOVEQ pc, lr ; identical => returning...
+ MOV r0, fp ; temporary FP...
+01 LDR r1, [r6] ; the saved return address...
+ LDR r2, [r5, #Work_HStack] ; top of handler stack
+ CMPS r1, r2 ; found the most recent handler, so
+ MOVEQ pc, lr ; abort the search
+ LDR r2, [r7, #PCITSect_Base]
+ CMPS r1, r2 ; see if >= base...
+ BLT %F02
+ LDR r2, [r7, #PCITSect_Limit]
+ CMPS r1, r2 ; ...and < limit ?
+ BLT FoundClash
+02 CMPS r0, #0 ; bottom of stack?
+ MOVEQ pc, lr ; yes => return
+ ADD r6, r0, #Stack_LRReturn
+ LDR r0, [r0, #Stack_FPReturn] ; previous FP
+ B %B01
+FoundClash
+ LDR r0, [r5, #Work_HFree] ; head of chain of free handlers
+ CMPS r0, #0
+ MOVEQ r0, #2
+ BEQ SevereErrorHandler
+; Transfer the next free handler to head of the handler stack.
+ LDR r1, [r0, #RHandl_Link] ; next free handler
+ STR r1, [r5, #Work_HFree]
+ LDR r1, [r5, #Work_HStack] ; the active handler stack
+ STR r1, [r0, #RHandl_Link]
+ STR r0, [r5, #Work_HStack] ; now with the latest handler linked in
+; Initialise the handler with a BL load_seg_and_ret, RealLR and Segment.
+ ADR r1, load_seg_and_ret
+ SUB r1, r1, r0 ; byte offset for BL in handler
+ SUB r1, r1, #8 ; correct for PC off by 8
+ MOV r1, r1, ASR #2 ; word offset
+ BIC r1, r1, #&FF000000
+ ORR r1, r1, #&EB000000 ; code for BL
+ STR r1, [r0, #RHandl_Branch]
+
+ LDR r1, [r6] ; LRReturn on stack
+ STR r1, [r0, #RHandl_RealLR] ; RealLR
+ STR r0, [r6] ; patch stack to return to handler
+
+ STR r7, [r0, #RHandl_Segment] ; segment to re-load on return
+ MOV pc, lr ; and return
+
+ AREA OverlayInit, DATA
+InitDoneFlag DCD 0
+
+ END