home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / program / code / andylib / s / CoRtn next >
Encoding:
Text File  |  1995-05-21  |  8.5 KB  |  290 lines

  1. ; cortn.s
  2. ;
  3. ; Low level functionality for coroutine package.  Written and tested under
  4. ; Acorn ANSI-C release 3.1B
  5. ;
  6. ;   30-09-90 AA   Started
  7. ;   01-10-90 AA   Changed to __ form of identifiers to hide these low level
  8. ;                 functions.  Changed launch_co() to pass its third argument
  9. ;                 to the coroutine.
  10. ;
  11.  
  12.                 GET             s.Regs
  13.                 GET             s.General
  14.  
  15.                 GBLL            db
  16. db              SETL            {FALSE}
  17.  
  18. ; typedef struct
  19. ; {  int sl, fp, sp;
  20. ; } context;
  21. ;
  22. ; typedef void (*coproc)(void *handle);
  23.  
  24. ; Entry and exit sequence for __launch_co() and __switch_co() must be
  25. ; identical since entry through one may result in exit via the other.  The
  26. ; entry and exit sequences are therefore standardised here.
  27.  
  28.                 MACRO
  29. $label          ENTER
  30. $label          MOV     ip, sp
  31.                 STMFD   sp!, {a1, a2, a3, v1, v2, v3, v4, v5, v6, fp, ip, lr, pc}
  32.                 STFE    f7, [sp, #-12]!
  33.                 STFE    f6, [sp, #-12]!
  34.                 STFE    f5, [sp, #-12]!
  35.                 STFE    f4, [sp, #-12]!
  36.                 SUB     fp, ip, #4
  37.                 CMPS    sp, sl
  38.                 BLLT    |x$stack_overflow|
  39.                 MEND
  40.  
  41.                 MACRO
  42. $label          EXIT
  43. $label
  44.                 [       db
  45.                 MOV     v1, a1
  46.                 ADRL    a1, exitfmt
  47.                 MOV     a2, sp
  48.                 BL      tracker_printf
  49.                 MOV     a1, v1
  50.                 ]
  51.                 LDFE    f4, [fp, #-92]
  52.                 LDFE    f5, [fp, #-80]
  53.                 LDFE    f6, [fp, #-68]
  54.                 LDFE    f7, [fp, #-56]
  55.                 LDMEA   fp, {v1, v2, v3, v4, v5, v6, fp, sp, pc}^
  56.  
  57.                 LTORG
  58.  
  59.                 MEND
  60.  
  61. ; Data structure at the base of a stack chunk
  62.  
  63.                 ^               0
  64. StackWord       #               4
  65. NextChunk       #               4
  66. PrevChunk       #               4
  67. ChunkSize       #               4
  68. FreeProc        #               4
  69. LibWord1        #               4
  70. LibWord2        #               4
  71.  
  72. ; struct context
  73.  
  74.                 ^               0
  75. sl_val          #               4
  76. fp_val          #               4
  77. sp_val          #               4
  78.  
  79.  
  80.                 AREA |C$$code|, CODE, READONLY
  81.  
  82.                 IMPORT          |x$stack_overflow|
  83.                 IMPORT          malloc
  84.                 IMPORT          free
  85.                 IMPORT          tracker_printf
  86.  
  87. SegBase         *               &0230
  88. SegSize         *               &0800
  89.  
  90. LAUNCHFAIL      *               -1
  91.  
  92. ; Note that launch_co() always returns a NULL in a1, because it only returns
  93. ; itself once the coroutine has completed.  A return via switch_co() will
  94. ; only *APPEAR* to have come from launch_co().
  95.  
  96.                 PROC            "__launch_co", "|__launch_co|"
  97.  
  98. ; context *__launch_co(coproc p, context *from, void *handle);
  99.  
  100. |__launch_co|   ENTER
  101.  
  102.                 MOV             v1, a1    ; Function
  103.                 MOV             v2, a2    ; Caller
  104.                 MOV             v3, a3    ; Handle for function
  105.  
  106. ; Now create a new stack segment for the coroutine
  107.  
  108.                 MOV             a1, #SegSize
  109.                 MOV             lr, pc
  110.                 LDR             pc, mallocproc
  111.                 TEQ             a1, #0
  112.                 MOVEQ           a1, #LAUNCHFAIL
  113.                 BEQ             launch_exit
  114.  
  115. ; Save old caller's stack
  116.  
  117.                 STR             sl, [v2, #sl_val]
  118.                 STR             fp, [v2, #fp_val]
  119.                 STR             sp, [v2, #sp_val]
  120.  
  121. ; Fill in header for stack chunk
  122.  
  123.                 LDR             a2, = &f60690ff
  124.                 STR             a2, [a1, #StackWord]
  125.                 MOV             a2, #0
  126.                 STR             a2, [a1, #NextChunk]
  127.                 STR             a2, [a1, #PrevChunk]
  128.                 MOV             a2, #SegSize
  129.                 STR             a2, [a1, #ChunkSize]
  130.                 LDR             a2, freeproc
  131.                 STR             a2, [a1, #FreeProc]
  132.                 LDR             a2, [sl, #-SegBase + LibWord1]
  133.                 STR             a2, [a1, #LibWord1]
  134.                 LDR             a2, [sl, #-SegBase + LibWord2]
  135.                 STR             a2, [a1, #LibWord2]
  136.  
  137. ; Create new stack
  138.  
  139.                 ADD             sl, a1, #SegBase
  140.                 MOV             fp, #0
  141.                 ADD             sp, a1, #SegSize
  142.  
  143. ; Enter coroutine
  144.  
  145.                 MOV             a1, v3
  146.                 MOV             lr, pc
  147.                 MOV             pc, v1
  148.  
  149. ; Kill the stack from the old coroutine
  150.  
  151.                 SUB             a1, sl, #SegBase
  152.                 BL              kill_co
  153.  
  154. ; Comes back from coroutine after completion, so restore original stack
  155.  
  156.                 LDR             sl, [v2, #sl_val]
  157.                 LDR             fp, [v2, #fp_val]
  158.                 LDR             sp, [v2, #sp_val]
  159.  
  160. ; Return with a1 == NULL
  161.  
  162.                 MOV             a1, #0
  163. launch_exit     EXIT
  164.  
  165.                 [               {TRUE}
  166.                 IMPORT          cofree
  167.                 IMPORT          comalloc
  168.  
  169. freeproc        &               cofree
  170. mallocproc      &               comalloc
  171.                 |
  172.  
  173. freeproc        &               free
  174. mallocproc      &               malloc
  175.                 ]
  176.  
  177.                 PROC            "__switch_co", "|__switch_co|"
  178.  
  179. ; context *__switch_co(context *to, context *from);
  180. ;
  181. ; save current context in from, restore old context from to and do return.
  182. ; caller's context in from is returned as result.
  183.  
  184. |__switch_co|   ENTER
  185.  
  186.                 TEQ             a1, #0
  187.                 BEQ             switch_exit
  188.  
  189. ; Save our context
  190.  
  191.                 STR             sl, [a2, #sl_val]
  192.                 STR             fp, [a2, #fp_val]
  193.                 STR             sp, [a2, #sp_val]
  194.  
  195. ; Get your context
  196.  
  197.                 LDR             sl, [a1, #sl_val]
  198.                 LDR             fp, [a1, #fp_val]
  199.                 LDR             sp, [a1, #sp_val]
  200.  
  201. ; Return pointer to our context
  202.  
  203.                 MOV             a1, a2
  204.  
  205. switch_exit     EXIT
  206.  
  207.                 PROC            "__kill_co", "|__kill_co|"
  208.  
  209. ; Progress down the coroutine's stack freeing each chunk in turn
  210.  
  211. |__kill_co|     MOV             ip, sp
  212.                 STMFD           sp!, {a1, v1, fp, ip, lr, pc}
  213.                 SUB             fp, ip, #4
  214.                 CMPS            sp, sl
  215.                 BLLT            |x$stack_overflow|
  216.  
  217. ; Now find first segment
  218.  
  219.                 LDR             v1, [a1, #sl_val]          ; copy of sl
  220.  
  221.                 [               db
  222.                 ADR             a1, fmt1
  223.                 MOV             a2, v1
  224.                 BL              tracker_printf
  225.                 ]
  226.                                 
  227.                 SUB             a1, v1, #SegBase
  228.                 BL              kill_co
  229.                 
  230.                 LDMEA           fp, {v1, fp, sp, pc}^
  231.  
  232. ; a1 is a stack chunk pointer
  233.  
  234. kill_co         MOV             ip, sp
  235.                 STMFD           sp!, {a1, v1, v2, v3, v4, fp, ip, lr, pc}
  236.                 SUB             fp, ip, #4
  237.                 CMPS            sp, sl
  238.                 BLLT            |x$stack_overflow|
  239.  
  240.                 LDR             v3, [a1, #NextChunk]
  241.  
  242. ; Loop through all segments in both directions
  243.  
  244. kill_co1
  245.                 [               db
  246.                 MOV             v4, a1
  247.                 MOV             a2, a1
  248.                 ADR             a1, fmt2
  249.                 BL              tracker_printf
  250.                 MOV             a1, v4
  251.                 ]
  252.  
  253.                 LDR             v1, [a1, #FreeProc]
  254.                 LDR             v2, [a1, #PrevChunk]
  255.  
  256. ; Call free function
  257.  
  258.                 TEQ             v1, #0
  259.                 MOVNE           lr, pc
  260.                 MOVNE           pc, v1
  261.  
  262.                 MOVS            a1, v2
  263.                 BNE             kill_co1
  264.  
  265. ; Now go the other way (v3 is the original nextchunk)
  266.  
  267.                 MOVS            a1, v3
  268.                 BEQ             kill_coX
  269.  
  270. ; Follow the chain the other way now
  271.  
  272. kill_co2        LDR             v1, [a1, #FreeProc]
  273.                 LDR             v2, [a1, #NextChunk]
  274.  
  275.                 TEQ             v1, #0
  276.                 MOVNE           lr, pc
  277.                 MOVNE           pc, v1
  278.  
  279.                 MOVS            a1, v2
  280.                 BNE             kill_co2
  281. kill_coX        LDMEA           fp, {v1, v2, v3, v4, fp, sp, pc}^
  282.  
  283.                 [               db
  284. fmt1            =               "Current SL is %08x\n", 0
  285. fmt2            =               "Killing stack chunk at %08x\n", 0
  286. exitfmt         =               "SP is %08x\n", 0
  287.                 ]
  288.  
  289.                 END
  290.