We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
what's the function of "AREGS"and "NOAREGS", can you provide me some sample, so that I could understand them clear. Are them still useful in current updated versions. In the manual it is said that with "NOAREGS" the function could be called by another functions using different register bank.
#pragma NOAREGS char add(char i) { return i+10; } void main(void) using 1 { ch = add(3); }
Hi,Thomas I tried the following codes,but I could never get right result soever I use NOARGS or not.
#pragma NOAREGS char add(char i) using 2 { return(i+10); } void main(void) using 1 { char ch; ch = add(3); while (1); }
The point about NOAREGS is that all registers also have an absolute address in memory. So, if the compiler knows that you are using register bank 0, it can access access registers R0, R1, ... R7 not only by name, but also accessing data memory addresses 0, 1, ... 7. Each register of each register bank has a unique address. Being able to access registers either way has advantages for speed and compactness of code. The compiler will use a mixture of addressing modes to get at the registers. The problems only start when a function is called and the currently selected register bank is unknown. In this case, the compiler cannot know the direct address of a register - in fact you have to tell it not to make any assumptions about the selected register bank by using NOAREGS. I find it very strange that the compiler should allow a function that has parameters passed in registers to set the register bank with using. The reason add() does not work with using 2 is parameter i is put into a register by main() and although add() will be looking at the right register, it will have changed the register bank. I cannot think of any good reason for the compiler not to generate a warning here.
You (Thomas and Nocky) are mixing two different things. The directive using determines what register bank will compiler use (if it ever needs use registers) in the particular function. The original RB is saved in the beginning (push psw), then switched to the required one (mov psw,#xx) and the original RB restored on exit (pop psw). The directives AREGS/NOAREGS tell the compiler if it CAN/CANNOT use (if it ever needs use registers) absolute register addressing, ie. direct addresses AR0 to AR7 for registers R0 to R7 of the Register Bank right being used. That's why it is called AREGS = A(bsolute)REG(ister)S. It means: if RB=0, AR0 address is 0; if RB=1, AR0 address is 8 and so on... or as if you "defined":
if (RB == 0) AR0 data 0 ; assembler AR1 data 1 ... endif if (RB == 1) AR0 data 8 AR1 data 9 ... endif
mov a,r0 ; this way it will be compiled with NOAREGS push acc
; and this way with AREGS push AR0 ; shorter but Register Bank dependent!
mov a,r7 ; 1 byte, 1 cycle instruction code
mov a,ar7 ; 2 bytes, 1 cycle instruction code
; FUNCTION _add (BEGIN) MOV A,R7 ; - Variable 'i' assigned to Register 'R7' - ADD A,#0AH ; RB without change, ie. RB1 for it was changed in main() MOV R7,A ; return value in R7, the same RB RET ; FUNCTION _add (END) ; FUNCTION main (BEGIN) PUSH PSW MOV PSW,#08H ; Register bank switched to RB1 MOV R7,#03H ; passing parameter value i=3 in R7-RB1 LCALL _add ; function _add(char i) doesn't touch RBs' setup MOV ch,R7 ; so the return value is in the right register POP PSW RET ; FUNCTION main (END)
; FUNCTION _add (BEGIN) PUSH PSW MOV PSW,#010H ; Register bank switched to RB2 MOV A,R7 ; - Variable 'i' assigned to Register 'R7' - but RB2!!! ADD A,#0AH MOV R7,A ; function _add returns the result in R7, but RB2!!! ?C0001: POP PSW RET ; FUNCTION _add (END) ; FUNCTION main (BEGIN) PUSH PSW MOV PSW,#08H ; Register bank switched to RB1 MOV R7,#03H ; passing parameter value i=3 in R7-RB1!!! LCALL _add MOV ch,R7 ; return value is expected to be in R7-RB1 again!!! ?C0002: SJMP ?C0002 ; FUNCTION main (END)
Thanks for your help! But in the manual it is said that with "NOAREGS" one function could be called by another functions using different register bank, why the manual said so, does it mean that with "AREGS" the function could not be called by another functions using different register bank. In the above examples, the two functios add() and main() use different register bank, but whether I used #pragam NOAREGS or #pragma AREGS, I always get the right answer. While in Nocky's sample, whether you used #pragam NOAREGS or #pragma AREGS, you always get the wrong result. How does the "AREGS" and "NOARGES" influence the two functions, only the addressing method?
The discussed directives have, as far as I know, the meaning I have explained. NOAREGS disables absolute register access, while AREGS enables (but not forces) it. When enabled, the compiler decides whether to use it or not in a particular situation ("is it advantageous or not?"). It doesn't mean that the addressing method unconditionally changes to absolute register accesses in every case. See your compiled programs in my previous post. You obtain the same result either you use AREGS or NOAREGS, because in both these examples NOAREGS option "prevails". There is no reason for absolute register access there. That's why it is not used even if AREGS option is selected. "But in the manual it is said that with "NOAREGS" one function could be called by another functions using different register bank..." In my opinion it is confusing (if not even wrong) as far as passing parameters or return values in registers are concerned. I suppose you mean C51.pdf, page 24 (?): "This directive may be used for functions that are called from other functions using different register banks." or further, on page 124: "To make a function insensitive to the current register bank, the function must be compiled using the NOAREGS control directive. This would be useful for a function that was called from the main program and also from an interrupt function that uses a different register bank. Note: The Cx51 compiler does not and cannot detect a register bank mismatch between functions. Therefore, make sure that functions using alternate register banks call only other functions that do not assume a default register bank." and later, page 128: "Functions called from an interrupt procedure must function with the same register bank as the interrupt procedure. When the NOAREGS directive is not explicitly specified, the compiler may generate absolute register accesses using the register bank selected (by the using attribute or by the REGISTERBANK control) for that function. Unpredictable results may occur when a function assumes a register bank other than the one currently selected." Once more as to the function register bank in/dependance - for instance lets assume 2 functions: a) func1() compiled with NOAREGS pragma, containing "mov r7,a" instruction in its body, the resulting code is 0xFF b) func2() compiled with AREGS pragma, containing corresponding to the above "mov ar7,a" instruction in its body, the resulting codes are 0xF5 0x17 if register bank used at compile time was 2 if current register bank for both functions at calling time is, say, 1, then func1() will always write in R7 of the current register bank while func2() will write in absolute address 17H which is probably not the intention This is, among others, what they meant "To make a function insensitive to the current register bank..." In my opinion the RB independence concerns rather the body of the function than parameters or return values passed in registers. The directive "using" is suitable (my opinion) esp. with ISRoutines to prevent them from pushing big load onto the (very limited) stack. It is also useful for functions called from ISR. Using "using" :-) for other common functions seems to me a bit "violent". Best wishes
Since the compiler doesn't give a warning ,can I say this is a bug? We can send to keil?
Having a look at this note in Manual: "The Cx51 compiler does not and cannot detect a register bank mismatch between functions. Therefore, make sure that functions using alternate register banks call only other functions that do not assume a default register bank." I think it is true, so for the above mentioned warning the adjective "missing" is at least disputable. Realize that compile time and run time are different things and the compiler (compile time) doesn't necessarily know the actual RB of a function at run time in general. Sometimes it is up to you to judge and decide. That's why I suggested: don't use using directive with common functions unless you have a really important reason for it (ISR, etc.)
Please look at discussion thread 1807 http://www.keil.com/forum/docs/thread1807.asp