ksr1.h

Go to the documentation of this file.
00001 /*
00002  * QuickThreads -- Threads-building toolkit.
00003  * Copyright (c) 1993 by David Keppel
00004  *
00005  * Permission to use, copy, modify and distribute this software and
00006  * its documentation for any purpose and without fee is hereby
00007  * granted, provided that the above copyright notice and this notice
00008  * appear in all copies.  This software is provided as a
00009  * proof-of-concept and for demonstration purposes; there is no
00010  * representation about the suitability of this software for any
00011  * purpose.
00012  */
00013 
00014 #ifndef QUICKTHREADS_KSR1_H
00015 #define QUICKTHREADS_KSR1_H
00016 
00017 /* 
00018    Stack layout:
00019 
00020    Registers are saved in strictly low to high order, FPU regs first 
00021    (only if qt_block is called), CEU regs second, IPU regs next, with no
00022    padding between the groups.
00023 
00024    Callee-save:  f16..f63; c15..c30; i12..i30.
00025    Args passed in i2..i5.
00026 
00027    Note: c31 is a private data pointer.  It is not changed on thread
00028    swaps with the assumption that it represents per-processor rather
00029    than per-thread state.
00030 
00031    Note: i31 is an instruction count register that is updated by the
00032    context switch routines.  Like c31, it is not changed on context
00033    switches.
00034 
00035    This is what we want on startup:
00036 
00037 
00038    +------      <-- BOS: Bottom of stack (grows down)
00039    | 80 (128 - 48) bytes of padding to a 128-byte boundary
00040    +---
00041    | only
00042    | userf
00043    | t
00044    | u
00045    | qt_start$TXT
00046    | (empty)        <-- qt.sp
00047    +------      <-- (BOS - 128)
00048 
00049    This is why we want this on startup:
00050    
00051    A thread begins running when the restore procedure switches thread stacks
00052    and pops a return address off of the top of the new stack (see below
00053    for the reason why we explicitly store qt_start$TXT).  The
00054    block procedure pushes two jump addresses on a thread's stack before
00055    it switches stacks.  The first is the return address for the block
00056    procedure, and the second is a restore address.  The return address
00057    is used to jump back to the thread that has been switched to;  the
00058    restore address is a jump within the block code to restore the registers.
00059    Normally, this is just a jump to the next address.  However, on thread
00060    startup, this is a jump to qt_start$TXT.  (The block procedure stores
00061    the restore address at an offset of 8 bytes from the top of the stack,
00062    which is also the offset at which qt_start$TXT is stored on the stacks
00063    of new threads.  Hence, when the block procedure switches to a new
00064    thread stack, it will initially jump to qt_start$TXT; thereafter,
00065    it jumps to the restore code.)
00066 
00067    qt_start$TXT, after it has read the initial data on the new thread's
00068    stack and placed it in registers, pops the initial stack frame
00069    and gives the thread the entire stack to use for execution.
00070 
00071    The KSR runtime system has an unusual treatment of pointers to
00072    functions.  From C, taking the `name' of a function yields a
00073    pointer to a _constant block_ and *not* the address of the
00074    function.  The zero'th entry in the constant block is a pointer to
00075    the function.
00076 
00077    We have to be careful: the restore procedure expects a return
00078    address on the top of the stack (pointed to by qt.sp).  This is not
00079    a problem when restoring a thread that has run before, since the
00080    block routine would have stored the return address on top of the
00081    stack.  However, when ``faking up'' a thread start (bootstrapping a
00082    thread stack frame), the top of the stack needs to contain a
00083    pointer to the code that will start the thread running.
00084 
00085    The pointer to the startup code is *not* `qt_start'.  It is the
00086    word *pointed to* by `qt_start'.  Thus, we dereference `qt_start',
00087    see QUICKTHREADS_ARGS_MD below.
00088 
00089    On varargs startup (still unimplemented):
00090 
00091    | padding to 128 byte boundary
00092    | varargs        <-- padded to a 128-byte-boundary
00093    +---
00094    | caller's frame, 16 bytes
00095    | 80 bytes of padding (frame padded to a 128-byte boundary)
00096    +---
00097    | cleanup
00098    | vuserf
00099    | startup
00100    | t
00101    +---
00102    | qt_start       <-- qt.sp
00103    +---
00104 
00105    Of a suspended thread:
00106 
00107    +---
00108    | caller's frame, 16 bytes
00109    | fpu registers 47 regs * 8 bytes/reg 376 bytes
00110    | ceu registers 16 regs * 8 bytes/reg 128 bytes
00111    | ipu registers 19 regs * 8 bytes/reg 152 bytes
00112    |  :
00113    | 80 bytes of padding
00114    |  :
00115    | qt_restore     <-- qt.sp
00116    +---
00117 
00118    */
00119 
00120 
00121 #define QUICKTHREADS_STKALIGN   128
00122 #define QUICKTHREADS_GROW_DOWN
00123 typedef unsigned long qt_word_t;
00124 
00125 #define QUICKTHREADS_STKBASE    QUICKTHREADS_STKALIGN
00126 #define QUICKTHREADS_VSTKBASE   QUICKTHREADS_STKBASE
00127 
00128 extern void qt_start(void);
00129 /*
00130  * See the discussion above for what indexing into a procedure ptr 
00131  * does for us (it's lovely, though, isn't it?).
00132  *
00133  * This assumes that the address of a procedure's code is the
00134  * first word in a procedure's constant block.  That's how the manual
00135  * says it will be arranged.
00136  */
00137 #define QUICKTHREADS_ARGS_MD(sp)    (QUICKTHREADS_SPUT (sp, 1, ((qt_word_t *)qt_start)[0]))
00138 
00139 /* 
00140  * The *index* (positive offset) of where to put each value.
00141  * See the picture of the stack above that explains the offsets.
00142  */
00143 #define QUICKTHREADS_ONLY_INDEX (5)
00144 #define QUICKTHREADS_USER_INDEX (4)
00145 #define QUICKTHREADS_ARGT_INDEX (3)
00146 #define QUICKTHREADS_ARGU_INDEX (2)
00147 
00148 #define QUICKTHREADS_VARGS_DEFAULT
00149 #define QUICKTHREADS_VARGS(sp, nb, vargs, pt, startup, vuserf, cleanup) \
00150       (qt_vargs (sp, nbytes, &vargs, pt, startup, vuserf, cleanup))
00151 
00152 
00153 #define QUICKTHREADS_VARGS_MD0(sp, vabytes) \
00154   ((qt_t *)(((char *)(sp)) - 4*8 - QUICKTHREADS_STKROUNDUP(vabytes)))
00155 
00156 extern void qt_vstart(void);
00157 #define QUICKTHREADS_VARGS_MD1(sp)  (QUICKTHREADS_SPUT (sp, 0, ((qt_word_t *)qt_vstart)[0]))
00158 
00159 #define QUICKTHREADS_VCLEANUP_INDEX (4)
00160 #define QUICKTHREADS_VUSERF_INDEX       (3)
00161 #define QUICKTHREADS_VSTARTUP_INDEX (2)
00162 #define QUICKTHREADS_VARGT_INDEX        (1)
00163 
00164 #endif /* def QUICKTHREADS_KSR1_H */

Generated on Wed Jan 21 15:32:10 2009 for SystemC by  doxygen 1.5.5