UNPKG

@nataliapc/mcp-openmsx

Version:

Model context protocol server for openMSX automation and control

788 lines (509 loc) 86.2 kB
# SDCC Compiler User Guide ## Notes on supported Processors ### MCS51 variants range none pageformat default MCS51 variants MCS51 processors are available from many vendors and come in many different flavours. While they might differ considerably in respect to Special Function Registers the core MCS51 is usually not modified or is kept compatible. #### pdata access by SFR With the upcome of devices with internal xdata and flash memory devices using port P2 range none pageformat default P2 (mcs51 sfr) as dedicated I/O port is becoming more popular. Switching the high byte for __pdata range none pageformat default pdata (mcs51, ds390 named address space) access which was formerly done by port P2 is then achieved by a Special Function Register range none pageformat default sfr. In well-established MCS51 tradition the address of this *sfr* is where the chip designers decided to put it. Needless to say that they didn't agree on a common name either. So that the startup code can correctly initialize xdata variables, you should define an sfr with the name _XPAGE range none pageformat default XPAGE (mcs51) at the appropriate location if the default, port P2, is not used for this. Some examples are: ```c __sfr __at (0x85) _XPAGE; /* Ramtron VRS51 family a.k.a. MPAGE */ __sfr __at (0x92) _XPAGE; /* Cypress EZ-USB family, Texas Instruments (Chipcon) a.k.a. MPAGE */ __sfr __at (0x91) _XPAGE; /* Infineon (Siemens) C500 family a.k.a. XPAGE */ __sfr __at (0xaf) _XPAGE; /* some Silicon Labs (Cygnal) chips a.k.a. EMI0CN */ __sfr __at (0xaa) _XPAGE; /* some Silicon Labs (Cygnal) chips a.k.a. EMI0CN */ ``` There are also devices without anything resembling _XPAGE, but luckily they usually have dual data-pointers. For these devices a different method can be used to correctly initialize xdata variables. A default implementation is already in crtxinit.asm but it needs to be assembled manually with DUAL_DPTR set to 1. For more exotic implementations further customizations may be needed. See section MCS51/DS390 Startup Code for other possibilities. #### Other Features available by SFR Some MCS51 variants offer features like Dual DPTR range none pageformat default DPTR, multiple DPTR, decrementing DPTR, 16x16 Multiply. These are currently not used for the MCS51 port. If you absolutely need them you can fall back to inline assembly or submit a patch to SDCC. #### Bankswitching Bankswitching range none pageformat default Bankswitching (a.k.a. code banking range none pageformat default code banking) is a technique to increase the code space above the 64k limit of the 8051. ##### Hardware | 8000-FFFF | bank1 | bank2 | bank3 | | --- | --- | --- | --- | | 0000-7FFF | common | | | | SiLabs C8051F120 example | | | | | SiLabs C8051F120 example | | | | Usually the hardware uses some sfr (an output port or an internal sfr) to select a bank and put it in the banked area of the memory map. The selected bank usually becomes active immediately upon assignment to this sfr and when running inside a bank it will switch out this code it is currently running. Therefor you cannot jump or call directly from one bank to another and need to use a so-called trampoline in the common area. For SDCC an example trampoline is in crtbank.asm and you may need to change it to your 8051 derivative or schematic. The presented code is written for the C8051F120. When calling a banked function SDCC will put the LSB of the functions address in register R0, the MSB in R1 and the bank in R2 and then call this trampoline *__sdcc_banked_call*. The current selected bank is saved on the stack, the new bank is selected and an indirect jump is made. When the banked function returns it jumps to *__sdcc_banked_ret* which restores the previous bank and returns to the caller. ##### Software When writing banked software using SDCC you need to use some special keywords and options. You also need to take over a bit of work from the linker. To create a function that can be called from another bank it requires the keyword *__banked* range none pageformat default banked. The caller must see this in the prototype of the callee and the callee needs it for a proper return. Called functions within the same bank as the caller do not need the *__banked* keyword nor do functions in the common area. Beware: SDCC does not know or check if functions are in the same bank. This is your responsibility! Normally all functions you write end up in the segment CSEG. If you want a function explicitly to reside in the common area put it in segment HOME. This applies for instance to interrupt service routines as they should not be banked. Functions that need to be in a switched bank must be put in a named segment. The name can be mostly anything up to eight characters (e.g. BANK1). To do this you either use --codeseg BANK1 (See Other Options) on the command line when compiling or #pragma codeseg BANK1 (See Pragmas) at the top of the C source file. The segment name always applies to the whole source file and generated object so functions for different banks need to be defined in different source files. When linking your objects you need to tell the linker where to put your segments. To do this you use the following command line option to SDCC:-Wl-b BANK1=0x18000 (See Linker Options). This sets the virtual start address of this segment. It sets the banknumber to 0x01 and maps the bank to 0x8000 and up. The linker will not check for overflows, again this is your responsibility. #### MCS51/DS390 Startup Code The compiler triggers the linker to link certain initialization modules from the runtime library range none pageformat default Runtime library called crt<something>. Only the necessary ones are linked, for instance crtxstack.asm (GSINIT1, GSINIT5) is not linked unless the - -xstack option is used. These modules are highly entangled by the use of special segments/areas, but a common layout is shown below: **(main.asm)** ```asm .area HOME (CODE) __interrupt_vect: ljmp __sdcc_gsinit_startup ``` **(crtstart.asm)** ```asm .area GSINIT0 (CODE) __sdcc_gsinit_startup:: mov sp,#__start__stack - 1 ``` **(crtxstack.asm)** ```asm .area GSINIT1 (CODE) __sdcc_init_xstack:: ; Need to initialize in GSINIT1 in case the user's __sdcc_external_startup uses the xstack. mov __XPAGE,#(__start__xstack >> 8) mov _spx,#__start__xstack ``` **(crtstart.asm)** ```asm .area GSINIT2 (CODE) lcall ___sdcc_external_startup mov a,dpl jz __sdcc_init_data ljmp __sdcc_program_startup __sdcc_init_data: ``` **(crtxinit.asm)** ```asm .area GSINIT3 (CODE) __mcs51_genXINIT:: mov r1,#l_XINIT mov a,r1 orl a,#(l_XINIT >> 8) jz 00003$ mov r2,#((l_XINIT+255) >> 8) mov dptr,#s_XINIT mov r0,#s_XISEG mov __XPAGE,#(s_XISEG >> 8) 00001$: clr a movc a,@a+dptr movx @r0,a inc dptr inc r0 cjne r0,#0,00002$ inc __XPAGE 00002$: djnz r1,00001$ djnz r2,00001$ mov __XPAGE,#0xFF 00003$: ``` **(crtclear.asm)** ```asm .area GSINIT4 (CODE) __mcs51_genRAMCLEAR:: clr a mov r0,#(l_IRAM-1) 00004$: mov @r0,a djnz r0,00004$ ; _mcs51_genRAMCLEAR() end ``` **(crtxclear.asm)** ```asm .area GSINIT4 (CODE) __mcs51_genXRAMCLEAR:: mov r0,#l_PSEG mov a,r0 orl a,#(l_PSEG >> 8) jz 00006$ mov r1,#s_PSEG mov __XPAGE,#(s_PSEG >> 8) clr a 00005$: movx @r1,a inc r1 djnz r0,00005$ 00006$: mov r0,#l_XSEG mov a,r0 orl a,#(l_XSEG >> 8) jz 00008$ mov r1,#((l_XSEG + 255) >> 8) mov dptr,#s_XSEG clr a 00007$: movx @dptr,a inc dptr djnz r0,00007$ djnz r1,00007$ 00008$: ``` **(crtxstack.asm)** ```asm .area GSINIT5 (CODE) ; Need to initialize in GSINIT5 because __mcs51_genXINIT modifies __XPAGE ; and __mcs51_genRAMCLEAR modifies _spx. mov __XPAGE,#(__start__xstack >> 8) mov _spx,#__start__xstack ``` **(application modules)** ```asm .area GSINIT (CODE) ``` **(main.asm)** ```asm .area GSFINAL (CODE) ljmp __sdcc_program_startup ;-------------------------------------------------------- ; Home ;-------------------------------------------------------- .area HOME (CODE) .area CSEG (CODE) __sdcc_program_startup: lcall _main ; return from main will lock up sjmp. ``` On some mcs51 variants __xdata range none pageformat default xdata (mcs51, ds390 named address space memory has to be explicitly enabled before it can be accessed or if the watchdog range none pageformat default watchdog needs to be disabled, this is the place to do it. The startup code clears all internal data memory, 256 bytes by default, but from 0 to n-1 if *--iram-size range none pageformat default --iram-size <Value>* is used. (recommended for Chipcon CC1010). See also the compiler option *--no-xinit*- *opt* range none pageformat default --no-xinit-opt and section MCS51 variants about MCS51-variants. While these initialization modules are meant as generic startup code there might be the need for customization. Let's assume the return value of *__sdcc_external_startup()* in *crtstart.asm* should not be checked (or *__sdcc_external_startup()* should not be called at all). The recommended way would be to copy *crtstart.asm* (f.e. from http://svn.code.sf.net/p/sdcc/code/trunk/sdcc/device/lib/mcs51/crtstart.asm) into the source directory, adapt it there, then assemble it with *sdas8051 -plosgff "-plosgff" are the assembler options used in http://sdcc.svn.sourceforge.net/viewvc/sdcc/trunk/sdcc/device/lib/mcs51/Makefile.in?view=markup crtstart.asm* and when linking your project explicitly specify *crtstart.rel*. As a bonus a listing of the relocated object file *crtstart.rst* is generated. #### Interfacing with Assembler Code range none pageformat default Assembler routines ##### Global Registers used for Parameter Passing range none pageformat default Parameter passing The compiler always uses the global registers *DPL, DPH range none pageformat default DPTR, DPH, DPL range none pageformat default DPTR, B range none pageformat default B (mcs51, ds390 register)* and *ACC range none pageformat default ACC (mcs51, ds390 register)* to pass the first (non-bit, non-struct) parameter to a function, and also to pass the return value range none pageformat default return value of function; according to the following scheme: one byte return value in *DPL*, two byte value in *DPL* (LSB) and *DPH* (MSB). three byte values (generic pointers) in *DPH*, *DPL* and *B*, and four byte values in *DPH*, *DPL*, *B* and *ACC*. Generic pointers range none pageformat default generic pointer contain type of accessed memory in *B*: **0x00** --xdata/far, **0x40** --idata/near --, **0x60** --pdata, **0x80** -- code This might not be the case of certain memory models (medium???). Further such parameters (and all struct parameters, as well as the bit parameters from the 9th onwards) are either allocated on the stack (for reentrant routines or if --stack-auto is used) or in data/xdata memory (depending on the memory model). The first 8 bit parameters are passed in a virtual register called 'bits' in bit-addressable space for reentrant functions or allocated directly in bit memory otherwise. Functions (with two or more parameters or bit parameters) that are called through function pointers range none pageformat default function pointers must therefor be reentrant so the compiler knows how to pass the parameters. ##### Register usage Unless the called function is declared as _naked range none pageformat default naked, or the --callee-saves range none pageformat default --callee-saves /--all-callee-saves command line option or the corresponding callee_saves pragma are used, the caller will save the registers (*R0-R7*) around the call, so the called function can destroy they content freely. If the called function is not declared as _naked, the caller will swap register banks around the call, if caller and callee use different register banks (having them defined by the __using modifier). The called function can also use *DPL*, *DPH*, *B* and *ACC* observing that they are used for parameter/return value passing. ##### Assembler Routine (non-reentrant) In the following example range none pageformat default reentrant range none pageformat default Assembler routines (non-reentrant) the function c_func calls an assembler routine asm_func, which takes two parameters range none pageformat default function parameter. ```c extern int asm_func(unsigned char, unsigned char); int c_func (unsigned char i, unsigned char j) { return asm_func(i,j); } int main() { return c_func(10,9); } ``` The corresponding assembler function is: ```asm .globl _asm_func_PARM_2 .globl _asm_func .area OSEG _asm_func_PARM_2: .ds 1 .area CSEG _asm_func: mov a,dpl add a,_asm_func_PARM_2 mov dpl,a mov dph range none pageformat default DPTR, DPH, DPL,#0x00 ret ``` The parameter naming convention is _<function_name>_PARM_<n>, where n is the parameter number starting from 1, and counting from the left. The first parameter is passed in *DPH*, *DPL*, *B* and *ACC* according to the description above. The variable name for the second parameter will be _<function_name>_PARM_2. Assemble the assembler routine with the following command: **sdas8051 -losg asmfunc.asm ** Then compile and link the assembler routine to the C source file with the following command: **sdcc cfunc.c asmfunc.rel ##### Assembler Routine (reentrant) In this case range none pageformat default reentrant range none pageformat default Assembler routines (reentrant) the second parameter range none pageformat default function parameter onwards will be passed on the stack, the parameters are pushed from right to left i.e. before the call the second leftmost parameter will be on the top of the stack (the leftmost parameter is passed in registers). Here is an example: ```c extern int asm_func(unsigned char, unsigned char, unsigned char) reentrant; int c_func (unsigned char i, unsigned char j, unsigned char k) reentrant { return asm_func(i,j,k); } int main() { return c_func(10,9,8); } ``` The corresponding (unoptimized) assembler routine is: ```asm .globl _asm_func _asm_func: push _bp mov _bp,sp;stack contains: _bp, return address, second parameter, third parameter mov r2,dpl mov a,_bp add a,#0xfd;calculate pointer to the second parameter mov r0,a mov a,_bp add a,#0xfc;calculate pointer to the rightmost parameter mov r1,a mov a,@r0 add a,@r1 add a,r2;calculate the result (= sum of all three parameters) mov dpl,a;return value goes into dptr (cast into int) mov dph,#0x00 mov sp,_bp pop _bp ret ``` The compiling and linking procedure remains the same, however note the extra entry & exit linkage required for the assembler code, _bp is the stack frame pointer and is used to compute the offset into the stack for parameters and local variables. ### DS400 port The DS80C400 range none pageformat default DS80C400 range none pageformat default DS400 microcontroller has a rich set of peripherals. In its built-in ROM library it includes functions to access some of the features, among them is a TCP stack with IP4 and IP6 support. Library headers (currently in beta status) and other files are provided at ftp://ftp.dalsemi.com/pub/tini/ds80c400/c_libraries/sdcc/index.html. ### The Z80, Z180, Rabbit 2000, Rabbit 2000A, Rabbit 3000A, SM83 (GameBoy), eZ80, TLCS-90 and R800 ports SDCC can target the Z80 range none pageformat default Z80, Z180, eZ80 in Z80 mode, Rabbit 2000, Rabbit 2000A, Rabbit 3000A and LR35902, the Sharp SM83 (used.e.g in the Nintendo GameBoy) sm83 range none pageformat default sm83 (GameBoy Z80). When a frame pointer is used, it resides in IX. Register A, B, C, D, E, H, L and IY are used as a temporary registers for holding variables. When enabling optimizations using --opt-code size and a sufficiently high value for --max-allocs-per-node SDCC typically generates much better code for these architectures than many other compilers. A comparison of compilers for these architecture can be found at http://sdcc.sourceforge.net/wiki/index.php/Z80_code_size. #### Startup Code On the Z80 range none pageformat default Z80 the startup code is inserted by linking with crt0.rel which is generated from sdcc/device/lib/z80/crt0.s. If you need a different startup code you can use the compiler option *- -no-std-crt0* range none pageformat default --no-std-crt0 and provide your own crt0.rel. When using a custom crt0.rel it needs to be listed first when linking. #### Rabbit ports SDCC has three Rabbit-supporting ports: r2k for the Rabbit 2000, r2ka for the Rabbit 2000A, 2000B, 2000C and 3000, r3ka for the Rabbit 3000A, 4000 and 6000. Some Rabbits support different memory types (Rabbit 4000 and later), different memory access modes (Rabbit 5000 and later), different instruction modes (Rabbit 4000 and later). All SDCC ports assume 8-bit memories, 8-bit memory access mode, 00/default instruction set mode (the code generated is also compatible with 10 and 01 instruction set mode, but not 11/enhanced instruction set mode). ##### Port choice | Ports vs. Device | R2K | R2KA | R2KB | R2KC | R3K | R3KA | R4K | R5K | R6K | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | r2k | Y | y | y | y | y | y | y | N | N | | r2ka | n | Y | Y | Y | y | y | y | N | N | | r3ka | N | N | N | N | N | Y | Y | N | N | | r3ka | N | N | N | N | N | Y | Y | N | N | Legend: Y - The code this port generates is the best for this CPU. y - The code this port generates will work on this CPU. N - The code this port generates will not work on this CPU. n - The code this port generates will typically not work on this CPU. There are multiple wait state bugs present in some of the the Rabbits. The difference between the r2k and r2ka port is additional wait state bug workarounds. If all memory used has zero wait states, code from the r2ka backend can be safely run on the original Rabbit 2000. The r2k and r2ka port assume that the whole stack has the same number of wait states (code from the r2k and r2ka ports can fail is the stack spans memories with a different amount of wait states). The Rabbit 2000 has some wait state bugs that SDCC does not work around. These bugs result in the number of wait states used being one less than configured for some instructions. The workaround has to be supplied by the user, by configuring all memories that do use wait states to use on additional wait state. For all Rabbit ports, SDCC assumes that all data memory is at least as fast (i.e. does not need more wait states) as all code memory. Code where this is not the case (e.g. code in fast Flash writing into slow battery-backed SRAM) will have to be written in assembler by hand. ##### Rabbit hardware bugs | Bug | R2K | R2KA | R2KB | R2KC | R3K | R3KA | R4K | R5K | R6K | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | ioi / ioe prefix bug | x | | | | | | | | | | ddcb / fdcb wait state bug | U | | | | | | | | | | conditional jump wait state bug | U | | | | | | | | | | ldir / lddr wait state bug | U | | | | | | | | | | mul wait state bug | w | | | | | | | | | | ldir / lddr split bug | | S | | | | | | | | | new ldir / lddr wait state bug | w | w | w | w | w | | | | | | 16-bit mode alignment bug | | | | | | | | X | | | ioi / ioe bit bug | | | | | | | | x | x | | ret cc bug | | | | | | | | X | X | | rmw wait state bug | W | W | W | W | W | W | W | W | | | 16-bit vs. 8-bit wait state bug | | | | | | | W | | | | dma vs stack prot. bug | | | | | | | X | | | | 16-bit dma vs. ldir / lddr / etc. bug | | | | | | | X | | | | cplx bug | | | | | | | | | x | | dma match bug | | | | | | | | | X | | ex jkhl, bcde alt reg bug | | | | | | | | | x | | ldbyte bug | | | | | | | | | x | | puma bug | | | | | | | | | x | | puma bug | | | | | | | | | x | Legend: x s w u - bug present, worked around by SDCC. X S W U - bug present, not worked around by SDCC. w W u U - wait state bug, only relevant when the Rabbit is configured to have wait states for some memory. s S - instruction / data split bug, only relevant when instruction / data split is enabled, which is currently not supported by SDCC. u U - bug can be worked around by the user by configuring memory that needs wait states to use one additional wait state. The 16-bit mode alignment bug only affects 16-bit mode, which is not currently supported by SDCC. The rmw wait state bug is only relevant when executing fast code writing to slow memory, such as code in fast RAM writing to slow battery-backed SRAM. The 16-bit vs. 8-bit wait state bug is only relevant when the target system uses both 16-bit and 8-bit memories for code, and the 8-bit memory requires wait states. The 16-bit dma vs. ldir / lddr / etc. bug is only relevant when using DMA and the target system uses 16-bit memory for code. Since SDCC uses the block move instructions like ldir, lddr, etc. without applying a workaround, this means that code execution and DMA may then not happen at the same time. A possible user workaround is to not use DMA when using 16-bit memory for code. Among all Rabbit 4000-based RCM and BL modules, only the RCM4000 and the RCM4010 use 16-bit memories. The dma match bug is only relevant when a DMA termination mask register is set to a nonzero value. #### Z80, Z180, Z80N and R800 calling conventions The current default is the SDCC calling convention, version 1. Using the command-line option --sdcccall 0, the default can be changed to version 0. There are three other calling conventions supported, which can be specified using the keywords __smallc, __z88dk_fastcall and __z88dk_callee. They are primarily intended for compatibility with libraries written for other compilers. For __z88dk_fastcall, there may be only one parameter of at most 32 bits, which is passed the same way as the return value of __sdcccall(0). For __z88dk_callee, the stack is not adjusted for stack parameters the parameters after the call (thus the callee has to do this instead). __z88dk_callee can be combined with __smallc, __sdcccall(0) or __sdcccall(1). ##### Z80 SDCC calling convention, version 1 This calling convention can be chosen per function via __sdcccall(1). 8-bit return values are passed in a, 16-bit values in de, 24-bit values in lde, 32-bit values in hlde. Larger return values (as well as struct and union independent of their size) are passed in memory in a location specified by the caller through a hidden pointer argument. For functions that have variable arguments: All parameters are passed on the stack. The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead). ![z80-arguments.svg](z80-arguments.svg) For Functions that do not have variable arguments: the first parameter is passed in a if it has 8 bits. If it has 16 bits it is passed in hl. If it has 32 bits, it is passed in hlde. If the first parameter is in a, and the second has 8 bits, it is passed in l; if the first is passed in a or hl, and the second has 16 bits, it is passed in de; all other parameters are passed on the stack, right-to-left. Independent of their size, struct / union parameters and all following parameters are always passed on the stack. ![z80-stack-cleanup.svg](z80-stack-cleanup.svg) If __z88dk_callee is not used, after the call, the stack parameters are cleaned up by the caller, with the following exceptions: functions that do not have variable arguments and return void or a type of at most 16 bits, or have both a first parameter of type float and a return value of type float. ##### Z80 SDCC calling convention, version 0 This calling convention can be chosen per function via __sdcccall(0). All parameters are passed on the stack, right-to-left. 8-bit return values are passed in l, 16-bit values in hl, 24-bit values in ehl, 32-bit values in dehl. Except for the SM83, where 8-bit values are passed in e, 16-bit values in de, 32-bit values in hlde. Larger return values (as well as struct and union independent of their size) are passed in a memory in a location specified by the caller through a hidden pointer argument. Unless __z88dk_callee is used, all stack parameters are cleaned up by the caller. #### Rabbit 2000, Rabbit 2000A, Rabbit 3000A, eZ80 and TLCS-90 calling conventions The current default is the Rabbit calling convetion desribed here, version 1. Using the command-line option --sdcccall 8, the default can be changed to version 0 of the Z80 calling convention, described above. There are four other calling conventions supported, which can be specified using the keywords __smallc, __z88dk_fastcall and __z88dk_callee. They are primarily intended for compatibility with libraries written for other compilers. For __z88dk_fastcall, there may be only one parameter of at most 32 bits, which is passed the same way as the return value. For __z88dk_callee, the stack is not adjusted for stack parameters the parameters after the call (thus the callee has to do this instead). __z88dk_callee can be combined with __smallc, __sdcccall(0) or __sdcccall(1). ##### Rabbit SDCC calling convention, version 1 This calling convention can be chosen per function via __sdcccall(1). 8-bit return values are passed in a, 16-bit values in hl, 24-bit values in lde, 32-bit values in hlde. Larger return values (as well as struct and union independent of their size) are passed in memory in a location specified by the caller through a hidden pointer argument. For functions that have variable arguments: All parameters are passed on the stack. The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead). ![r3ka-arguments.svg](r3ka-arguments.svg) For Functions that do not have variable arguments: the first parameter is passed in a if it has 8 bits. If it has 16 bits it is passed in hl. If it has 32 bits, it is passed in hlde. If the first parameter is in a, and the second has 8 bits, it is passed in l; if the first is in hl or hlde, and the second has 8 bits, it is passed in a; if the first is in a, and the second has 16 bits, it is passed in hl; all other parameters are passed on the stack, right-to-left. Independent of their size, struct / union parameters and all following parameters are always passed on the stack. ![z80-stack-cleanup.svg](z80-stack-cleanup.svg) If __z88dk_callee is not used, after the call, the stack parameters are cleaned up by the caller, with the following exceptions: functions that do not have variable arguments and return void or a type of at most 16 bits, or have both a first parameter of type float and a return value of type float. #### SM83 calling conventions The current default is the SDCC calling convention, version 1. Using the command-line option --sdcccall 0, the default can be changed to version 0. ##### SM83 SDCC calling convention, version 1 This calling convention can be chosen per function via __sdcccall(1). 8-bit return values are passed in a, 16-bit values in bc, 32-bit values in debc. Larger return values (as well as struct and union independent of their size) are passed in memory in a location specified by the caller through a hidden pointer argument. For functions that have variable arguments: All parameters are passed on the stack. The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead). ![sm83-arguments.svg](sm83-arguments.svg) For Functions that do not have variable arguments: the first parameter is passed in a if it has 8 bits. If it has 16 bits it is passed in de. If it has 32 bits, it is passed in debc. If the first parameter is in a, and the second has 8 bits, it is passed in e; if the first is in bc or debc, and the second has 8 bits, it is passed in a; if the first is passed in a, and the second has 16 bits, it is passed in bc; if the first is passed in de, and the second has 16 bits, it is passed in bc; all other parameters are passed on the stack, right-to-left. Independent of their size, struct / union parameters and all following parameters are always passed on the stack. The stack is adjusted by the callee (thus explicitly specifying __z88dk_callee does not make a difference), unless the functionhas variable arguments. ##### SM83 SDCC calling convention, version 0 This calling convention can be chosen per function via __sdcccall(0). 8-bit return values are passed in e, 16-bit values in de, 32-bit values in hlde. Larger return values (as well as struct and union independent of their size) are passed in memory in a location specified by the caller through a hidden pointer argument. All parameters are passed on the stack. The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead), unless __z88dk_callee is specified. __sdcccall(0) can be combined with __z88dk_callee. #### Small-C calling convention Functions declared as __smallc are called using the Small-C calling convention (passing arguments on-stack left-to-right, 1 byte arguments are passed as 2 bytes, with the value in the lower byte). 8-bit return values are passed in a, 16-bit values in de, 32-bit values in hlde. Larger return values (as well as struct and union independent of their size) are passed in memory in a location specified by the caller through a hidden pointer argument. This way assembler routines originally written for Small-C or code generated by Small-C can be called from SDCC. Currently variable arguments are not yet supported (neither on the caller nor on the callee side). #### Complex instructions The Z80 and some derivatives support complex instructions, such as ldir, cpir,.... SDCC only emits these instructions for functions in the standard library. Thus, e.g. copying one array into another is more efficient when using memcpy() than by using a a user-written loop. Depending on the target, code generation options and the parameters to the call, SDCC emits ldir for memcpy(), ldir or lsidr for memset(), ldi for strcpy(), ldi for strncpy(). Other library functions use the complex instructions as well, but for those, function calls are generated. #### Unsafe reads Usually, Z80-based systems (except for the SM83 and TLCS-90) have separate I/O and memory spaces, and any normal memory location can be read without side-effects. For such systems, the option --allow-unsafe-reads can be used to enable some extra optimizations that rely on this. #### Z80 banked calls Banked calls are supported via __banked. Banked calls are done via a trampoline (__sdcc_bcall if --legacy-banking is specified, __sdcc_bcall_abc for z88dk_fastcall, __sdcc_bcall_ehl for other calls). Default trampolines are provided in the library. The default trampolines calls user supplied helper functions set_bank and get_bank that set the current bank to the value in register a, or return the current bank in register a. For banked functions, the calling convention is slightly different: the stack is always cleared up by the caller. Unless __z88dk_fastcall is used, all parameters are passed on the stack. ### The HC08 and S08 ports The port to the Freescale/Motorola HC08 range none pageformat default HC08 and S08 does not yet generate code as compact as that generated by some non-free compilers. A comparison of compilers for these architecture can be found at http://sdcc.sourceforge.net/wiki/index.php/Hc08_code_size. #### Startup Code The HC08 range none pageformat default HC08 startup code follows the same scheme as the MCS51 startup code. ### The STM8 port #### Calling conventions By default, the SDCC calling convention, version 1 is used. Using the option --sdcccall 0, the default can be changed to version 0. Arguments are passed on the stack right-to-left. Return values are in a (8 bit), x (16 bit), xyl (24 bit), xy (32 bit) or use a hidden extra pointer parameter pointing to the location (anything wider than 32 bit, and all struct / union). ##### SDCC calling convention, version 1 ![stm8-arguments.svg](stm8-arguments.svg) For functions that have variable arguments, all parameters are passed on the stack. For other functions, if the first parameter has 8 or 16 bits, it is passed in a or x. If the first parameter is passed in a, and the second has 16 bits, the second is passed in x. If the first parameter is passed in x, and the second has 8 bits, the second is passed in a. All other parameters are passed on the stack. Independent of their size, struct / union parameters and all following parameters are always passed on the stack. If __z88dk_callee is specified, the stack is always adjusted by the callee. Otherwise, for the large memory model, the stack is always adjusted by the caller. For the medium memory model the stack is adjusted by the caller, with the following exceptions: functions that do not have variable arguments and return void or a type of at most 16 bits, or have both a first parameter of type float and a return value of type float. ##### SDCC calling convention, version 0 This calling convention can be chosen per function via __sdcccall(0) (e.g. for compatibility with functions written in assembler for use with older versions of SDCC). All parameters are passed on the stack. The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead), unless __z88dk_callee is specified. ##### Raisonance calling convention For compatibility with the Raisonance STM8 compiler, the __raisonance calling convention is supported. If the first parameter is 8 or 16 bits, it is passed in a or x. If the first parameter is 8 bits, and the second 16 bits, the second is passed in x. If the first parameter is 16 bits, and the second is 8 bits, the second is passed in a. All other parameters are passed on the stack. If the return value is 8 bits, it is passed in a. If it is 16 bits, it is passed in x. Raisonance passes larger return values in pseudoregisters, which is not supported by SDCC. ##### IAR calling convention For compatibility with the IAR STM8 compiler, the __iar calling convention is supported. The first 8-bit parameter is passed in a, the first 16-bit parameter in x, the second 16-bit parameter in y. Further parameters of up to 32 bits are passed in pseudoregisters, which is not supported by SDCC. All other parameters are passed on the stack. If the return value is 8 bits, it is passed in a. If it is 16 bits, it is passed in x. IAR passes larger return values in pseudoregisters, which is not supported by SDCC. ##### Cosmic calling convention For compatibility with the Cosmic STM8 compiler, the __cosmic calling convention is supported. If the first parameter is 8 or 16 bits, it is passed in a or x. If the return value is 8 bits, it is passed in a. If it is 16 bits, it is passed in x. Cosmic passes larger return values in pseudoregisters, which is not supported by SDCC. Even for the medium memory model, __cosmic functions use a 24-bit return address in their stack frame, and are called using callf. ### The f8 port #### Calling convention If the the function does not have variable arguments, and the first argument is not a struct or union and has 8 or 16 bits, it is passed in xl (8 bits) or y (16 bits). All other arguments are passed on the stack right-to-left. Return values are in xl (8 bit), x (16 bit), xxl (24 bit), yx (32 bit) or use a hidden extra pointer parameter pointing to the location (anything wider than 32 bit, and all struct / union). The stack is not adjusted for the parameters by the callee (thus the caller has to do this instead). ### The MOS6502 and WDC65C02 ports The mos6502 range none pageformat default MOS6502 port can target the original MOS Technology NMOS 6502, and the CMOS Rockwell/WDC 65C02 with enhanched instruction set. #### Startup Code On the MOS6502 range none pageformat default MOS6502 the startup code is inserted by linking with crt0.rel which is generated from sdcc/device/lib/mos6502/crt0.s. If you need a different startup code you can use the compiler option *- -no-std-crt0* range none pageformat default --no-std-crt0 and provide your own crt0.rel. When using a custom crt0.rel it needs to be listed first when linking. #### Hooking up interrupts ISR can be written in C using SDCC. However, to hook interrupts is necessary to customize crt0.asm and have the interrupt vectors point to the C functions. #### Reentrancy Due to the very limited stack space, the MOS6502 port by default generates non-reentrant code. Re-entrant functions should be declared using the __reentrant keyword. Alternatively the entire program can be compiled using --stack-auto. On the MOS6502 re-entrant code is, in general, much less efficient. #### Code and Data placement The compiler can pass segment location to the linker. On the MOS6502 the following switches are supported: --code-loc: start address of the code segment --data-loc: start address of the zero page --xram-loc: start address of the data segment ### The PIC14 range none pageformat default PIC14 port The PIC14 port adds support for Microchip range none pageformat default Microchip $^{\text{TM}}$ PIC range none pageformat default PIC14 $^{\text{TM}}$ MCUs with 14 bit wide instructions. This port is not yet mature and still lacks many features. However, it can work for simple code. Currently supported devices include: 10F320, 10F322, 10LF320, 10LF322 12F609, 12F615, 12F617, 12F629, 12F635, 12F675, 12F683 12F752 12HV752 16C62, 16C63A, 16C65B 16C71, 16C72, 16C73B, 16C74B 16C432, 16C433 16C554, 16C557, 16C558 16C620, 16C620A, 16C621, 16C621A, 16C622, 16C622A 16C710, 16C711, 16C715, 16C717, 16C745, 16C765, 16C770, 16C771, 16C773, 16C774, 16C781, 16C782 16C925, 16C926 16CR73, 16CR74, 16CR76, 16CR77 16CR620A 16F72,16F73, 16F74, 16F76, 16F77 16F84, 16F84A, 16F87, 16F88 16F610, 16F616, 16F627, 16F627A, 16F628, 16F628A, 16F630, 16F631, 16F636, 16F639, 16F648A 16F676, 16F677, 16F684, 16F685, 16F687, 16F688, 16F689, 16F690 16F707, 16F716, 16F720, 16F721, 16F722, 16F722A, 16F723, 16F723A, 16F724, 16F726, 16F727 16F737, 16F747, 16F753, 16F767, 16F777, 16F785 16F818, 16F819, 16F870, 16F871, 16F872, 16F873, 16F873A, 16F874, 16F874A, 16F876, 16F876A 16F877, 16F877A, 16F882, 16F883, 16F884, 16F886, 16F887 16F913, 16F914, 16F916, 16F917, 16F946 16LF74, 16LF76, 16LF77 16LF84, 16LF84A, 16LF87, 16LF88 16LF627, 16LF627A, 16LF628, 16LF628A, 16LF648A 16LF707, 16LF720, 16LF721, 16LF722, 16LF722A, 16LF723, 16LF723A, 16LF724, 16LF726, 16LF727 16LF747, 16LF767, 16LF777 16LF818, 16LF819, 16LF870, 16LF871, 16LF872, 16LF873, 16LF873A, 16LF874, 16LF874A 16LF876, 16LF876A, 16LF877, 16LF877A 16HV610, 16HV616, 16HV753, 16HV785 Supported devices with enhanced cores: 12F1501, 12F1571, 12F1572, 12F1612, 12F1822, 12F1840 12LF1501, 12LF1552, 12LF1571, 12LF1572, 12LF1612, 12LF1822, 12LF1840, 12LF1840T39A, 12LF1840T48A 16F1454, 16F1455, 16F1458, 16F1459 16F1503, 16F1507, 16F1508, 16F1509, 16F1512, 16F1513, 16F1516, 16F1517, 16F1518, 16F1519 16F1526, 16F1527, 16F1574, 16F1575, 16F1578, 16F1579 16F1613, 16F1614, 16F1615, 16F1618, 16F1619 16F1703, 16F1704, 16F1705, 16F1707, 16F1708, 16F1709, 16F1713, 16F1716, 16F1717, 16F1718, 16F1719 16F1764, 16F1765, 16F1768, 16F1769, 16F1773, 16F1776, 16F1777, 16F1778, 16F1779 16F1782, 16F1783, 16F1784, 16F1786, 16F1787, 16F1788, 16F1789 16F1823, 16F1824, 16F1825, 16F1826, 16F1827, 16F1828, 16F1829, 16F1829LIN, 16F1847 16F1933, 16F1934, 16F1936, 16F1937, 16F1938, 16F1939, 16F1946, 16F1947 16F18313, 16F18323, 16F18324, 16F18325, 16F18344, 16F18345, 16F18855, 16F18875 16LF1454, 16LF1455, 16LF1458, 16LF1459 16LF1503, 16LF1507, 16LF1508, 16LF1509, 16LF1512, 16LF1513, 16LF1516, 16LF1517, 16LF1518, 16LF1519, 16LF1526, 16LF1527 16LF1554, 16LF1559, 16LF1566, 16LF1567, 16LF1574, 16LF1575, 16LF1578, 16LF1579 16LF1613, 16LF1614, 16LF1615, 16LF1618, 16LF1619 16LF1703, 16LF1704, 16LF1705, 16LF1707, 16LF1708, 16LF1709, 16LF1713, 16LF1716, 16LF1717, 16LF1718, 16LF1719 16LF1764, 16LF1765, 16LF1768, 16LF1769, 16LF1773, 16LF1776, 16LF1777, 16LF1778, 16LF1779 16LF1782, 16LF1783, 16LF1784, 16LF1786, 16LF1787, 16LF1788, 16LF1789, 16LF1823, 16LF1824, 16LF1824T39A 16LF1825, 16LF1826, 16LF1827, 16LF1828, 16LF1829, 16LF1847 16LF1902, 16LF1903, 16LF1904, 16LF1906, 16LF1907 16LF1933, 16LF1934, 16LF1936, 16LF1937, 16LF1938, 16LF1939, 16LF1946, 16LF1947 16LF18313, 16LF18323, 16LF18324, 16LF18325, 16LF18344, 16LF18345 16LF18855, 16LF18875 An up-to-date list of currently supported devices can be obtained via sdcc -mpic14 -phelp foo.c (foo.c must exist...). #### PIC Code Pages range none pageformat default code page (pic14) and Memory Banks range none pageformat default Memory bank (pic14) The linker organizes allocation for the code page and RAM banks. It does not have intimate knowledge of the code flow. It will put all the code section of a single.asm file into a single code page. In order to make use of multiple code pages, separate asm files must be used. The compiler assigns all *static* functions of a single.c file into the same code page. To get the best results, follow these guidelines: 1. Make local functions static, as non static functions require code page selection overhead. Due to the way SDCC handles functions, place called functions prior to calling functions in the file wherever possible: Otherwise SDCC will insert unnecessary pagesel directives around the call, believing that the called function is externally defined. 2. For devices that have multiple code pages it is more efficient to use the same number of files as pages: Use up to 4 separate.c files for the 16F877, but only 2 files for the 16F874. This way the linker can put the code for each file into different code pages and there will be less page selection overhead. 3. And as for any 8 bit micro (especially for PIC14 as they have a very simple instruction set), use `unsigned char' wherever possible instead of `int'. #### Adding New Devices to the Port Adding support for a new 14 bit PIC MCU requires the following steps: 1. Create a new device description. Each device is described in two files: pic16f*.h and pic16f*.c. These files primarily define SFRs, structs to access their bits, and symbolic configuration options. Both files can be generated from gputils'.inc files using the perl script support/scripts/inc2h.pl. This file also contains further instructions on how to proceed. 2. Copy the.h file into SDCC's include path and either add the.c file to your project or copy it to device/lib/pic/libdev. Afterwards, rebuild and install the libraries. 3. Edit pic14devices.txt in SDCC's include path (device/include/pic/ in the source tree or /usr/local/share/sdcc/include/pic after installation). You need to add a device specification here to make the memory layout (code banks, RAM, aliased memory regions,...) known to the compiler. Probably you can copy and modify an existing entry. The file format is documented at the top of the file. #### Interrupt Code For the interrupt function, use the keyword *__interrupt* range none pageformat default PIC14!interrupt with level number of 0 (PIC14 only has 1 interrupt so this number is only there to avoid a syntax error - it ought to be fixed). E.g.: ```c void Intr(void) __interrupt (0) { T0IF = 0; /* Clear timer interrupt */ } ``` #### Configuration Bits Configuration bits (also known as fuses) can be configured using ` __code ' and ` __at ' modifiers. Possible options should be ANDed and can be found in your processor header file. Example for PIC16F88: ```c #include <pic16f88.h> //Contains config addresses and options #include <stdint.h> //Needed for uint16_t static __code uint16_t __at (_CONFIG1) configword1 = _INTRC_IO & _CP_ALL & _WDT_OFF & [...]; static __code uint16_t __at (_CONFIG2) configword2 = [...]; ``` Although data type is ignored if the address (__at()) refers to a config word location, using a type large enough for the configuration word (uint16_t in this case) is recommended to prevent changes in the compiler (implicit, early range check and enforcement) from breaking the definition. If your processor header file doesn't contain config addresses you can declare it manually or use a literal address: ```c static __code uint16_t __at (0x2007) configword1 = _INTRC_IO & _CP_ALL & _WDT_OFF & [...]; ``` #### Linking and Assembling For assembling you can use either GPUTILS' range none pageformat default gputils (pic tools) gpasm.exe or MPLAB's mpasmwin.exe. GPUTILS are available from http://sourceforge.net/projects/gputils. For linking you can use either GPUTILS' gplink or MPLAB's mplink.exe. If you use MPLAB and an interrupt function then the linker script file vectors section will need to be enlarged to link with mplink. Pic device specific header and c source files are automatically generated from MPLAB include files, which are published by Microchip with a special requirement that they are only to be used with authentic Microchip devices. This reqirement prevents to publish generated header and c source files under the GPL compatible license, so they are located in non-free directory (see section Search Paths). In order to include them in include and library search paths, the **--use-non-free range none pageformat default --use-non-free** command line option should be defined. NOTE: the compiled code, which use non-free pic device specific libraries, is not GPL compatible! Here is a Makefile using GPUTILS: .c.o: sdcc -V --use-non-free -mpic14 -p16f877 -c $< $(PRJ).hex: $(OBJS) gplink -m -s $(PRJ).lkr -o $(PRJ).hex $(OBJS) libsdcc.lib Here is a Makefile using MPLAB: .c.o: sdcc -S -V --use-non-free -mpic14 -p16f877 $< mpasmwin /q /o $*.asm $(PRJ).hex: $(OBJS) mplink /v $(PRJ).lkr /m $(PRJ).map /o $(PRJ).hex $(OBJS) libsdcc.lib Please note that indentations within a Makefile have to be done with a tabulator character. #### Command-Line Options Besides the switches common to all SDCC backends, the PIC14 port accepts the following options (for an updated list see sdcc --help): --debug-xtra range none pageformat default PIC14!Options!--debug-extra emit debug info in assembly output --no-pcode-opt range none pageformat default PIC14!Options!--no-pcode-opt disable (slightly faulty) optimization on pCode --stack-loc range none pageformat default PIC14!Options!--stack-loc sets the lowest address of the argument passing stack (defaults to a suitably large shared databank to reduce BANKSEL overhead) --stack-size range none pageformat default PIC14!Options!--stack-size sets the size if the argument passing stack (default: 16, minimum: 4) --use-non-free range none pageformat default PIC14!Options!--use-non-free make non-free device headers and libraries available in the compiler's search paths (implicit -I and -L options) --no-extended-instructions forbid use of the extended instruction set (e.g., ADDFSR) #### Environment Variables The PIC14 port recognizes the following environment variables: SDCC_PIC14_SPLIT_LOCALS range none pageformat default PIC14!Environment variables!SDCC PIC14 SPLIT LOCALS range none pageformat default SDCC!Environment variables!SDCC PIC14 SPLIT LOCALS If set and not empty, sdcc will allocate each temporary register (the ones called r0xNNNN) in a section of its own. By default (if this variable is unset), sdcc tries to cluster registers in sections in order to reduce the BANKSEL overhead when accessing them. #### The Library The PIC14 library currently only contains support routines required by the compiler to implement multiplication, division, and floating point support. No libc-like replacement is available at the moment, though many of the common sdcc library sources (in device/lib) should also compile with the PIC14 port. ##### Enhanced cores SDCC/PIC14 has experimental support for devices with the enhanced 14-bit cores (such as pic12f1822). Due to differences in required code, the libraries provided with SDCC (libm.lib and libsdcc.lib) are now provided in two variants: libm.lib and libsdcc.lib are compiled for the regular, non-enhanced devices. libme.lib and libsdcce.lib (note the trailing ' e ') are compiled for enhanced devices. When linking manually, make sure to select the proper variant! When SDCC is used to invoke the linker, SDCC will automatically select the libsdcc.lib-variant suitable for the target device. However, no such magic has been conjured up for libm.lib! ##### Accessing bits of special function registers Individual bits within SFRs can be accessed either using or using a shorthand, which is defined in the respective device header for all s. In order to avoid polluting the global namespace with the names of all the bits, you can #define NO_BIT_DEFINES before inclusion of the device header file. ##### Naming of special function registers If NO_BIT_DEFINES is used, individual bits of the SFRs can be accessed as. With the 3.1.0 release, the previously used (note the underscore) is deprecated. This was done to align the naming conventions with the PIC16 port and competing compiler vendors. To avoid polluting the global namespace with the legacy names, you can prevent their definition using #define NO_LEGACY_NAMES prior to the inclusion of the device header. You **must** also #define NO_BIT_DEFINES in order to access SFRs as, otherwise will expand to, yielding the undefined expression. ##### error: missing definition for symbol ``__gptrget1'' The PIC14 port uses library routines to provide more complex operations like multiplication, division/modulus and (generic) pointer dereferencing. In order to add these routines to your project, you must link with PIC14's libsdcc.lib. For single source file projects this is done automatically, more complex projects must add libsdcc.lib to the linker's arguments. Make sure you also add an include path for the library (using the -I switch to the linker)! ##### Processor mismatch in file ``XXX''. This warnin