home *** CD-ROM | disk | FTP | other *** search
- ; cortn.s
- ;
- ; Low level functionality for coroutine package. Written and tested under
- ; Acorn ANSI-C release 3.1B
- ;
- ; 30-09-90 AA Started
- ; 01-10-90 AA Changed to __ form of identifiers to hide these low level
- ; functions. Changed launch_co() to pass its third argument
- ; to the coroutine.
- ;
-
- GET s.Regs
- GET s.General
-
- GBLL db
- db SETL {FALSE}
-
- ; typedef struct
- ; { int sl, fp, sp;
- ; } context;
- ;
- ; typedef void (*coproc)(void *handle);
-
- ; Entry and exit sequence for __launch_co() and __switch_co() must be
- ; identical since entry through one may result in exit via the other. The
- ; entry and exit sequences are therefore standardised here.
-
- MACRO
- $label ENTER
- $label MOV ip, sp
- STMFD sp!, {a1, a2, a3, v1, v2, v3, v4, v5, v6, fp, ip, lr, pc}
- STFE f7, [sp, #-12]!
- STFE f6, [sp, #-12]!
- STFE f5, [sp, #-12]!
- STFE f4, [sp, #-12]!
- SUB fp, ip, #4
- CMPS sp, sl
- BLLT |x$stack_overflow|
- MEND
-
- MACRO
- $label EXIT
- $label
- [ db
- MOV v1, a1
- ADRL a1, exitfmt
- MOV a2, sp
- BL tracker_printf
- MOV a1, v1
- ]
- LDFE f4, [fp, #-92]
- LDFE f5, [fp, #-80]
- LDFE f6, [fp, #-68]
- LDFE f7, [fp, #-56]
- LDMEA fp, {v1, v2, v3, v4, v5, v6, fp, sp, pc}^
-
- LTORG
-
- MEND
-
- ; Data structure at the base of a stack chunk
-
- ^ 0
- StackWord # 4
- NextChunk # 4
- PrevChunk # 4
- ChunkSize # 4
- FreeProc # 4
- LibWord1 # 4
- LibWord2 # 4
-
- ; struct context
-
- ^ 0
- sl_val # 4
- fp_val # 4
- sp_val # 4
-
-
- AREA |C$$code|, CODE, READONLY
-
- IMPORT |x$stack_overflow|
- IMPORT malloc
- IMPORT free
- IMPORT tracker_printf
-
- SegBase * &0230
- SegSize * &0800
-
- LAUNCHFAIL * -1
-
- ; Note that launch_co() always returns a NULL in a1, because it only returns
- ; itself once the coroutine has completed. A return via switch_co() will
- ; only *APPEAR* to have come from launch_co().
-
- PROC "__launch_co", "|__launch_co|"
-
- ; context *__launch_co(coproc p, context *from, void *handle);
-
- |__launch_co| ENTER
-
- MOV v1, a1 ; Function
- MOV v2, a2 ; Caller
- MOV v3, a3 ; Handle for function
-
- ; Now create a new stack segment for the coroutine
-
- MOV a1, #SegSize
- MOV lr, pc
- LDR pc, mallocproc
- TEQ a1, #0
- MOVEQ a1, #LAUNCHFAIL
- BEQ launch_exit
-
- ; Save old caller's stack
-
- STR sl, [v2, #sl_val]
- STR fp, [v2, #fp_val]
- STR sp, [v2, #sp_val]
-
- ; Fill in header for stack chunk
-
- LDR a2, = &f60690ff
- STR a2, [a1, #StackWord]
- MOV a2, #0
- STR a2, [a1, #NextChunk]
- STR a2, [a1, #PrevChunk]
- MOV a2, #SegSize
- STR a2, [a1, #ChunkSize]
- LDR a2, freeproc
- STR a2, [a1, #FreeProc]
- LDR a2, [sl, #-SegBase + LibWord1]
- STR a2, [a1, #LibWord1]
- LDR a2, [sl, #-SegBase + LibWord2]
- STR a2, [a1, #LibWord2]
-
- ; Create new stack
-
- ADD sl, a1, #SegBase
- MOV fp, #0
- ADD sp, a1, #SegSize
-
- ; Enter coroutine
-
- MOV a1, v3
- MOV lr, pc
- MOV pc, v1
-
- ; Kill the stack from the old coroutine
-
- SUB a1, sl, #SegBase
- BL kill_co
-
- ; Comes back from coroutine after completion, so restore original stack
-
- LDR sl, [v2, #sl_val]
- LDR fp, [v2, #fp_val]
- LDR sp, [v2, #sp_val]
-
- ; Return with a1 == NULL
-
- MOV a1, #0
- launch_exit EXIT
-
- [ {TRUE}
- IMPORT cofree
- IMPORT comalloc
-
- freeproc & cofree
- mallocproc & comalloc
- |
-
- freeproc & free
- mallocproc & malloc
- ]
-
- PROC "__switch_co", "|__switch_co|"
-
- ; context *__switch_co(context *to, context *from);
- ;
- ; save current context in from, restore old context from to and do return.
- ; caller's context in from is returned as result.
-
- |__switch_co| ENTER
-
- TEQ a1, #0
- BEQ switch_exit
-
- ; Save our context
-
- STR sl, [a2, #sl_val]
- STR fp, [a2, #fp_val]
- STR sp, [a2, #sp_val]
-
- ; Get your context
-
- LDR sl, [a1, #sl_val]
- LDR fp, [a1, #fp_val]
- LDR sp, [a1, #sp_val]
-
- ; Return pointer to our context
-
- MOV a1, a2
-
- switch_exit EXIT
-
- PROC "__kill_co", "|__kill_co|"
-
- ; Progress down the coroutine's stack freeing each chunk in turn
-
- |__kill_co| MOV ip, sp
- STMFD sp!, {a1, v1, fp, ip, lr, pc}
- SUB fp, ip, #4
- CMPS sp, sl
- BLLT |x$stack_overflow|
-
- ; Now find first segment
-
- LDR v1, [a1, #sl_val] ; copy of sl
-
- [ db
- ADR a1, fmt1
- MOV a2, v1
- BL tracker_printf
- ]
-
- SUB a1, v1, #SegBase
- BL kill_co
-
- LDMEA fp, {v1, fp, sp, pc}^
-
- ; a1 is a stack chunk pointer
-
- kill_co MOV ip, sp
- STMFD sp!, {a1, v1, v2, v3, v4, fp, ip, lr, pc}
- SUB fp, ip, #4
- CMPS sp, sl
- BLLT |x$stack_overflow|
-
- LDR v3, [a1, #NextChunk]
-
- ; Loop through all segments in both directions
-
- kill_co1
- [ db
- MOV v4, a1
- MOV a2, a1
- ADR a1, fmt2
- BL tracker_printf
- MOV a1, v4
- ]
-
- LDR v1, [a1, #FreeProc]
- LDR v2, [a1, #PrevChunk]
-
- ; Call free function
-
- TEQ v1, #0
- MOVNE lr, pc
- MOVNE pc, v1
-
- MOVS a1, v2
- BNE kill_co1
-
- ; Now go the other way (v3 is the original nextchunk)
-
- MOVS a1, v3
- BEQ kill_coX
-
- ; Follow the chain the other way now
-
- kill_co2 LDR v1, [a1, #FreeProc]
- LDR v2, [a1, #NextChunk]
-
- TEQ v1, #0
- MOVNE lr, pc
- MOVNE pc, v1
-
- MOVS a1, v2
- BNE kill_co2
- kill_coX LDMEA fp, {v1, v2, v3, v4, fp, sp, pc}^
-
- [ db
- fmt1 = "Current SL is %08x\n", 0
- fmt2 = "Killing stack chunk at %08x\n", 0
- exitfmt = "SP is %08x\n", 0
- ]
-
- END
-