28 October 2019, 11:46 | #1 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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? |
28 October 2019, 13:15 | #2 |
Registered User
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
|
I'm not 100% sure this will work, but you would need to modify the backend to mark registers r4 - r31 as allocated in the init_cg function (regsa[n]=1; careful, the register number doesn't map directly to n - see the register names array.) - then modify the t1, t2 and t3 values to restrict the compiler's internal scratch registers to the allowed range. You'll leave just one register free for the compiler's use so expect to see lots of stack operations.
|
28 October 2019, 13:39 | #3 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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: mfspr r2,HASH1 #get first pointer li r1,8 #load 8 for counter mfctr r0 #save counter mfspr r3,DCMP #get first compare value addi r2,r2,-8 #pre dec the pointer dm0: mtctr r1 #load counter dm1: lwzu r1,8(r2) #get next pte cmpw r1,r3 #see if found pte bdnzf eq,dm1 #dec count br if cmp ne and if count not zero bne dataSecHash #if not found set up second hash or exit lwz r1,4(r2) #load tlb entry lower-word mtctr r0 #restore counter mfspr r0,DMISS #get the miss address for the tlbld mfsrr1 r3 #get the saved cr0 bits mtcrf 0x80,r3 #restore CR0 mtspr RPA,r1 #set the pte ori r1,r1,PTE_REFERENCED #set reference bit srwi r1,r1,8 #get byte 7 of pte tlbld r0 #load the dtlb stb r1,6(r2) #update page table rfi #return to executing program dataSecHash: andi. r1,r3,PTE_HASHID #see if we have done second hash bne doDSI #if so, go to DSI interrupt mfspr r2,HASH2 #get the second pointer ori r3,r3,PTE_HASHID #change the compare value li r1,8 #load 8 for counter addi r2,r2,-8 #pre dec for update on load b dm0 #try second hash |
28 October 2019, 14:47 | #4 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
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". |
28 October 2019, 15:43 | #5 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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. |
13 January 2020, 22:17 | #6 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
I have opted to make parts of the exception code in asm. Can you confirm i can use any volatile register I want (r3-r12) inside the asm code without trashing stuff? And non-volatile (r13-r31) are saved on the stack before jumping to a(n asm) function? @phx.
|
14 January 2020, 11:17 | #7 | ||
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
|
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:
|
||
14 January 2020, 11:44 | #8 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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 :-) |
06 April 2020, 22:54 | #9 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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? |
07 April 2020, 00:14 | #10 | |
Registered User
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
|
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"; int func(int param1,int param2) { return(d1wrapper()); } int func_inner(int dummy1, int dummy2, int dummy3, int dummy4, int param1, int param2) { return(param1+param2); } 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.) Last edited by robinsonb5; 07 April 2020 at 09:07. |
|
07 April 2020, 20:03 | #11 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
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? Last edited by Hedeon; 07 April 2020 at 20:12. |
07 April 2020, 22:41 | #12 | ||
Registered User
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
|
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. |
||
01 July 2020, 11:42 | #13 |
Semi-Retired
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
|
Ended up with a library of some sorts. :-) Bit slower (5% or so) than the original asm one.
Thanks for all the support. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Preservation of registers | guy lateur | Coders. Asm / Hardware | 51 | 26 October 2018 14:33 |
A4000 IDE registers | mark_k | Coders. Asm / Hardware | 6 | 11 May 2015 17:05 |
Using FPU registers? | oRBIT | Coders. General | 16 | 26 April 2010 13:34 |
Need DA8000-DAFFFF registers documentation | BlueAchenar | Coders. General | 2 | 13 December 2008 15:39 |
Gayle Hardware Registers | bluea | support.Hardware | 5 | 09 July 2006 17:07 |
|
|