README.PORT revision 12027
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