home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / icon / Source / Iconx / Asm / Rswitch
Encoding:
Text File  |  1990-09-18  |  7.0 KB  |  282 lines

  1. ;    Asm.Rswitch: Icon "context switch", for co-expression.
  2. ;
  3. ;    coswitch(old_cs, new_cs, first) saves the C stack and frame pointers
  4. ;    in the old_cs array, and then sets up new stack and frame pointers
  5. ;    from the new_cs array. If first == 0, then coswitch() actually
  6. ;    creates, using malloc(), the new stack.
  7.  
  8. ;    From checking the Icon source code, it appears that if first == -1
  9. ;    on entry, then this is the last time that coswitch() will be called
  10. ;    for this co-expression. It is therefore possible to free the
  11. ;    co-expression's stack at this point. Note that this use of first is
  12. ;    not actually documented, and so may be subject to change in new
  13. ;    versions of Icon. It is, however, the only "clean" way to free the
  14. ;    co-expression stack, so I have used it here.
  15.  
  16. ;    Register definitions
  17.  
  18. a1    RN    0
  19. a2    RN    1
  20. a3    RN    2
  21. a4    RN    3
  22. v1    RN    4
  23. v2    RN    5
  24. v3    RN    6
  25. v4    RN    7
  26. v5    RN    8
  27. v6    RN    9
  28. sl    RN    10
  29. fp    RN    11
  30. ip    RN    12
  31. sp    RN    13
  32. lr    RN    14
  33. pc    RN    15
  34.  
  35. f0    FN    0
  36. f1    FN    1
  37. f2    FN    2
  38. f3    FN    3
  39. f4    FN    4
  40. f5    FN    5
  41. f6    FN    6
  42. f7    FN    7
  43.  
  44. ;    Work registers (parameters)
  45.  
  46. old_cs    RN    0
  47. new_cs    RN    1
  48. first    RN    2
  49.  
  50. ;    Constants
  51.  
  52. MinStack    *    &800        ; 2K (should be an exact no of words)
  53. SL_Off        *    560
  54.  
  55. ;    External symbols
  56.  
  57.     IMPORT    |x$stack_overflow|
  58.     IMPORT    interp
  59.     IMPORT    syserr
  60.     IMPORT    malloc
  61.     IMPORT    free
  62.     IMPORT    stksize
  63.     EXPORT    coswitch
  64.  
  65. ;    coswitch() procedure
  66.  
  67.     AREA    |C$$code|, CODE, READONLY
  68.  
  69. start    =    "coswitch",0
  70.     ALIGN
  71.     &    &FF000000+{PC}-start
  72.  
  73. ;    int coswitch (word *old_cs, word *new_cs, int first)
  74.  
  75. coswitch
  76.     MOV    ip, sp
  77.     STMFD    sp!, {v1,fp,ip,lr,pc}
  78.     SUB    fp, ip, #4
  79.     CMPS    sp, sl
  80.     BLLT    |x$stack_overflow|
  81.  
  82. ;    Save vn, fp, sp, sl, and lr, and the floating point registers
  83. ;    (ie, the C state) in old_cs.
  84.  
  85.     STMIA    old_cs, {v1-v6,sl,fp,sp,lr}
  86.     STFE    f4, [old_cs, #40]
  87.     STFE    f5, [old_cs, #52]
  88.     STFE    f6, [old_cs, #64]
  89.     STFE    f7, [old_cs, #76]
  90.  
  91. ;    If first is zero, we must set up a new stack frame (at label First).
  92. ;    Otherwise we can simply reload the C state from new_cs.
  93.  
  94.     CMP    first, #0
  95.     BEQ    First
  96.  
  97. ;    If first is not -1, we can now return. Otherwise, we must free
  98. ;    the co-expression stack before we return, as we are now finished
  99. ;    with this co-expression.
  100.  
  101.     CMN    first, #1
  102.     BEQ    Free
  103.  
  104. ;    *------------------------------------------------------------*
  105. ;    *          Simple case: switch context and return            *
  106. ;    *------------------------------------------------------------*
  107.  
  108. ;    Restore vn, fp, sp, sl, and lr, and the floating point registers
  109.  
  110.     LDMIA    new_cs, {v1-v6,sl,fp,sp,lr}
  111.     LDFE    f4, [new_cs, #40]
  112.     LDFE    f5, [new_cs, #52]
  113.     LDFE    f6, [new_cs, #64]
  114.     LDFE    f7, [new_cs, #76]
  115.  
  116. ;    Return, restoring fp, sp, and pc (all other registers are as at the
  117. ;    point of call).
  118.  
  119.      LDMDB    fp, {fp,sp,pc}^
  120.  
  121. ;    *------------------------------------------------------------*
  122. ;    * First call: Create a stack, switch to it, and call interp  *
  123. ;    *------------------------------------------------------------*
  124.  
  125. First
  126.  
  127. ;    Icon has offered us a stack pointer in new_cs[0]. Unfortunately,
  128. ;    this is the top of a double-ended stack, with the bottom containing
  129. ;    the Icon run-time stack. So we cannot use it (as this would not
  130. ;    allow the C run-time stack checks to function). So we get our own
  131. ;    stack, using malloc(). We will assume that the value in the external
  132. ;    variable stksize is a suitable stack size, but we require a minimum
  133. ;    of 2K, which seems a reasonable size (the initial C stack is 16K)
  134.  
  135.     LDR    a1, StkSize
  136.     LDR    a1, [a1]
  137.     ADD    a1, a1, #3        ; Round to a word boundary
  138.     BIC    a1, a1, #3
  139.     CMP    a1, #MinStack        ; Make sure we have at least the min
  140.     MOVLT    a1, #MinStack
  141.     MOV    v1, a1            ; Save the size in v1 for later
  142.     BL    malloc
  143.  
  144. ;    Check if we ran out of memory
  145.  
  146.     CMP    a1, #0
  147.     BNE    MemOk
  148.  
  149. ;    If we did, do syserr("ran out of memory in coswitch")
  150.  
  151.     ADR    a1, nomem
  152.     LDMDB    fp, {v1,fp,sp,lr}
  153.     B    syserr
  154.  
  155. MemOk
  156.  
  157. ;    Copy the old stack chunk structure (5 words, plus 7 Acorn-reserved
  158. ;    words) into the new stack chunk. This seems the best way of making
  159. ;    sure that everything is as it should be.
  160.  
  161.     SUB    sl, sl, #SL_Off
  162.     MOV    ip, a1
  163.  
  164.     MOV    a3, #12            ; 5 basic words, plus 7 Acorn-reserved
  165. 1    LDR    a2, [sl], #4
  166.     STR    a2, [ip], #4
  167.     SUBS    a3, a3, #1
  168.     BNE    %B1
  169.  
  170. ;    Now overwrite the stuff specific to our stack
  171.  
  172.     MOV    ip, #0
  173.     STR    ip, [a1, #4]        ; Stack chunk: sc_next is NULL
  174.     STR    ip, [a1, #8]        ; Stack chunk: sc_prev is NULL
  175.     STR    v1, [a1, #12]        ; Stack chunk: sc_size is what we set
  176.     LDR    ip, FreeAddr
  177.     STR    ip, [a1, #16]        ; Stack chunk: sc_deallocate is free()
  178.  
  179. ;    Set up the new stack pointers
  180.  
  181.     MOV    sl, a1            ; Start at the base
  182.     ADD    sp, sl, v1        ; SP is at the high end
  183.     ADD    sl, sl, #SL_Off        ; SL points 560 bytes in
  184.     MOV    fp, #0            ; FP starts at 0
  185.  
  186. ;    interp(0,0)
  187.  
  188.     MOV    a2, #0
  189.     MOV    a1, #0
  190.     BL    interp
  191.  
  192. ;    syserr("interp() returned in coswitch")
  193.  
  194.     ADR    a1, errmsg
  195.     LDMDB    fp, {v1,fp,sp,lr}
  196.     B    syserr
  197.  
  198. ;    *------------------------------------------------------------*
  199. ;    *    Last call: Free the stack, switch context, and return   *
  200. ;    *------------------------------------------------------------*
  201.  
  202. Free
  203.  
  204. ;    OK, so we have to free the current C stack. We do this by getting
  205. ;    the address of the latest chunk from sl, and following the chain back,
  206. ;    freeing stuff as it goes.
  207.  
  208.     LDR    v1, [old_cs, #24]    ; Depends on sl < {fp,sp,lr} !!!
  209.     SUB    v1, v1, #SL_Off        ; Get to the chunk head
  210.  
  211. ;    We're about to trash our stack. Before we do, we should switch to
  212. ;    the new stack, so that the deallocation functions don't get in a
  213. ;    mess trying to deallocate their own stack..... We also save the value
  214. ;    of new_cs in a scratch register for use later.
  215.  
  216.     ADD    v2, new_cs, #24        ; Skip v1-v6
  217.     LDMIA    v2, {sl,fp,sp}        ; Get the new stack frame
  218.     MOV    v6, new_cs
  219.  
  220. ;    First, get the address of the next chunk to free and the address of
  221. ;    the deallocation function (sc_prev and sc_deallocate). Note that we
  222. ;    jump back to this point repeatedly, for each stack chunk. The only
  223. ;    entry condition is that v1 points to the stack chunk header.
  224.  
  225. 1    LDR    v2, [v1, #8]        ; v2 = v1->sc_prev
  226.     LDR    v3, [v1, #16]        ; v3 = v1->sc_deallocate
  227.  
  228. ;    Now, deallocate this chunk. That is, call the function whose address
  229. ;    is in v3 with a single parameter, v1.
  230.  
  231.     MOV    a1, v1
  232.     ADR    lr, %F2            ; Set up the return address
  233.     MOV    pc, v3
  234.  
  235. ;    Now, check whether there is another chunk to free. If v2 is NULL, we
  236. ;    have reached the end of the stack chain and we can stop.
  237.  
  238. 2    CMP    v2, #0
  239.     BEQ    %F3
  240.  
  241. ;    Otherwise, we should move the address of the next chunk into v1,
  242. ;    and start over.
  243.  
  244.     MOV    v1, v2
  245.     B    %B1
  246.  
  247. ;    Now, we can finally restore the whole machine state from new_cs.
  248. ;    Note, however, that new_cs is a volatile register (not guaranteed
  249. ;    across function calls). That's why we saved it in v6, and it's v6
  250. ;    we will use now.
  251.  
  252. 3    MOV    new_cs, v6
  253.     LDMIA    new_cs, {v1-v6,sl,fp,sp,lr}
  254.     LDFE    f4, [new_cs, #40]
  255.     LDFE    f5, [new_cs, #52]
  256.     LDFE    f6, [new_cs, #64]
  257.     LDFE    f7, [new_cs, #76]
  258.  
  259. ;    Return, restoring fp, sp, and pc (all other registers are as at the
  260. ;    point of call).
  261.  
  262.      LDMDB    fp, {fp,sp,pc}^
  263.  
  264. ;    *------------------------------------------------------------*
  265. ;    *              Extra junk (variables, strings)               *
  266. ;    *------------------------------------------------------------*
  267.  
  268. ;    Indirected addresses for C variables
  269.  
  270. StkSize        &    stksize
  271. FreeAddr    &    free
  272.  
  273. ;    Message texts for syserr()
  274.  
  275. errmsg        =    "interp() returned in coswitch",0
  276. nomem        =    "ran out of memory in coswitch",0
  277.         ALIGN
  278.  
  279. ;    That's all, folks...
  280.  
  281.     END
  282.