📄 c5111.txt
字号:
发信人: reflection (似水流年), 信区: EEtechnology
标 题: C51 primer (10) Miscellaneous Points
发信站: 南京大学小百合站 (Wed Nov 24 12:03:29 1999), 转信
10 Miscellaneous Points
10.1 Tying The C Program To The Restart Vector
This is achieved by the assembler file STARTUP.A51. This program simply plac
es a LJMP STARTUP at location C0000 (Lowest EPROM location
The startup routine just clears the internal RAM and sets up the stack point
er. Finally it executes a LJMP to "main", (hopefully) the first function in
the C program.
LJMP main
.
.
.
.
main()
{
}
In fact this need be the only assembler present in a C51 program.
10.2 Intrinsic Functions
There are a number of special 8051 assembler instructions which are not norm
ally used by C51. For the sake of speed it is sometimes useful to get direct
access to these.
Unlike the normal C51 '>>' functions, _cror_ allows direct usage of an 8051
instruction set feature, in this case the "RR A" (rotate accumulator). This
yields a much faster result than would be obtained by writing one using bits
and the normal >> operator. There are also _iror_ and _lror_ intrinsic func
tions for integer and long data as well.
The _nop_ function simply adds an in-line NOP instruction to generate a shor
t and predictable time delay. Another function, _testbit_, makes use of the
JBC instruction to allow a bit to be tested, a branch taken and the bit clea
red if set. The only extra step necessary is to include "intrins.h" in the C
51 source file.
Here is an example of how the _testbit_() intrinsic function is used to save
a CLR instruction:
; #include <intrins.h>
;
;
; unsigned int shift_reg = 0 ;
;
; bit test_flag ;
;
; void main(void) {
RSEG ?PR?main?T
USING 0
main:
; SOURCE LINE # 12
;
; /* Use Normal Approach */
;
; test_flag = 1 ;
; SOURCE LINE # 14
SETB test_flag
;
; if(test_flag == 1) {
; SOURCE LINE # 16
JNB test_flag,?C0001
; test_flag = 0 ;
; SOURCE LINE # 17
CLR test_flag
; P1 = 0xff ;
; SOURCE LINE # 18
MOV P1,#0FFH
; }
; SOURCE LINE # 19
?C0001:
;
; /* Use Intrinsic Function */
;
; test_flag = 1 ;
; SOURCE LINE # 21
SETB test_flag
;
; if(!_testbit_(test_flag)) {
; SOURCE LINE # 23
JBC test_flag,?C0003
; P1 = 0xff ;
; SOURCE LINE # 24
MOV P1,#0FFH
; }
; SOURCE LINE # 25
;
; }
; SOURCE LINE # 27
?C0003:
RET
; END OF main
END
See pages 9-17 in the C51 Manual
10.3 EA Bit Control #pragma
Whilst the interrupt modifier for function declarations remains unchanged a
new directive, DISABLE, allows interrupts to be disabled for the duration of
a function. Note that this can be individually applied to separate function
s within a module but is given as a #pragma rather than as part of the funct
ion declaration. Although not verified yet, DISABLE gives the user some cont
rol over the EA or EAL bit.
10.4 16 Bit sfr Support
Another new feature is the 16bit sfr type. Within expanded 8051 variants in
particular, many 16 bit timer and capture registers exist. Rather than havin
g to load the upper and lower bytes individually with separate C statements,
the sfr16 type is provided. The actual address declared for a 16 bit sfr in
the header file is always the low byte of the sfr. Now to load a 16 bit sfr
from C, only a single int load is required. Be warned - 8-bit instructions
are still used, so the 16 bit load/read is not indivisible - odd things can
happen if you load a timer and it overflows during the process! Note that us
ually only timer 2 or above has the high/low bytes arranged sequentially.
10.5 Function Level Optimisation
Optimisation levels of 4 and above are essentially function optimisations an
d, as such, the whole function must be held in PC memory for processing. If
there is insufficient memory for this, a warning is issued and the additiona
l optimisation abandoned. Code execution will still be correct however. See
p1-8 in the C51 manual.
10.6 In-Line Functions In C51
One of the fundamentals of C is that code with a well-defined input, output
and job is placed into a function i.e. a subroutine. This involves placing p
arameters into a passing area, whether a stack or a register, and then execu
ting a CALL. It is unavoidable that the call instruction will use two bytes
of stack.
In most 8051 applications this not a problem, as there is generally 256 on-c
hip RAM potentially available as stack. Even after allowing for a few regist
erbanks, there is normally sufficient stack space for deeply nested function
s.
However in the case of the 8031 and reduced devices such as the 87C751, ever
y byte of RAM is critical. In the latter case there are only 64 bytes!
A trick which can both save stack and reduce run time is to use macros with
parameters to act like "in-line" functions. The ability to create macros wit
h replaceable parameters is not commonly used but on limited RAM variants it
can be very useful.
Here a strcpy() function created as a macro named "Inline_Strcpy", whilst it
looks like a normal function, it does not actually have any fixed addresses
or local data of its own. The '\' characters serve to allow the macro defin
ition to continue to a new line, in this case to preserve the function-like
appearance.
It is "called" like a normal function with the parameters to be passed enclo
sed in ( ). However no CALL is used and the necessary code is created in-lin
e. The end result is that a strcpy is performed but no new RAM or stack is r
equired.
Please note however, the drawback with this very simple example is that the
source and destination pointers are modified by the copying process and so i
s rather suspect!
A further benefit in this example is that the notional pointers s1 and s2 ar
e automatically memory-specific and thus very efficient. Thus in situations
where the same function must operate on pointer data in a variety of memory
spaces, slow generic pointers are not required.
#define Inline_Strcpy(s1,s2) {\ while((*s1 = *s2) != 0)}\
{\*s1++ ; *s2++; }\
}
char xdata *out_buffx = { " " } ;
char xdata *in_buffx = { "Hello" } ;
char idata *in_buffi = { "Hello" } ;
char idata *out_buffi = { " " } ;
char code *in_buffc = { "Hello" } ;
void main(void) {
Inline_Strcpy(out_buffx,in_buffx) // In line functions
Inline_Strcpy(out_buffi,in_buffi)
Inline_Strcpy(out_buffx,in_buffc)
}
Another good example of how a macro with parameters can be used to aid sourc
e readability is in the optimisation feature in Appendix D. The interpolatio
n calculation that originally formed a subroutine could easily be redefined
as a macro with 5 parameters, realising a ram and run time saving at the exp
ense of code size.
Note that 'r', the fifth parameter, represents the return value which has to
be "passed" to the macro so that it has somewhere to put the result!
#define interp_sub(x,y,n,d,r) y -= x ; \
if(!CY) { r = (unsigned char) (x +(unsigned char)(((unsigned
int)(n * y))/d)) ;\
} else { r = (unsigned char) (x - (unsigned char)(((unsigned int)(n * -y))/d
)) ; }
This is then called by:
/*Interpolate 2D Map Values */
/*Macro With Parameters Used*/
interp_sub(map_x1y1,map_x2y1,x_temp1,x_temp2,result_y1)
and later it is reused with different parameters thus:
interp_sub(map_x1y2,map_x2y2,x_temp1,x_temp2,result_y2)
To summarise, parameter macros are a good way of telling C51 about a general
ised series of operations whose memory spaces or input values change in prog
rams where speed or RAM usage is critical.
----------------------------------------------------------------------------
----
--
Ours is essentially a tragic age, so we refuse to take it tragically.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -