112027Sjungma@eit.uni-kl.deDate: Tue, 11 Jan 94 13:23:11 -0800
212027Sjungma@eit.uni-kl.deFrom: "pardo@cs.washington.edu" <pardo@meitner.cs.washington.edu>
312027Sjungma@eit.uni-kl.de
412027Sjungma@eit.uni-kl.de>[What's needed to get `qt' on an i860-based machine?]
512027Sjungma@eit.uni-kl.de
612027Sjungma@eit.uni-kl.deAlmost certainly "some assembly required" (pun accepted).
712027Sjungma@eit.uni-kl.de
812027Sjungma@eit.uni-kl.deTo write a cswap port, you need to understand the context switching
912027Sjungma@eit.uni-kl.demodel.  Turn to figure 2 in the QT TR.  Here's about what the assembly
1012027Sjungma@eit.uni-kl.decode looks like to implement that:
1112027Sjungma@eit.uni-kl.de
1212027Sjungma@eit.uni-kl.de	qt_cswap:
1312027Sjungma@eit.uni-kl.de		adjust stack pointer
1412027Sjungma@eit.uni-kl.de		save callee-save registers on to old's stack
1512027Sjungma@eit.uni-kl.de		argument register <- old sp
1612027Sjungma@eit.uni-kl.de		sp <- new sp
1712027Sjungma@eit.uni-kl.de		(*helper)(args...)
1812027Sjungma@eit.uni-kl.de		restore callee-save registers from new's stack
1912027Sjungma@eit.uni-kl.de		unadjust stack pointer
2012027Sjungma@eit.uni-kl.de		return
2112027Sjungma@eit.uni-kl.de
2212027Sjungma@eit.uni-kl.deOnce more in slow motion:
2312027Sjungma@eit.uni-kl.de
2412027Sjungma@eit.uni-kl.de	- `old' thread calls context switch routine (new, a0, a1, h)
2512027Sjungma@eit.uni-kl.de	- cswap routine saves registers that have useful values
2612027Sjungma@eit.uni-kl.de	- cswap routine switches to new stack
2712027Sjungma@eit.uni-kl.de	- cswap routine calls helper function (*h)(old, a0, a1)
2812027Sjungma@eit.uni-kl.de	- when helper returns, cswap routine restores registers
2912027Sjungma@eit.uni-kl.de	  that were saved the last time `new' was suspended
3012027Sjungma@eit.uni-kl.de	- cswap routine returns to whatever `new' routine called the
3112027Sjungma@eit.uni-kl.de	  context switch routine
3212027Sjungma@eit.uni-kl.de
3312027Sjungma@eit.uni-kl.deThere's a few tricks here.  First, how do you start a thread running
3412027Sjungma@eit.uni-kl.defor the very first time?  Answer is: fake some stuff on the stack
3512027Sjungma@eit.uni-kl.deso it *looks* like it was called from the middle of some routine.
3612027Sjungma@eit.uni-kl.deWhen the new thread is restarted, it is treated like any other
3712027Sjungma@eit.uni-kl.dethread.  It just so happens that it's never really run before, but
3812027Sjungma@eit.uni-kl.deyou can't tell that because the saved state makes it look like like
3912027Sjungma@eit.uni-kl.deit's been run.  The return pc is set to point at a little stub of
4012027Sjungma@eit.uni-kl.deassembly code that loads up registers with the right values and
4112027Sjungma@eit.uni-kl.dethen calls `only'.
4212027Sjungma@eit.uni-kl.de
4312027Sjungma@eit.uni-kl.deSecond, I advise you to forget about varargs routines (at least
4412027Sjungma@eit.uni-kl.deuntil you get single-arg routines up and running).
4512027Sjungma@eit.uni-kl.de
4612027Sjungma@eit.uni-kl.deThird, on most machines `qt_abort' is the same as `qt_cswap' except
4712027Sjungma@eit.uni-kl.dethat it need not save any callee-save registers.
4812027Sjungma@eit.uni-kl.de
4912027Sjungma@eit.uni-kl.deFourth, `qt_cswap' needs to save and restore any floating-point
5012027Sjungma@eit.uni-kl.deregisters that are callee-save (see your processor handbook).  On
5112027Sjungma@eit.uni-kl.desome machines, *no* floating-point registers are callee-save, so
5212027Sjungma@eit.uni-kl.de`qt_cswap' is exactly the same as the integer-only cswap routine.
5312027Sjungma@eit.uni-kl.de
5412027Sjungma@eit.uni-kl.deI suggest staring at the MIPS code for a few minutes.  It's "mostly"
5512027Sjungma@eit.uni-kl.degeneric RISC code, so it gets a lot of the flavor across without
5612027Sjungma@eit.uni-kl.degetting too bogged down in little nitty details.
5712027Sjungma@eit.uni-kl.de
5812027Sjungma@eit.uni-kl.de
5912027Sjungma@eit.uni-kl.de
6012027Sjungma@eit.uni-kl.deNow for a bit more detail:  The stack is laid out to hold callee-save
6112027Sjungma@eit.uni-kl.deregisters.  On many machines, I implemented fp cswap as save fp
6212027Sjungma@eit.uni-kl.deregs, call integer cswap, and when integer cswap returns (when the
6312027Sjungma@eit.uni-kl.dethread wakes up again), restore fp regs.
6412027Sjungma@eit.uni-kl.de
6512027Sjungma@eit.uni-kl.deFor thread startup, I figure out some callee-save registers that
6612027Sjungma@eit.uni-kl.deI use to hold parameters to the startup routine (`only').  When
6712027Sjungma@eit.uni-kl.dethe thread is being started it doesn't have any saved registers
6812027Sjungma@eit.uni-kl.dethat need to be restored, but I go ahead and let the integer context
6912027Sjungma@eit.uni-kl.deswitch routine restore some registers then "return" to the stub
7012027Sjungma@eit.uni-kl.decode.  The stub code then copies the "callee save" registers to
7112027Sjungma@eit.uni-kl.deargument registers and calls the startup routine.  That keeps the
7212027Sjungma@eit.uni-kl.destub code pretty darn simple.
7312027Sjungma@eit.uni-kl.de
7412027Sjungma@eit.uni-kl.deFor each machine I need to know the machine's procedure calling
7512027Sjungma@eit.uni-kl.deconvention before I write a port.  I figure out how many callee-save
7612027Sjungma@eit.uni-kl.deregisters are there and allocate enough stack space for those
7712027Sjungma@eit.uni-kl.deregisters.  I also figure out how parameters are passed, since I
7812027Sjungma@eit.uni-kl.dewill need to call the helper function.  On most RISC machines, I
7912027Sjungma@eit.uni-kl.dejust need to put the old sp in the 0'th arg register and then call
8012027Sjungma@eit.uni-kl.deindirect through the 3rd arg register; the 1st and 2nd arg registers
8112027Sjungma@eit.uni-kl.deare already set up correctly.  Likewise, I don't touch the return
8212027Sjungma@eit.uni-kl.devalue register between the helper's return and the context switch
8312027Sjungma@eit.uni-kl.deroutine's return.
8412027Sjungma@eit.uni-kl.de
8512027Sjungma@eit.uni-kl.deI have a bunch of macros set up to do the stack initialization.
8612027Sjungma@eit.uni-kl.deThe easiest way to debug this stuff is to go ahead and write a C
8712027Sjungma@eit.uni-kl.deroutine to do stack initialization.  Once you're happy with it you
8812027Sjungma@eit.uni-kl.decan turn it in to a macro.
8912027Sjungma@eit.uni-kl.de
9012027Sjungma@eit.uni-kl.deIn general there's a lot of ugly macros, but most of them do simple
9112027Sjungma@eit.uni-kl.dethings like return constants, etc.  Any time you're looking at it
9212027Sjungma@eit.uni-kl.deand it looks confusing you just need to remember "this is actually
9312027Sjungma@eit.uni-kl.desimple code, the only tricky thing is calling the helper between
9412027Sjungma@eit.uni-kl.dethe stack switch and the new thread's register restore."
9512027Sjungma@eit.uni-kl.de
9612027Sjungma@eit.uni-kl.de
9712027Sjungma@eit.uni-kl.deYou will almost certainly need to write the assembly code fragment
9812027Sjungma@eit.uni-kl.dethat starts a thread.  You might be able to do a lot of the context
9912027Sjungma@eit.uni-kl.deswitch code with `setjmp' and `longjmp', if they *happen* to have
10012027Sjungma@eit.uni-kl.dethe "right" implementation.  But getting all the details right (the
10112027Sjungma@eit.uni-kl.dehelper can return a value to the new thread's cswap routine caller)
10212027Sjungma@eit.uni-kl.deis probaby trickier than writing code that does the minimum and
10312027Sjungma@eit.uni-kl.dethus doesn't have any extra instructions (or generality) to cause
10412027Sjungma@eit.uni-kl.deproblems.
10512027Sjungma@eit.uni-kl.de
10612027Sjungma@eit.uni-kl.deI don't know of any ports besides those included with the source
10712027Sjungma@eit.uni-kl.decode distribution.   If you send me a port I will hapily add it to
10812027Sjungma@eit.uni-kl.dethe distribution.
10912027Sjungma@eit.uni-kl.de
11012027Sjungma@eit.uni-kl.deLet me know as you have questions and/or comments.
11112027Sjungma@eit.uni-kl.de
11212027Sjungma@eit.uni-kl.de	;-D on  ( Now *that*'s a switch... )  Pardo
113