⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdccman.txt

📁 很少见的源码公开的msc51和z80的c编译器。
💻 TXT
📖 第 1 页 / 共 5 页
字号:
Well you get the idea. For compatibility with the previous version of the compiler,the following syntax for pointer declaration is still supportedbut will disappear int the near future. unsigned char _xdata *ucxdp; /* pointer to data in externalram */ unsigned char _data  *ucdp ; /* pointerto data in internal ram */ unsigned char _code  *uccp ; /* pointerto data in R/O code space */unsigned char _idata *uccp;  /*pointer to upper 128 bytes of ram */All unqualified pointers are treated as 3-byte (4-byte forthe ds390) generic pointers. These type of pointers canalso to be explicitly declared.unsigned char _generic *ucgp;The highest order byte of the generic pointers contains thedata space information. Assembler support routines are calledwhenever data is stored or retrieved using generic pointers.These are useful for developing reusable library routines.Explicitly specifying the pointer type will generate themost efficient code. Pointers declared using a mixture ofOLD and NEW style could have unpredictable results. Parameters & Local VariablesAutomatic (local) variables and parameters to functions caneither be placed on the stack or in data-space. The defaultaction of the compiler is to place these variables in theinternal RAM (for small model) or external RAM (for Largemodel). This in fact makes them static so by default functionsare non-reentrant.They can be placed on the stack either by using the --stack-autocompiler option or by using the reentrant keyword in thefunction declaration, e.g.:unsigned char foo(char i) reentrant { ... }Since stack space on 8051 is limited, the reentrant keywordor the --stack-auto option should be used sparingly. Notethat the reentrant keyword just means that the parameters& local variables will be allocated to the stack, it doesnot mean that the function is register bank independent.Local variables can be assigned storage classes and absoluteaddresses, e.g.: unsigned char foo() {    xdata unsigned char i;    bit bvar;    data at 0x31 unsiged char j;    ... }In the above example the variable i will be allocated inthe external ram, bvar in bit addressable space and j ininternal ram. When compiled with --stack-auto or when afunction is declared as reentrant this can only be donefor static variables.Parameters however are not allowed any storage class, (storageclasses for parameters will be ignored), their allocationis governed by the memory model in use, and the reentrancyoptions. OverlayingFor non-reentrant functions SDCC will try to reduce internalram space usage by overlaying parameters and local variablesof a function (if possible). Parameters and local variablesof a function will be allocated to an overlayable segmentif the function has no other function calls and the functionis non-reentrant and the memory model is small. If an explicitstorage class is specified for a local variable, it willNOT be overlayed.Note that the compiler (not the linkage editor) makes thedecision for overlaying the data items. Functions that arecalled from an interrupt service routine should be precededby a #pragma NOOVERLAY if they are not reentrant.Also note that the compiler does not do any processing ofinline assembler code, so the compiler might incorrectlyassign local variables and parameters of a function intothe overlay segment if the inline assembler code calls otherc-functions that might use the overlay. In that case the#pragma NOOVERLAY should be used.Parameters and Local variables of functions that contain16 or 32 bit multiplication or division will NOT be overlayedsince these are implemented using external functions, e.g.:#pragma SAVE #pragma NOOVERLAY void set_error(unsigned char errcd) {    P3 = errcd;} #pragma RESTORE void some_isr () interrupt 2 using 1 {    ...    set_error(10);    ... }In the above example the parameter errcd for the functionset_error would be assigned to the overlayable segment ifthe #pragma NOOVERLAY was not present, this couldcause unpredictable runtime behavior when called from anISR. The #pragma NOOVERLAY ensures thatthe parameters and local variables for the function areNOT overlayed. Interrupt Service RoutinesSDCC allows interrupt service routines to be coded in C,with some extended keywords.void timer_isr (void) interrupt 2 using 1 { .. }The number following the interrupt keyword is the interruptnumber this routine will service. The compiler will inserta call to this routine in the interrupt vector table forthe interrupt number specified. The using keyword is usedto tell the compiler to use the specified register bank(8051 specific) when generating code for this function.Note that when some function is called from an interruptservice routine it should be preceded by a #pragma NOOVERLAYif it is not reentrant. A special note here, int (16 bit)and long (32 bit) integer division, multiplication & modulusoperations are implemented using external support routinesdeveloped in ANSI-C, if an interrupt service routine needsto do any of these operations then the support routines(as mentioned in a following section) will have to be recompiledusing the --stack-auto option and the source file will needto be compiled using the --int-long-rent compiler option.If you have multiple source files in your project, interruptservice routines can be present in any of them, but a prototypeof the isr MUST be present or included in the file thatcontains the function main.Interrupt Numbers and the corresponding address & descriptionsfor the Standard 8051 are listed below. SDCC will automaticallyadjust the interrupt vector table to the maximum interruptnumber specified.+--------------+--------------+----------------+| Interrupt #  | Description  | Vector Address |+--------------+--------------+----------------++--------------+--------------+----------------+|      0       | External 0   |     0x0003     |+--------------+--------------+----------------+|      1       |   Timer 0    |     0x000B     |+--------------+--------------+----------------+|      2       | External 1   |     0x0013     |+--------------+--------------+----------------+|      3       |   Timer 1    |     0x001B     |+--------------+--------------+----------------+|      4       |   Serial     |     0x0023     |+--------------+--------------+----------------+If the interrupt service routine is defined without usinga register bank or with register bank 0 (using 0), the compilerwill save the registers used by itself on the stack uponentry and restore them at exit, however if such an interruptservice routine calls another function then the entire registerbank will be saved on the stack. This scheme may be advantageousfor small interrupt service routines which have low registerusage.If the interrupt service routine is defined to be using aspecific register bank then only a, b & dptr are save andrestored, if such an interrupt service routine calls anotherfunction (using another register bank) then the entire registerbank of the called function will be saved on the stack.This scheme is recommended for larger interrupt serviceroutines.Calling other functions from an interrupt service routineis not recommended, avoid it if possible.Also see the _naked modifier. Critical FunctionsA special keyword may be associated with a function declaringit as critical. SDCC will generate code to disable all interruptsupon entry to a critical function and enable them back beforereturning. Note that nesting critical functions may causeunpredictable results.int foo () critical { ... ... }The critical attribute maybe used with other attributes likereentrant. Naked FunctionsA special keyword may be associated with a function declaringit as _naked. The _naked function modifier attribute preventsthe compiler from generating prologue and epilogue codefor that function. This means that the user is entirelyresponsible for such things as saving any registers thatmay need to be preserved, selecting the proper registerbank, generating the return instruction at the end, etc.Practically, this means that the contents of the functionmust be written in inline assembler. This is particularlyuseful for interrupt functions, which can have a large (andoften unnecessary) prologue/epilogue. For example, comparethe code generated by these two functions:data unsigned char counter;void simpleInterrupt(void) interrupt 1{    counter++;}void nakedInterrupt(void) interrupt 2 _naked{    _asm      inc     _counter      reti    ;MUST explicitly include ret in _naked function.    _endasm;}For an 8051 target, the generated simpleInterrupt looks like:_simpleIterrupt:    push    acc    push    b    push    dpl    push    dph    push    psw    mov     psw,#0x00    inc     _counter    pop     psw    pop     dph    pop     dpl    pop     b    pop     acc    retiwhereas nakedInterrupt looks like:_nakedInterrupt:    inc    _counter    reti   ; MUST explicitlyinclude ret(i) in _naked function.While there is nothing preventing you from writing C codeinside a _naked function, there are many ways to shoot yourselfin the foot doing this, and is is recommended that you stickto inline assembler. Functions using private banksThe using attribute (which tells the compiler to use a registerbank other than the default bank zero) should only be appliedto interrupt functions (see note 1 below). This will inmost circumstances make the generated ISR code more efficientsince it will not have to save registers on the stack.The using attribute will have no effect on the generatedcode for a non-interrupt function (but may occasionallybe useful anyway([footnote] possible exception: if a function is called ONLYfrom 'interrupt' functions using a particular bank, it canbe declared with the same 'using' attribute as the calling'interrupt' functions. For instance, if you have severalISRs using bank one, and all of them call memcpy(), it mightmake sense to create a specialized version of memcpy() 'using1', since this would prevent the ISR from having to savebank zero to the stack on entry and switch to bank zerobefore calling the function) ).(pending: I don't think this has been done yet)An interrupt function using a non-zero bank will assume thatit can trash that register bank, and will not save it. Sincehigh-priority interrupts can interrupt low-priority oneson the 8051 and friends, this means that if a high-priorityISR using a particular bank occurs while processing a low-priorityISR using the same bank, terrible and bad things can happen.To prevent this, no single register bank should be usedby both a high priority and a low priority ISR. This isprobably most easily done by having all high priority ISRsuse one bank and all low priority ISRs use another. If youhave an ISR which can change priority at runtime, you'reon your own: I suggest using the default bank zero and takingthe small performance hit.It is most efficient if your ISR calls no other functions.If your ISR must call other functions, it is most efficientif those functions use the same bank as the ISR (see note1 below); the next best is if the called functions use bankzero. It is very inefficient to call a function using adifferent, non-zero bank from an ISR.  Absolute AddressingData items can be assigned an absolute address with the at<address> keyword, in addition to a storage class, e.g.:xdata at 0x8000 unsigned char PORTA_8255 ;In the above example the PORTA_8255 will be allocated tothe location 0x8000 of the external ram. Note that thisfeature is provided to give the programmer access to memorymapped devices attached to the controller. The compilerdoes not actually reserve any space for variables declaredin this way (they are implemented with an equate in theassembler). Thus it is left to the programmer to make surethere are no overlaps with other variables that are declaredwithout the absolute address. The assembler listing file(.lst) and the linker output files (.rst) and (.map) area good places to look for such overlaps.Absolute address can be specified for variables in all storageclasses, e.g.:bit at 0x02 bvar;The above example will allocate the variable at offset 0x02in the bit-addressable space. There is no real advantageto assigning absolute addresses to variables in this manner,unless you want strict control over all the variables allocated. Startup CodeThe compiler inserts a call to the C routine _sdcc__external__startup()at the start of the CODE area. This routine is in the runtimelibrary. By default this routine returns 0, if this routinereturns a non-zero value, the static & global variable initializationwill be skipped and the function main will be invoked Otherwise static & global variables will be initialized beforethe function main is invoked. You could add a _sdcc__external__startup()routine to your program to override the default if you needto setup hardware or perform some other critical operationprior to static & global variable initialization. Inline Assembler CodeSDCC allows the use of in-line assembler with a few restrictionas regards labels. All labels defined within inline assemblercode has to be of the form nnnnn$ where nnnn is a numberless than 100 (which implies a limit of utmost 100 inlineassembler labels per function). It is strongly recommendedthat each assembly instruction (including labels) be placedin a separate line (as the example shows). When the --peep-asmcommand line option is used, the inline assembler code willbe passed through the peephole optimizer. This might causesome unexpected changes in the inline assembler code. Pleasego throught the peephole optimizer rules defined in fileSDCCpeeph.def carefully before using this option._asm     mov     b,#1000001$:     djnz    b,00001$_endasm ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -