Hello, I'm having trouble understanding the NOAREG, AREG & USING options. I'm also confused with R0-R7 & AR0-AR7. I've read the support files and manual but i'm still confused. May I know a) How is it that using NOAREGs will allow me to disregard register bank currently used when writing function? ( will the registers be automatically saved to stack? ) b) What is the difference with R0 and AR0? How does the USING option affect R0 & AR0? (for example if i put the option "USING 2", have then use R4, does this mean that it is the actually R20 ie in bank 2, whiel AR4 is not affected by the using function) c) How does USING help me to save stack space? Best Regards, AL
The 8051 family of processors have four register banks each of which contain eight 8-bit registers R0 through R7. At any instant, exactly one register bank is selected so that any instruction that references register Rn will access Rn in the currently selected register bank. i.e. the register that is accessed is affected by the currently selected register bank. However, all the registers in all the register banks also have unique direct addresses so that it is also possible to access any register Rn from any register bank – regardless of the currently selected register bank. 8051 instruction have a fairly limited range of addressing modes. For example, it is not possible to move the contents of one register to another directly as in MOV R0,R1. If code is written with knowledge of which register bank is selected when the code is to be executed, then there is an alternative way to access a register – because its absolute address is know. For convenience, the absolute address of a register Rn is simply ARn. So, an instruction such as MOV R0,AR1 is now possible. The Assembler/Compiler knows the currently selected register bank required to work out the absolute address of a register by either using a default (usually register bank 0) or because it has been told otherwise by a C #pragma REGISTERBANK(n) or an Assembler USING control. Note that these controls do not themselves change the register bank selected, they only affect the calculation of the absolute addresses of the ARn registers. Generally, being able to address registers directly is an advantage and results in faster and more compact code. The generation of code that uses absolute register addressing is turned on by the C #pragma AREGS. However, it is possible that a function may be called and it is not known what the currently selected register bank is – the compiler must be told not to attempt to use instructions that use absolute register address because the absolute addresses cannot be reliably computed at compile time. This situation is indicated to the compiler by using #pragma NOAREGS. Sometimes, it is useful to be able to change the currently selected register bank. In Keil C this should be done using the using keyword. This is most usefully applied when the function is question is an interrupt. When an interrupt is generated and the interrupt service function is invoked, that function will need a set of working registers to get anything non-trivial done. Obviously, the interrupt service function must not change the value of any registers in the code that was interrupted. There are two ways of achieving this, the interrupt function can save the current value of all registers that it needs onto the stack and restore them before returning to the interrupted code; or it can switch to a register bank that <u>cannot</u> currently be in use and restore the register bank before returning to the interrupted code. The latter option is generally faster and is achieved by the using keyword. It is common practice to assign a register bank to each 'level' of execution in the code. For example, the base level code (everything called by main) uses register bank 0 (default), low-priority interrupt use register bank 1 and high priority interrupts use register bank 2. Everything should be fairly straightforward unless the interrupt function calls another function – the called function must have the correct register bank indicated by #pragma REGISTERBANK(n); otherwise, things will go very wrong. In general, a function should only be called from code from one 'level' of execution. This can be done, but it is a whole other subject.
Hello, First of all I wanted to thank Cole for his excellent explanation. It clears a lot of the fog around this issue, and I think that this explanation should be entered into the manual ! I still have several questions regarding interrupt coding and relevant compiler directives: 1) Assuming the following code:
void UartIsr( void ) INTERRUPT(4) USING(2) { f1(); } #pragma NOAREGS void f1(void) { … … f2(); … … } #pragma AREGS void f2(void) { … … … }
And some more questions... Is it deafult compilation state to use AREG if no AREG/NOAREG pragma is written in the code ? Do I need to specify it in the beginning of main? If I specify any option (use AREG or NOAREG) at a specific place in the code, will this direction be relevant in all the following code (including called functions) untill a new direction will be issued ?
View all questions in Keil forum