![]() |
VBCC: Restrict usage of registers in C
Hi,
I am busy transferring the WarpOS compatible kernel I did for PCI PPC cards from assembly to C. Of course the kernel is very low level and it is unavoidable to use assembly here and there. The 603 and e300 PPCs don't have hardware tlb lookup and make use of software exceptions to load the correct values from the page table. To accomplish this the exceptions use four shadow registers called r0-r3. They are independent from the 'normal' registers which are also called r0-r3 (up to r31). IF I want to make this in C, I need to restrict the usage of registers to these 4. Is this even possible with VBCC? |
Quote:
|
Had hoped that some directive would do. Current source does not use stack and only modifies the software page table.
I'd guess this is one of those parts that will stay in assembly. Excerpt: Code:
.DLoadTLBMiss: |
No, you cannot restrict the code generator to use certain registers in a function. But to minimize assembler usage you could either use the __saveall attribute, which also saves/restores all (used) volatile registers, or insert inline-assembler to save them: __asm("\tstw\tr4,offset(r1)");
You might also want to use the __interrupt attribute, which makes sure that such a function ends with "rfi" instead of "blr". |
Thanks @phx. I learned that from you last time we spoke :-) (regarding __interrupt)
See https://github.com/Sakura-IT/PowerPC...aster/kernel.c or https://github.com/Sakura-IT/PowerPCAmiga Nothing much there yet. I need to use assembly anyway to access the special registers, but want to keep it at minimum. For these tlb exceptions I'll just use assembly also for speed reasons. |
Quote:
|
Quote:
Or did you think about calling an assembler function or inline routine? Then yes, the compiler always treats the ABI-defined volatile registers accordingly and may save them before a call. If your function does not use all volatile registers you may specify that with __regsused(). Quote:
|
I meant a C function calling an asm function. I use r3-r12 in those asm functions and was hoping that that would be possible without saving them all and then restoring them again inside the asm function. You say they are saved in the caller function so that is great.
Regarding r13-r31, that was a duh moment as I should have known that :-) WarpOS has a small exception context that directly uses all the registers from the original interrupted task. However, the main exception itself (which is mostly C) of course changes a lot of these registers before it jumps to the custom exception handler (wosdb uses large exception context in which the interrupted task registers are used indirectly from the context, iFusion uses small context. Only two programs I know that uses them). I had hoped that I just needed to reload the volatile registers before jumping to the small context custom exception, but I just better reload all the registers (they were saved in a stack frame when the main exception happened). Thanks for your help. Now to finish this project quickly :-) |
I have another registers related question and this is more for the 68K backend but it is WarpOS related:
I see in the original powerpc.library that all registers are saved on the stack except d0. I now also see that some WarpOS programs from the WarpOS distribution itself rely on this (e.g. CyberPi). They use but don't save d1 before calling RunPPC and use it again after. This works with the original powerpc.library, but in C d1 (and a0 and a1) are not saved as they are volatile. For optimal compatibility I also need to save those registers and I want it to do without asm. I looked through the vbcc manual but cannot find anything on this. Is this possible? |
Quote:
Possible, yes - but very ugly. The only way I can think of (without modifying vbcc) would be to use an inline assembly function to save the registers. It would look something like this: Code:
int d1wrapper() = "\tmovem.l a0-a1/d1,-(a7)\n\tjsr _func_inner\n\tmovem.l (a7)+,a0-a1/d1\n"; Edit: if you don't need to return a value to the caller, you can simply declare your function with the __interrupt attribute. Unfortunately, because it saves and restores not just d1/a0/a1, but d0 as well, you lose the ability to return a value! Edit 2: If your function uses register parameters, rather than stack based parameters, (and I guess it does if it's a library function) then the hideous hack with dummy parameters shouldn't be necessary - you should be able to just omit those.) |
Yes. It is a library function. I do have some asm already in there (especially at the ppc side due to special registers), so I could just add to the asm part something like push, bsr/jsr function and pop, but maybe there was something like __interrupt but then ending with rts (and not rte) and not restoring d0 (didn't know it did that, actually).
Thanks for the suggestions. I guess I have to add a little bit of asm. EDIT: There is also something like __amigainterrupt which reads like it will end with rts. Have to see. EDIT2: Not sure if __saveall would help here? |
Quote:
Ah yes, I missed that __interrupt causes the function to end with rte. A quick test suggests __amigainterrupt doesn't seem to save the scratch registers either. Quote:
It would help a lot if it were implemented for m68k. Sadly, it's PPC only. |
Ended up with a library of some sorts. :-) Bit slower (5% or so) than the original asm one.
Thanks for all the support. |
All times are GMT +2. The time now is 17:34. |
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, vBulletin Solutions Inc.