English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 28 October 2019, 11:46   #1
Hedeon
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?
Hedeon is offline  
Old 28 October 2019, 13:15   #2
robinsonb5
Registered User
 
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
Quote:
Originally Posted by Hedeon View Post
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?
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.
robinsonb5 is offline  
Old 28 October 2019, 13:39   #3
Hedeon
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
Hedeon is offline  
Old 28 October 2019, 14:47   #4
phx
Natteravn
 
phx's Avatar
 
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".
phx is offline  
Old 28 October 2019, 15:43   #5
Hedeon
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.
Hedeon is offline  
Old 13 January 2020, 22:17   #6
Hedeon
Semi-Retired
 
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,993
Quote:
Originally Posted by phx View Post
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)");
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.
Hedeon is offline  
Old 14 January 2020, 11:17   #7
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Hedeon View Post
Can you confirm i can use any volatile register I want (r3-r12) inside the asm code without trashing stuff?
Using __asm() inside a C function? No. The compiler does not know what happens inside such a block.

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:
And non-volatile (r13-r31) are saved on the stack before jumping to a(n asm) function?
Saving and restoring non-volatile registers is always the duty of the callee, not of the caller.
phx is offline  
Old 14 January 2020, 11:44   #8
Hedeon
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 :-)
Hedeon is offline  
Old 06 April 2020, 22:54   #9
Hedeon
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?
Hedeon is offline  
Old 07 April 2020, 00:14   #10
robinsonb5
Registered User
 
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
Quote:
Originally Posted by Hedeon View Post
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?

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);
}
(The extra dummy parameters are to account for the extra entries on the stack - one extra return address and three registers.)

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.
robinsonb5 is offline  
Old 07 April 2020, 20:03   #11
Hedeon
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.
Hedeon is offline  
Old 07 April 2020, 22:41   #12
robinsonb5
Registered User
 
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
Quote:
Originally Posted by Hedeon View Post
There is also something like __amigainterrupt which reads like it will end with rts. Have to see.

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:
Not sure if __saveall would help here?

It would help a lot if it were implemented for m68k. Sadly, it's PPC only.
robinsonb5 is offline  
Old 01 July 2020, 11:42   #13
Hedeon
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.
Hedeon is offline  
 


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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:15.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.24983 seconds with 13 queries