/****************************************************************************** FILE : datapage.c PURPOSE : paged data access runtime routines MACHINE : Freescale 68HC12 (Target) LANGUAGE : ANSI-C HISTORY : 21.7.96 first version created ******************************************************************************/ #include "hidef.h" #include "non_bank.sgm" #include "runtime.sgm" /*lint --e{957} , MISRA 8.1 REQ, these are runtime support functions and, as such, are not meant to be called in user code; they are only invoked via jumps, in compiler-generated code */ /*lint -estring(553, __OPTION_ACTIVE__) , MISRA 19.11 REQ , __OPTION_ACTIVE__ is a built-in compiler construct to check for active compiler options */ #ifndef __HCS12X__ /* it's different for the HCS12X. See the text below at the #else // __HCS12X__ */ /* According to the -Cp option of the compiler the __DPAGE__, __PPAGE__ and __EPAGE__ macros are defined. If none of them is given as argument, then no page accesses should occur and this runtime routine should not be used ! To be on the save side, the runtime routines are created anyway. */ /* Compile with option -DHCS12 to activate this code */ #if defined(HCS12) || defined(_HCS12) || defined(__HCS12__) #ifndef PPAGE_ADDR #ifdef __PPAGE_ADR__ #define PPAGE_ADDR __PPAGE_ADR__ #else #define PPAGE_ADDR (0x30 + REGISTER_BASE) #endif #endif #ifndef __PPAGE__ /* may be set already by option -CPPPAGE */ #define __PPAGE__ #endif /* Compile with option -DDG128 to activate this code */ #elif defined DG128 /* HC912DG128 derivative has PPAGE register only at 0xFF */ #ifndef PPAGE_ADDR #define PPAGE_ADDR (0xFF+REGISTER_BASE) #endif #ifndef __PPAGE__ /* may be set already by option -CPPPAGE */ #define __PPAGE__ #endif #elif defined(HC812A4) /* all setting default to A4 already */ #endif #if !defined(__EPAGE__) && !defined(__PPAGE__) && !defined(__DPAGE__) /* as default use all page registers */ #define __DPAGE__ #define __EPAGE__ #define __PPAGE__ #endif /* modify the following defines to your memory configuration */ #define EPAGE_LOW_BOUND 0x400u #define EPAGE_HIGH_BOUND 0x7ffu #define DPAGE_LOW_BOUND 0x7000u #define DPAGE_HIGH_BOUND 0x7fffu #define PPAGE_LOW_BOUND (DPAGE_HIGH_BOUND+1u) #define PPAGE_HIGH_BOUND 0xBFFFu #ifndef REGISTER_BASE #define REGISTER_BASE 0x0u #endif #ifndef DPAGE_ADDR #define DPAGE_ADDR (0x34u+REGISTER_BASE) #endif #ifndef EPAGE_ADDR #define EPAGE_ADDR (0x36u+REGISTER_BASE) #endif #ifndef PPAGE_ADDR #define PPAGE_ADDR (0x35u+REGISTER_BASE) #endif /* The following parts about the defines are assumed in the code of _GET_PAGE_REG : - the memory region controlled by DPAGE is above the area controlled by the EPAGE and below the area controlled by the PPAGE. - the lower bound of the PPAGE area is equal to be the higher bound of the DPAGE area + 1 */ #if (EPAGE_LOW_BOUND >= EPAGE_HIGH_BOUND) || (EPAGE_HIGH_BOUND >= DPAGE_LOW_BOUND) || (DPAGE_LOW_BOUND >= DPAGE_HIGH_BOUND) || (DPAGE_HIGH_BOUND >= PPAGE_LOW_BOUND) || (PPAGE_LOW_BOUND >= PPAGE_HIGH_BOUND) #error /* please adapt _GET_PAGE_REG for this non default page configuration */ #endif #if (DPAGE_HIGH_BOUND+1u) != PPAGE_LOW_BOUND #error /* please adapt _GET_PAGE_REG for this non default page configuration */ #endif /* this module does either control if any access is in the bounds of the specified page or */ /* ,if only one page is specified, just use this page. */ /* This behavior is controlled by the define USE_SEVERAL_PAGES. */ /* If !USE_SEVERAL_PAGES does increase the performance significantly */ /* NOTE : When !USE_SEVERAL_PAGES, the page is also set for accesses outside of the area controlled */ /* by this single page. But this is should not cause problems because the page is restored to the old value before any other access could occur */ #if !defined(__DPAGE__) && !defined(__EPAGE__) && !defined(__PPAGE__) /* no page at all is specified */ /* only specifying the right pages will speed up these functions a lot */ #define USE_SEVERAL_PAGES 1 #elif (defined(__DPAGE__) && defined(__EPAGE__)) || (defined(__DPAGE__) && defined(__PPAGE__)) || (defined(__EPAGE__) && defined(__PPAGE__)) /* more than one page register is used */ #define USE_SEVERAL_PAGES 1 #else #define USE_SEVERAL_PAGES 0 #if defined(__DPAGE__) /* check which pages are used */ #define PAGE_ADDR PPAGE_ADDR #elif defined(__EPAGE__) #define PAGE_ADDR EPAGE_ADDR #elif defined(__PPAGE__) #define PAGE_ADDR PPAGE_ADDR #else /* we do not know which page, decide it at runtime */ #error /* must not happen */ #endif #endif #if USE_SEVERAL_PAGES /* only needed for several pages support */ /*--------------------------- _GET_PAGE_REG -------------------------------- Runtime routine to detect the right register depending on the 16 bit offset part of an address. This function is only used by the functions below. Depending on the compiler options -Cp different versions of _GET_PAGE_REG are produced. Arguments : - Y : offset part of an address Result : if address Y is controlled by a page register : - X : address of page register if Y is controlled by an page register - Zero flag cleared - all other registers remain unchanged if address Y is not controlled by a page register : - Zero flag is set - all registers remain unchanged --------------------------- _GET_PAGE_REG ----------------------------------*/ #if defined(__DPAGE__) #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */ asm { L_DPAGE: CPY #DPAGE_LOW_BOUND ;/* test of lower bound of DPAGE */ #if defined(__EPAGE__) BLO L_EPAGE ;/* EPAGE accesses are possible */ #else BLO L_NOPAGE ;/* no paged memory below accesses */ #endif CPY #DPAGE_HIGH_BOUND ;/* test of higher bound DPAGE/lower bound PPAGE */ #if defined(__PPAGE__) BHI L_PPAGE ;/* EPAGE accesses are possible */ #else BHI L_NOPAGE ;/* no paged memory above accesses */ #endif FOUND_DPAGE: LDX #DPAGE_ADDR ;/* load page register address and clear zero flag */ RTS #if defined(__PPAGE__) L_PPAGE: CPY #PPAGE_HIGH_BOUND ;/* test of higher bound of PPAGE */ BHI L_NOPAGE FOUND_PPAGE: LDX #PPAGE_ADDR ;/* load page register address and clear zero flag */ RTS #endif #if defined(__EPAGE__) L_EPAGE: CPY #EPAGE_LOW_BOUND ;/* test of lower bound of EPAGE */ BLO L_NOPAGE CPY #EPAGE_HIGH_BOUND ;/* test of higher bound of EPAGE */ BHI L_NOPAGE FOUND_EPAGE: LDX #EPAGE_ADDR ;/* load page register address and clear zero flag */ RTS #endif L_NOPAGE: ORCC #0x04 ;/* sets zero flag */ RTS } } #else /* !defined(__DPAGE__) */ #if defined( __PPAGE__ ) #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */ asm { L_PPAGE: CPY #PPAGE_LOW_BOUND ;/* test of lower bound of PPAGE */ #if defined( __EPAGE__ ) BLO L_EPAGE #else BLO L_NOPAGE ;/* no paged memory below */ #endif CPY #PPAGE_HIGH_BOUND ;/* test of higher bound PPAGE */ BHI L_NOPAGE FOUND_PPAGE: LDX #PPAGE_ADDR ;/* load page register address and clear zero flag */ RTS #if defined( __EPAGE__ ) L_EPAGE: CPY #EPAGE_LOW_BOUND ;/* test of lower bound of EPAGE */ BLO L_NOPAGE CPY #EPAGE_HIGH_BOUND ;/* test of higher bound of EPAGE */ BHI L_NOPAGE FOUND_EPAGE: LDX #EPAGE_ADDR ;/* load page register address and clear zero flag */ RTS #endif L_NOPAGE: ;/* not in any allowed page area */ ;/* its a far access to a non paged variable */ ORCC #0x04 ;/* sets zero flag */ RTS } } #else /* !defined(__DPAGE__ ) && !defined( __PPAGE__) */ #if defined(__EPAGE__) #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */ asm { L_EPAGE: CPY #EPAGE_LOW_BOUND ;/* test of lower bound of EPAGE */ BLO L_NOPAGE CPY #EPAGE_HIGH_BOUND ;/* test of higher bound of EPAGE */ BHI L_NOPAGE FOUND_EPAGE: LDX #EPAGE_ADDR ;/* load page register address and clear zero flag */ RTS L_NOPAGE: ;/* not in any allowed page area */ ;/* its a far access to a non paged variable */ ORCC #0x04 ;/* sets zero flag */ RTS } } #endif /* defined(__EPAGE__) */ #endif /* defined(__PPAGE__) */ #endif /* defined(__DPAGE__) */ #endif /* USE_SEVERAL_PAGES */ /*--------------------------- _SET_PAGE -------------------------------- Runtime routine to set the right page register. This routine is used if the compiler does not know the right page register, i.e. if the option -Cp is used for more than one page register or if the runtime option is used for one of the -Cp options. Arguments : - offset part of an address in the Y register - page part of an address in the B register Result : - page part written into the correct page register. - the old page register content is destroyed - all processor registers remains unchanged --------------------------- _SET_PAGE ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _SET_PAGE(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE STAB 0,X ;/* set page register */ L_NOPAGE: PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { STAB PAGE_ADDR ;/* set page register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _LOAD_FAR_8 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register Result : - value to be read in the B register - all other registers remains unchanged - all page register still contain the same value --------------------------- _LOAD_FAR_8 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _LOAD_FAR_8(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHA ;/* save A register */ LDAA 0,X ;/* save page register */ STAB 0,X ;/* set page register */ LDAB 0,Y ;/* actual load, overwrites page */ STAA 0,X ;/* restore page register */ PULA ;/* restore A register */ PULX ;/* restore X register */ RTS L_NOPAGE: LDAB 0,Y ;/* actual load, overwrites page */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHA ;/* save A register */ LDAA PAGE_ADDR ;/* save page register */ STAB PAGE_ADDR ;/* set page register */ LDAB 0,Y ;/* actual load, overwrites page */ STAA PAGE_ADDR ;/* restore page register */ PULA ;/* restore A register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _LOAD_FAR_16 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register Result : - value to be read in the Y register - all other registers remains unchanged - all page register still contain the same value --------------------------- _LOAD_FAR_16 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _LOAD_FAR_16(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHA ;/* save A register */ LDAA 0,X ;/* save page register */ STAB 0,X ;/* set page register */ LDY 0,Y ;/* actual load, overwrites address */ STAA 0,X ;/* restore page register */ PULA ;/* restore A register */ PULX ;/* restore X register */ RTS L_NOPAGE: LDY 0,Y ;/* actual load, overwrites address */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHA ;/* save A register */ LDAA PAGE_ADDR ;/* save page register */ STAB PAGE_ADDR ;/* set page register */ LDY 0,Y ;/* actual load, overwrites address */ STAA PAGE_ADDR ;/* restore page register */ PULA ;/* restore A register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _LOAD_FAR_24 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register Result : - value to be read in the Y:B registers - all other registers remains unchanged - all page register still contain the same value --------------------------- _LOAD_FAR_24 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _LOAD_FAR_24(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHA ;/* save A register */ LDAA 0,X ;/* save page register */ STAB 0,X ;/* set page register */ LDAB 0,Y ;/* actual load, overwrites page of address */ LDY 1,Y ;/* actual load, overwrites offset of address */ STAA 0,X ;/* restore page register */ PULA ;/* restore A register */ PULX ;/* restore X register */ RTS L_NOPAGE: LDAB 0,Y ;/* actual load, overwrites page of address */ LDY 1,Y ;/* actual load, overwrites offset of address */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHA ;/* save A register */ LDAA PAGE_ADDR ;/* save page register */ STAB PAGE_ADDR ;/* set page register */ LDAB 0,Y ;/* actual load, overwrites page of address */ LDY 1,Y ;/* actual load, overwrites offset of address */ STAA PAGE_ADDR ;/* restore page register */ PULA ;/* restore A register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _LOAD_FAR_32 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register Result : - low 16 bit of value to be read in the D registers - high 16 bit of value to be read in the Y registers - all other registers remains unchanged - all page register still contain the same value --------------------------- _LOAD_FAR_32 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _LOAD_FAR_32(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE LDAA 0,X ;/* save page register */ PSHA ;/* put it onto the stack */ STAB 0,X ;/* set page register */ LDD 2,Y ;/* actual load, low word */ LDY 0,Y ;/* actual load, high word */ MOVB 1,SP+,0,X ;/* restore page register */ PULX ;/* restore X register */ RTS L_NOPAGE: LDD 2,Y ;/* actual load, low word */ LDY 0,Y ;/* actual load, high word */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { LDAA PAGE_ADDR ;/* save page register */ PSHA ;/* put it onto the stack */ STAB PAGE_ADDR ;/* set page register */ LDD 2,Y ;/* actual load, low word */ LDY 0,Y ;/* actual load, high word */ MOVB 1,SP+,PAGE_ADDR ;/* restore page register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _STORE_FAR_8 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register - value to be stored in the B register Result : - value stored at the address - all registers remains unchanged - all page register still contain the same value --------------------------- _STORE_FAR_8 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _STORE_FAR_8(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHB ;/* save B register */ LDAB 0,X ;/* save page register */ MOVB 0,SP, 0,X ;/* set page register */ STAA 0,Y ;/* store the value passed in A */ STAB 0,X ;/* restore page register */ PULB ;/* restore B register */ PULX ;/* restore X register */ RTS L_NOPAGE: STAA 0,Y ;/* store the value passed in A */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHB ;/* save A register */ LDAB PAGE_ADDR ;/* save page register */ MOVB 0,SP,PAGE_ADDR ;/* set page register */ STAA 0,Y ;/* store the value passed in A */ STAB PAGE_ADDR ;/* restore page register */ PULB ;/* restore B register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _STORE_FAR_16 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register - value to be stored in the X register Result : - value stored at the address - all registers remains unchanged - all page register still contain the same value --------------------------- _STORE_FAR_16 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _STORE_FAR_16(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHA LDAA 0,X ;/* save page register */ STAB 0,X ;/* set page register */ MOVW 1,SP,0,Y ;/* store the value passed in X */ STAA 0,X ;/* restore page register */ PULA ;/* restore A register */ PULX ;/* restore X register */ RTS L_NOPAGE: STX 0,Y ;/* store the value passed in X */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHA ;/* save A register */ LDAA PAGE_ADDR ;/* save page register */ STAB PAGE_ADDR ;/* set page register */ STX 0,Y ;/* store the value passed in X */ STAA PAGE_ADDR ;/* restore page register */ PULA ;/* restore A register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _STORE_FAR_24 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address in the B register - value to be stored in the X:A registers (X : low 16 bit, A : high 8 bit) Result : - value stored at the address - all registers remains unchanged - all page register still contain the same value --------------------------- _STORE_FAR_24 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _STORE_FAR_24(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHA LDAA 0,X ;/* save page register */ STAB 0,X ;/* set page register */ MOVW 1,SP, 1,Y ;/* store the value passed in X */ MOVB 0,SP, 0,Y ;/* store the value passed in A */ STAA 0,X ;/* restore page register */ PULA ;/* restore A register */ PULX ;/* restore X register */ RTS L_NOPAGE: STX 1,Y ;/* store the value passed in X */ STAA 0,Y ;/* store the value passed in X */ PULX ;/* restore X register */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHA ;/* save A register */ LDAA PAGE_ADDR ;/* save page register */ STAB PAGE_ADDR ;/* set page register */ MOVB 0,SP, 0,Y ;/* store the value passed in A */ STX 1,Y ;/* store the value passed in X */ STAA PAGE_ADDR ;/* restore page register */ PULA ;/* restore A register */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _STORE_FAR_32 -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of an address in the Y register - page part of an address is on the stack at 3,SP (just below the return address) - value to be stored in the X:D registers (D : low 16 bit, X : high 16 bit) Result : - value stored at the address - all registers remains unchanged - the page part is removed from the stack - all page register still contain the same value --------------------------- _STORE_FAR_32 ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _STORE_FAR_32(void) { #if USE_SEVERAL_PAGES asm { PSHX ;/* save X register */ __PIC_JSR(_GET_PAGE_REG) BEQ L_NOPAGE PSHD LDAA 0,X ;/* save page register */ MOVB 6,SP, 0,X ;/* set page register */ MOVW 2,SP, 0,Y ;/* store the value passed in X (high word) */ MOVW 0,SP, 2,Y ;/* store the value passed in D (low word) */ STAA 0,X ;/* restore page register */ PULD ;/* restore A register */ BRA done L_NOPAGE: MOVW 0,SP, 0,Y ;/* store the value passed in X (high word) */ STD 2,Y ;/* store the value passed in D (low word) */ done: PULX ;/* restore X register */ MOVW 0,SP, 1,+SP ;/* move return address */ RTS } #else /* USE_SEVERAL_PAGES */ asm { PSHD ;/* save D register */ LDAA PAGE_ADDR ;/* save page register */ LDAB 4,SP ;/* load page part of address */ STAB PAGE_ADDR ;/* set page register */ STX 0,Y ;/* store the value passed in X */ MOVW 0,SP, 2,Y ;/* store the value passed in D (low word) */ STAA PAGE_ADDR ;/* restore page register */ PULD ;/* restore D register */ MOVW 0,SP, 1,+SP ;/* move return address */ RTS } #endif /* USE_SEVERAL_PAGES */ } /*--------------------------- _FAR_COPY_RC -------------------------------- This runtime routine is used to access paged memory via a runtime function. It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments : - offset part of the source int the X register - page part of the source in the A register - offset part of the dest int the Y register - page part of the dest in the B register - number of bytes to be copied is defined by the next 2 bytes after the return address. Result : - memory area copied - no registers are saved, i.e. all registers may be destroyed - all page register still contain the same value as before the call - the function returns after the constant defining the number of bytes to be copied stack-structure at the loop-label: 0,SP : destination offset 2,SP : source page 3,SP : destination page 4,SP : source offset 6,SP : points to length to be copied. This function returns after the size A usual call to this function looks like: struct Huge src, dest; ; ... LDX #src LDAA #PAGE(src) LDY #dest LDAB #PAGE(dest) JSR _FAR_COPY_RC DC.W sizeof(struct Huge) ; ... --------------------------- _FAR_COPY_RC ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_RC(void) { #if USE_SEVERAL_PAGES asm { DEX ;/* source addr-=1, because loop counter ends at 1 */ PSHX ;/* save source offset */ PSHD ;/* save both pages */ DEY ;/* destination addr-=1, because loop counter ends at 1 */ PSHY ;/* save destination offset */ LDY 6,SP ;/* Load Return address */ LDX 2,Y+ ;/* Load Size to copy */ STY 6,SP ;/* Store adjusted return address */ loop: LDD 4,SP ;/* load source offset */ LEAY D,X ;/* calculate actual source address */ LDAB 2,SP ;/* load source page */ __PIC_JSR(_LOAD_FAR_8) ;/* load 1 source byte */ PSHB ;/* save value */ LDD 0+1,SP ;/* load destination offset */ LEAY D,X ;/* calculate actual destination address */ PULA ;/* restore value */ LDAB 3,SP ;/* load destination page */ __PIC_JSR(_STORE_FAR_8) ;/* store one byte */ DEX BNE loop LEAS 6,SP ;/* release stack */ _SRET ;/* debug info only: This is the last instr of a function with a special return */ RTS ;/* return */ } #else asm { PSHD ;/* store page registers */ TFR X,D PSHY ;/* temporary space */ LDY 4,SP ;/* load return address */ ADDD 2,Y+ ;/* calculate source end address. Increment return address */ STY 4,SP PULY PSHD ;/* store src end address */ LDAB 2,SP ;/* reload source page */ LDAA PAGE_ADDR ;/* save page register */ PSHA loop: STAB PAGE_ADDR ;/* set source page */ LDAA 1,X+ ;/* load value */ MOVB 4,SP, PAGE_ADDR ;/* set destination page */ STAA 1,Y+ CPX 1,SP BNE loop LDAA 5,SP+ ;/* restore old page value and release stack */ STAA PAGE_ADDR ;/* store it into page register */ _SRET ;/* debug info only: This is the last instr of a function with a special return */ RTS } #endif } /*--------------------------- _FAR_COPY -------------------------------- The _FAR_COPY runtime routine was used to copied large memory blocks in previous compiler releases. However this release now does use _FAR_COPY_RC instead. The only difference is how the size of the area to be copied is passed into the function. For _FAR_COPY the size is passed on the stack just above the return address. _FAR_COPY_RC does expect the return address just after the JSR _FAR_COPY_RC call in the code of the caller. This allows for denser code calling _FAR_COPY_RC but does also need a slightly larger runtime routine and it is slightly slower. The _FAR_COPY routine is here now mainly for compatibility with previous releases. The current compiler does not use it. --------------------------- _FAR_COPY ----------------------------------*/ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY(void) { #if USE_SEVERAL_PAGES asm { DEX ;/* source addr-=1, because loop counter ends at 1 */ PSHX ;/* save source offset */ PSHD ;/* save both pages */ DEY ;/* destination addr-=1, because loop counter ends at 1 */ PSHY ;/* save destination offset */ LDX 8,SP ;/* load counter, assuming counter > 0 */ loop: LDD 4,SP ;/* load source offset */ LEAY D,X ;/* calculate actual source address */ LDAB 2,SP ;/* load source page */ __PIC_JSR(_LOAD_FAR_8) ;/* load 1 source byte */ PSHB ;/* save value */ LDD 0+1,SP ;/* load destination offset */ LEAY D,X ;/* calculate actual destination address */ PULA ;/* restore value */ LDAB 3,SP ;/* load destination page */ __PIC_JSR(_STORE_FAR_8) ;/* store one byte */ DEX BNE loop LDX 6,SP ;/* load return address */ LEAS 10,SP ;/* release stack */ JMP 0,X ;/* return */ } #else asm { PSHD ;/* store page registers */ TFR X,D ADDD 4,SP ;/* calculate source end address */ STD 4,SP PULB ;/* reload source page */ LDAA PAGE_ADDR ;/* save page register */ PSHA loop: STAB PAGE_ADDR ;/* set source page */ LDAA 1,X+ ;/* load value */ MOVB 1,SP, PAGE_ADDR ;/* set destination page */ STAA 1,Y+ CPX 4,SP BNE loop LDAA 2,SP+ ;/* restore old page value and release stack */ STAA PAGE_ADDR ;/* store it into page register */ LDX 4,SP+ ;/* release stack and load return address */ JMP 0,X ;/* return */ } #endif } #else /* __HCS12X__ */ /* The HCS12X knows two different kind of addresses: - Logical addresses. E.g. MOVB #page(var),RPAGE INC var - Global addresses E.g. MOVB #page(var),GPAGE GLDAA var INCA GSTAA var Global addresses are used with G-Load's and G-Store's, logical addresses are used for all the other instructions and occasions. As HC12's or HCS12's do not have the G-Load and G-Store instructions, global addresses are not used with these processor families. They are only used with HCS12X chips (and maybe future ones deriving from a HCS12X). Logical and Global addresses can point to the same object, however the global and logical address of an object are different for most objects (actually for all except the registers from 0 to 0x7FF). Therefore the compiler needs to transform in between them. HCS12X Pointer types: The following are logical addresses: - all 16 bit pointers - "char* __near": always. - "char *" in the small and banked memory model - 24 bit dpage, epage, ppage or rpage pointers (*1) (note: the first HCS12X compilers may not support these pointer types) - "char *__dpage": Note this type only exists for orthogonality with the HC12 A4 chip which has a DPAGE reg. It does not apply to the HCS12X. - "char *__epage": 24 bit pointer using the EPAGE register - "char *__ppage": 24 bit pointer using the PPAGE register. As the PPAGE is also used for BANKED code, using this pointer type is only legal from non banked code. - "char *__rpage": 24 bit pointer using the RPAGE register The following are global addresses: "char*": in the large memory model (only HCS12X) "char* __far": always for HCS12X. (*1): For the HC12 and HCS12 "char* __far" and "char*" in the large memory model are also logical. Some notes for the HC12/HCS12 programmers. The address of a far object for a HC12 and for a HCS12X is different, even if they are at the same place in the memory map. For the HC12, a far address is using the logical addresses, for the HCS12X however, far addresses are using global addresses. This does cause troubles for the unaware! The conversion routines implemented in this file support the special HCS12XE RAM mapping (when RAMHM is set). To enable this mapping compile this file with the "-MapRAM" compiler option. HCS12X Logical Memory map Logical Addresses Used for shadowed at page register Global Address 0x000000 .. 0x0007FF Peripheral Registers Not Paged 0x000000 0x??0800 .. 0x??0BFF Paged EEPROM EPAGE (@0x17) 0x100000+EPAGE*0x0400 0x000C00 .. 0x000FFF Non Paged EEPROM 0xFF0800..0xFF0FFF Not Paged 0x13FC00 0x??1000 .. 0x??1FFF Paged RAM RPAGE (@0x16) 0x000000+RPAGE*0x1000 0x002000 .. 0x003FFF Non Paged RAM 0xFE1000..0xFF1FFF Not Paged 0x0FE000 0x004000 .. 0x007FFF Non Paged FLASH 0xFC8000..0xFCBFFF Not Paged 0x7F4000 0x??8000 .. 0x00BFFF Paged FLASH PPAGE (@0x30) 0x400000+PPAGE*0x4000 0x00C000 .. 0x00FFFF Non Paged FLASH 0xFF8000..0xFFBFFF Not Paged 0x7FC000 NA: Not Applicable HCS12X Global Memory map Global Addresses Used for Logical mapped at 0x000000 .. 0x0007FF Peripheral Registers 0x000000 .. 0x0007FF 0x000800 .. 0x000FFF DMA registers Not mapped 0x001000 .. 0x0FFFFF RAM 0x??1000 .. 0x??1FFF 0x0FE000 .. 0x0FFFFF RAM, Log non paged 0x002000 .. 0x003FFF 0x100000 .. 0x13FFFF EEPROM 0x??0800 .. 0x??0BFF 0x13FC00 .. 0x13FFFF EEPROM non paged 0x000C00 .. 0x000FFF 0x140000 .. 0x3FFFFF External Space Not mapped 0x400000 .. 0x7FFFFF FLASH 0x??8000 .. 0x??BFFF 0x7F4000 .. 0x7F7FFF FLASH, Log non paged 0x004000 .. 0x007FFF 0x7FC000 .. 0x7FFFFF FLASH, Log non paged 0x00C000 .. 0x00FFFF HCS12XE Logical Memory map (with RAMHM set) Logical Addresses Used for shadowed at page register Global Address 0x000000 .. 0x0007FF Peripheral Registers Not Paged 0x000000 0x??0800 .. 0x??0BFF Paged EEPROM EPAGE 0x100000+EPAGE*0x0400 0x000C00 .. 0x000FFF Non Paged EEPROM 0xFF0800..0xFF0FFF Not Paged 0x13FC00 0x??1000 .. 0x??1FFF Paged RAM RPAGE 0x000000+RPAGE*0x1000 0x002000 .. 0x003FFF Non Paged RAM 0xFA1000..0xFB1FFF Not Paged 0x0FA000 0x004000 .. 0x007FFF Non Paged RAM 0xFC1000..0xFF1FFF Not Paged 0x0FC000 0x??8000 .. 0x00BFFF Paged FLASH PPAGE 0x400000+PPAGE*0x4000 0x00C000 .. 0x00FFFF Non Paged FLASH 0xFF8000..0xFFBFFF Not Paged 0x7FC000 NA: Not Applicable HCS12X Global Memory map (with RAMHM set) Global Addresses Used for Logical mapped at 0x000000 .. 0x0007FF Peripheral Registers 0x000000 .. 0x0007FF 0x000800 .. 0x000FFF DMA registers Not mapped 0x001000 .. 0x0FFFFF RAM 0x??1000 .. 0x??1FFF 0x0FA000 .. 0x0FFFFF RAM, Log non paged 0x002000 .. 0x007FFF 0x100000 .. 0x13FFFF EEPROM 0x??0800 .. 0x??0BFF 0x13FC00 .. 0x13FFFF EEPROM non paged 0x000C00 .. 0x000FFF 0x140000 .. 0x3FFFFF External Space Not mapped 0x400000 .. 0x7FFFFF FLASH 0x??8000 .. 0x??BFFF 0x7F4000 .. 0x7F7FFF FLASH, Log non paged Not mapped 0x7FC000 .. 0x7FFFFF FLASH, Log non paged 0x00C000 .. 0x00FFFF How to read this table: For logical addresses, the lower 16 bits of the address do determine in which area the address is, if this address is paged, then this entry also controls and which of the EPAGE, PPAGE or RPAGE page register is controlling the bits 16 to 23 of the address. For global addresses, the bits 16 to 23 have to be in the GPAGE register and the lower 16 bits have to be used with the special G load or store instructions (e.g. GLDAA). As example the logical address 0x123456 is invalid. Because its lower bits 0x3456 are in a non paged area, so the page 0x12 does not exist. The address 0xFE1020 however does exist. To access it, the RPAGE has to contain 0xFE and the offset 0x1020 has to be used. ORG $7000 MOVB #0xFE, 0x16 ; RPAGE LDAA 0x1020 ; reads at the logical address 0xFE1020 Because the last two RAM pages are also accessible directly from 0x2000 to 0x3FFF, the following shorter code does read the same memory location: ORG $7000 LDAA 0x2020 ; reads at the logical address 0x2020 ; which maps to the same memory as 0xFE1020 This memory location also has a global address. For logical 0xFE1020 the global address is 0x0FE020. So the following code does once more access the same memory location: ORG $7000 MOVB #0x0F, 0x10 ; GPAGE GLDAA 0xE020 ; reads at the global address 0x0FE020 ; which maps to the same memory as the logical addr. 0xFE1020 Therefore every memory location for the HCS12X has up to 3 different addresses. Up to two logical and one global. Notes. - Not every address has a logical equivalent. The external space is only available in the global address space. - The PPAGE must only be set if the code is outside of the 0x8000 to 0xBFFF range. If not, the next code fetch will be from the new wrong PPAGE value. - Inside of the paged area, the highest pages are allocated first. So all HCS12X's do have the FF pages (if they have this memory type at all). - For RPAGE, the value 0 is illegal. Otherwise the global addresses would overlap with the registers. */ /*lint -e10, -e106, -e30 */ #if __OPTION_ACTIVE__("-MapRAM") #define __HCS12XE_RAMHM_SET__ #endif /*lint +e10, +e106, +e30 */ /*--------------------------- pointer conversion operations -------------------------------*/ /*--------------------------- _CONV_GLOBAL_TO_LOGICAL -------------------------------- Convert 24 bit logical to 24 bit global pointer ("char*__far" to "char*__gpage") Arguments : - B : page part of global address - X : 16 offset part of global address Postcondition : - B == page of returned logical address - X == offset of returned logical address - Y remains unchanged - A remains unchanged */ /*--------------------------- Convert 24 bit global to 24 bit logical pointer ----------------------------------*/ /* B:X = Logical(B:X) */ #ifdef __cplusplus extern "C" #endif #pragma NO_FRAME #pragma NO_ENTRY #pragma NO_EXIT void NEAR _CONV_GLOBAL_TO_LOGICAL(void) { asm { CMPB #0x40 ;/* flash (0x400000..0x7FFFFF) or not? */ BLO Below400000 /* from 0x400000 to 0x7FFFFF */ CMPB #0x7F ;/* check for Unpaged areas 0x7FC000..0x7FFFFF and 0x7F4000..0x7F7FFF */ BNE PAGED_FLASH_AREA #ifndef __HCS12XE_RAMHM_SET__ BITX #0x4000 BEQ PAGED_FLASH_AREA #else CPX #0xC000 BLO PAGED_FLASH_AREA #endif /* from 0x7F4000 to 0x7F7FFF or 0x7FC000 to 0x7FFFFF */ ;/* Note: offset in X is already OK. */ CLRB ;/* logical page == 0 */ RTS PAGED_FLASH_AREA: ;/* paged flash. Map to 0x8000..0xBFFF */ /* from 0x400000 to 0x7F3FFF or 0x7F8000 to 0x7FBFFF */ LSLX ; /* shift 24 bit address 2 bits to the left to get correct page in B */ ROLB LSLX ROLB LSRX ; /* shift back to get offset from 0x8000 to 0xBFFF */ SEC RORX RTS ;/* done */ Below400000: /* from 0x000000 to 0x3FFFFF */ #if 0 /* How should we handle mapping to External Space. There is no logical equivalent. This is an error case! */ CMPB #0x14 ;/* check if above 0x140000. If so, its in the external space */ BLO Below140000 ERROR !!!! ;/* this mapping is not possible! What should we do? */ RTS Below140000: /* from 0x000000 to 0x13FFFF */ #endif CMPB #0x10 ;/* if >= 0x100000 it's EEPROM */ BLO Below100000 /* from 0x100000 to 0x13FFFF (or 0x3FFFFF) */ CMPB #0x13 ;/* check if its is in the non paged EEPROM area at 0x13FC00..0x13FFFF */ BLO Below13FC00 CPX #0xFC00 BLO Below13FC00 /* from 0x13FC00 to 0x13FFFF (or 0x3FFFFF) */ LEAX 0x1000,X ;/* same as SUBX #0xF000 // map from 0xFC00 to 0x0C00 */ CLRB RTS Below13FC00: /* from 0x100000 to 0x13FBFF */ PSHA TFR XH,A ;/* calculate logical page */ EXG A,B LSRD LSRD PULA ANDX #0x03FF LEAX 0x0800,X ;/* same as ORX #0x0800 */ RTS Below100000: /* from 0x000000 to 0x0FFFFF */ TSTB BNE RAM_AREA CPX #0x1000 BLO Below001000 RAM_AREA: /* from 0x001000 to 0x0FFFFF */ CMPB #0x0F BNE PagedRAM_AREA #ifndef __HCS12XE_RAMHM_SET__ CPX #0xE000 BLO PagedRAM_AREA /* from 0x0FE000 to 0x0FFFFF */ SUBX #(0xE000-0x2000) ;/* map 0xE000 to 0x2000 */ #else CPX #0xA000 BLO PagedRAM_AREA /* from 0x0FA000 to 0x0FFFFF */ SUBX #(0xA000-0x2000) ;/* map 0xA000 to 0x2000 */ #endif CLRB ;/* Page is 0 */ RTS PagedRAM_AREA: /* from 0x001000 to 0x0FDFFF */ PSHA TFR XH, A ;/* calculate logical page */ EXG A,B LSRD LSRD LSRD LSRD PULA ANDX #0x0FFF LEAX 0x1000,X ;/* same as ORX #0x1000 */ RTS Below001000: /* from 0x000000 to 0x000FFF */ #if 0 CMPA #0x08 BLO Below000800 /* from 0x000800 to 0x000FFF */ /* ??? DMA Regs? */ RTS Below000800: /* from 0x000000 to 0x0007FF */ #endif CLRB RTS } } /*--------------------------- _CONV_GLOBAL_TO_NEAR -------------------------------- Convert 24 bit global to 16 bit logical pointer ("char*__far" to "char*") Arguments : - B : page part of global address - X : 16 offset part of global address Postcondition : - B is undefined - A remains unchanged - X == offset of returned logical address - Y remains unchanged */ /*--------------------------- Convert 24 bit global to 16 bit logical pointer ----------------------------------*/ /* X = Logical(B:X) */ #ifdef __cplusplus extern "C" #endif #define _REUSE_CONV_GLOBAL_TO_LOGICAL 1 #pragma NO_FRAME #pragma NO_ENTRY #pragma NO_EXIT void NEAR _CONV_GLOBAL_TO_NEAR(void){ #if _REUSE_CONV_GLOBAL_TO_LOGICAL /* do we want an optimized version? */ __asm JMP _CONV_GLOBAL_TO_LOGICAL; /* offset for NEAR is same as for LOGICAL. */ #else asm { CMPB #0x40 ;/* flash (0x400000..0x7FFFFF) or not? */ BLO Below400000 /* from 0x400000 to 0x7FFFFF */ #ifndef __HCS12XE_RAMHM_SET__ CMPB #0x7F ;/* check for Unpaged areas 0x7FC000..0x7FFFFF and 0x7F4000..0x7F7FFF */ BNE PAGED_FLASH_AREA CPX #0x4000 BLO PAGED_FLASH_AREA /* from 0x7F4000 to 0x7FFFFF */ #else CMPB #0x7F ;/* check for Unpaged area 0x7FC000..0x7FFFFF */ BNE PAGED_FLASH_AREA CPX #0xC000 BLO PAGED_FLASH_AREA /* from 0x7FC000 to 0x7FFFFF */ #endif ;/* note non PAGED flash areas or paged area 0x7F8000..0x7FBFFF which are mapping all correctly */ RTS PAGED_FLASH_AREA: ;/* paged flash. Map to 0x8000..0xBFFF */ /* from 0x400000 to 0x7F3FFF */ ANDX #0x3F00 ;/* cut to 0.. 0x3FFF */ LEAX 0x8000,X ;/* same as ORX #0x8000 ;// move to 0x8000..0xBFFF */ RTS ;/* done */ Below400000: /* from 0x000000 to 0x3FFFFF */ #if 0 /* How should we handle mapping to External Space. There is no logical equivalent. This is an error case! */ CMPB #0x14 ;/* check if above 0x140000. If so, its in the external space */ BLO Below140000 ERROR !!!! ;/* this mapping is not possible! What should we do? */ RTS Below140000: /* from 0x000000 to 0x13FFFF */ #endif CMPB #0x10 ;/* if >= 0x100000 it's EEPROM */ BLO Below100000 /* from 0x100000 to 0x13FFFF (or 0x3FFFFF) */ CMPB #0x13 ;/* check if its is in the non paged EEPROM area at 0x13FC00..0x13FFFF */ BNE Below13FC00 CPX #0xFC00 BLO Below13FC00 /* from 0x13FC00 to 0x13FFFF (or 0x3FFFFF) */ SUBX #0xF000 ;/* map from 0xFC00 to 0x0C00 */ RTS Below13FC00: /* from 0x100000 to 0x13FBFF */ ANDX #0x03FF LEAX 0x800,X ;/* same as ORX #0x0800 */ RTS Below100000: /* from 0x000000 to 0x0FFFFF */ TBNE B,RAM_AREA CPX #0x1000 BLO Below001000 RAM_AREA: /* from 0x001000 to 0x0FFFFF */ CMPB #0x0F BNE PagedRAM_AREA #ifndef __HCS12XE_RAMHM_SET__ CPX #0xE000 BLO PagedRAM_AREA /* from 0x0FE000 to 0x0FFFFF */ SUBX #(0xE000-0x2000) ;/* map 0xE000 to 0x2000 */ #else CPX #0xA000 BLO PagedRAM_AREA /* from 0x0FA000 to 0x0FFFFF */ SUBX #(0xA000-0x2000) ;/* map 0xA000 to 0x2000 */ #endif RTS PagedRAM_AREA: /* from 0x001000 to 0x0FDFFF (0x001000 to 0x0F9FFF if HCS12XE RAM mapping is enabled) */ ANDX #0x0FFF LEAX 0x1000,X ;/* same as ORX #0x1000 */ RTS Below001000: /* from 0x000000 to 0x000FFF */ RTS } #endif } /*--------------------------- _CONV_NEAR_TO_GLOBAL -------------------------------- Convert 16 bit logical to 24 bit global pointer ("char*__near" to "char*__far") Arguments : - X : 16 bit near pointer Postcondition : - B == page of returned global address - X == offset of returned global address - Y remains unchanged - A is unspecified */ /*--------------------------- Convert 16 bit logical to 24 bit global pointer ----------------------------------*/ /* B:X = Global(X) */ #ifdef __cplusplus extern "C" #endif #pragma NO_FRAME #pragma NO_ENTRY #pragma NO_EXIT void NEAR _CONV_NEAR_TO_GLOBAL(void){ asm { /* syntax: */ /* input 16 bit offset is bit15..bit0 */ /* ppage values: ppage7..ppage0 */ /* epage values: epage7..epage0 */ /* dpage values: dpage7..dpage0 */ /* rpage values: rpage7..rpage0 */ PSHX ;/* D contains bit15..bit0 */ TFR X,D ;/* D is cheaper to shift */ LSLD ;/* D contains 0 bit14..bit0, C contains bit15 */ BCC Below8000 ;/* bit15 == 0? */ /* from 0x8000 to 0xFFFF */ LSLD ;/* D contains 00 bit13..bit0, C contains bit14 */ BCC BelowC000 LDAB #0x7F PULX RTS ;/* returns 0b0111 1111 11 bit13...bit0 */ BelowC000: ;/* from 0x8000 to 0xBFFF */ TFR D,X LDAB __PPAGE_ADR__ SEC RORB RORX LSRB RORX LEAS 2,SP RTS ;/* returns 0b01 ppage7..ppage0 bit13...bit0 */ Below8000: LSLD ;/* D contains 00 bit13..bit0, C contains bit14 */ BCC Below4000 /* from 0x4000 to 0x7FFF */ PULX #ifndef __HCS12XE_RAMHM_SET__ LDAB #0x7F #else LEAX (0xC000-0x4000),X LDAB #0x0F #endif RTS ;/* returns 0b0111 1111 01 bit13...bit0 */ Below4000: LSLD ;/* D contains 000 bit12..bit0, C contains bit13 */ BCC Below2000 /* from 0x2000 to 0x3FFF */ PULX #ifndef __HCS12XE_RAMHM_SET__ LEAX (0xE000-0x2000),X #else LEAX (0xA000-0x2000),X #endif LDAB #0x0F RTS ;/* returns 0b0000 1111 111 bit12...bit0 */ Below2000: LSLD ;/* D contains 0000 bit11..bit0, C contains bit12 */ BCC Below1000 /* from 0x1000 to 0x1FFF */ LDAB __RPAGE_ADR__ LDAA #0x10 MUL EORB 0,SP EORB #0x10 ;/* clear 1 bit */ STAB 0,SP TFR A,B PULX RTS Below1000: LSLD ;/* D contains 0000 0 bit10..bit0, C contains bit11 */ BCC Below0800 /* from 0x0800 to 0x0FFF */ LSLD ;/* D contains 0000 00 bit9..bit0, C contains bit10 */ BCC Below0C00 /* from 0x0C00 to 0x0FFF */ LDAB #0x13 PULX LEAX 0xF000,X RTS ;/* returns 0b0001 0011 1111 11 bit9...bit0 */ Below0C00: /* from 0x0800 to 0x0BFF */ LDAB __EPAGE_ADR__ LDAA #0x04 MUL EORB 0,SP EORB #0x08 STAB 0,SP TFR A,B ORAB #0b00010000 PULX RTS Below0800: PULX CLRB RTS } } /*--------------------------- _CONV_STACK_NEAR_TO_GLOBAL -------------------------------- Convert 16 bit logical of address on the stack 24 bit global pointer ("char*__near" to "char*__far") Arguments : - X : 16 bit near pointer Postcondition : - B == page of returned global address - X == offset of returned global address - Y remains unchanged - A is unspecified */ /*--------------------------- Convert 16 bit logical stack address to 24 bit global pointer ----------------------------------*/ /* B:X = Global(D) */ #ifdef __cplusplus extern "C" #endif #pragma NO_FRAME #pragma NO_ENTRY #pragma NO_EXIT void NEAR _CONV_STACK_NEAR_TO_GLOBAL(void){ asm { /* syntax: */ /* input 16 bit offset is bit15..bit0 */ /* ppage values: ppage7..ppage0 */ /* epage values: epage7..epage0 */ /* dpage values: dpage7..dpage0 */ /* rpage values: rpage7..rpage0 */ /* stack must be between $1000 and $3FFF. */ /* actually placing the stack at $1000 implies that the RPAGE register is not set (and correctly initialized) */ CPX #0x2000 BLO PAGED_RAM /* Map 0x2000 to 0x0FE000 (0x0FA000 for HCS12XE RAM mapping is enabled) */ LDAB #0x0F #ifndef __HCS12XE_RAMHM_SET__ LEAX (0xE000-0x2000),X ;/* LEAX is one cycle faster than ADDX # */ #else LEAX (0xA000-0x2000),X ;/* LEAX is one cycle faster than ADDX # */ #endif RTS PAGED_RAM: PSHX LDAB __RPAGE_ADR__ LDAA #0x20 MUL EORB 0,SP EORB #0x10 ;/* clear 1 bit */ STAB 0,SP TFR A,B PULX RTS } } /*--------------------------- _CONV_LOGICAL_TO_GLOBAL -------------------------------- Convert 24 bit global to 24 bit logical pointer ("char*__far" to "char*__gpage") Arguments : - B : page part of logical address - X : 16 offset part of logical address Postcondition : - B == page of returned global address - X == offset of returned global address - Y remains unchanged - A remains unchanged */ /*--------------------------- Convert 24 bit logical to 24 bit global pointer ----------------------------------*/ /* B:X = Logical(B:X) */ #ifdef __cplusplus extern "C" #endif #pragma NO_FRAME #pragma NO_ENTRY #pragma NO_EXIT void NEAR _CONV_LOGICAL_TO_GLOBAL(void) { asm { /* syntax: */ /* input 16 bit offset is bit15..bit0 */ /* ppage values: ppage7..ppage0 */ /* epage values: epage7..epage0 */ /* dpage values: dpage7..dpage0 */ /* rpage values: rpage7..rpage0 */ PSHA ;/* save A across this routine. */ PSHX ;/* D contains bit15..bit0 */ PSHB ;/* store page */ TFR X,D ;/* D is cheaper to shift */ LSLD ;/* D contains 0 bit14..bit0, C contains bit15 */ BCC Below8000 ;/* bit15 == 0? */ /* from 0x8000 to 0xFFFF */ LSLD ;/* D contains 00 bit13..bit0, C contains bit14 */ BCC BelowC000 PULB ;/* cleanup stack */ LDAB #0x7F PULX PULA RTS ;/* returns 0b0111 1111 11 bit13...bit0 */ BelowC000: ;/* from 0x8000 to 0xBFFF */ TFR D,X PULB ;/* cleanup stack */ SEC RORB RORX LSRB RORX LEAS 2,SP PULA RTS ;/* returns 0b01 ppage7..ppage0 bit13...bit0 */ Below8000: LSLD ;/* D contains 00 bit13..bit0, C contains bit14 */ BCC Below4000 ;/* from 0x4000 to 0x7FFF */ PULB ;/* cleanup stack */ PULX #ifndef __HCS12XE_RAMHM_SET__ LDAB #0x7F #else LEAX (0xC000-0x4000),X LDAB #0x0F #endif PULA RTS ;/* returns 0b0111 1111 01 bit13...bit0 */ Below4000: LSLD ;/* D contains 000 bit12..bit0, C contains bit13 */ BCC Below2000 /* from 0x2000 to 0x3FFF */ PULB ;/* cleanup stack */ PULX #ifndef __HCS12XE_RAMHM_SET__ LEAX (0xE000-0x2000),X #else LEAX (0xA000-0x2000),X #endif LDAB #0x0F PULA RTS ;/* returns 0b0000 1111 111 bit12...bit0 */ Below2000: LSLD ;/* D contains 0000 bit11..bit0, C contains bit12 */ BCC Below1000 /* from 0x1000 to 0x1FFF */ PULB LDAA #0x10 MUL EORB 0,SP EORB #0x10 ;/* clear 1 bit */ STAB 0,SP TFR A,B PULX PULA RTS Below1000: LSLD ;/* D contains 0000 0 bit10..bit0, C contains bit11 */ BCC Below0800 /* from 0x0800 to 0x0FFF */ LSLD ;/* D contains 0000 00 bit9..bit0, C contains bit10 */ BCC Below0C00 /* from 0x0C00 to 0x0FFF */ PULB ;/* cleanup stack */ LDAB #0x13 PULX LEAX 0xF000,X PULA RTS ;/* returns 0b0001 0011 1111 11 bit9...bit0 */ Below0C00: /* from 0x0800 to 0x0BFF */ PULB LDAA #0x04 MUL EORB 0,SP EORB #0x08 STAB 0,SP TFR A,B ORAB #0b00010000 PULX PULA RTS Below0800: PULB PULX PULA CLRB RTS } } /*--------------------------- _FAR_COPY_RC HCS12X Routines -------------------------------- copy larger far memory blocks There are the following memory block copy routines: _COPY : 16 bit logical copies. Src and dest are both near. Note: implemented in rtshc12.c and not here. _FAR_COPY_RC HC12/HCS12 struct copy routine. Expects HC12/HCS12 logical 24 bit address. Note: Does not exist for the HCS12X. The HC12/HCS12 implementation is implemented above. _FAR_COPY_GLOBAL_GLOBAL_RC: _FAR_COPY_GLOBAL_LOGICAL_RC: _FAR_COPY_LOGICAL_GLOBAL_RC: _FAR_COPY_LOGICAL_LOGICAL_RC: _FAR_COPY_NEAR_GLOBAL_RC: _FAR_COPY_NEAR_LOGICAL_RC: _FAR_COPY_GLOBAL_NEAR_RC: _FAR_COPY_LOGICAL_NEAR_RC: HCS12X specific far copy routine. The name describes what the src/dest address format are. All near src arguments are passed in X, all 24 bit src in X/B. All near dest arguments are passed in Y, all 24 bit src in Y/A. (Note: HC12 _FAR_COPY_RC is using X/A as src and Y/B as dest, so the register usage is not the same!) Arguments : - B:X : src address (for NEAR/_COPY: only X) - A:Y : dest address (for NEAR/_COPY: only Y) - number of bytes to be copied behind return address (for _COPY: in D register). The number of bytes is always > 0 Result : - memory area copied - no registers are saved, i.e. all registers may be destroyed - for _COPY: D contains 0. - for HCS12X _FAR_COPY_... routines: GPAGE state is unknown */ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_GLOBAL_GLOBAL_RC(void) { asm { PSHD PSHY LDY 4,SP ;/* load return address */ LDD 2,Y+ ;/* load size */ STY 4,SP ;/* store return address */ PULY PSHD LDAB 3,SP Loop: STAB __GPAGE_ADR__ GLDAA 1,X+ MOVB 2,SP,__GPAGE_ADR__ GSTAA 1,Y+ DECW 0,SP BNE Loop LEAS 4,SP _SRET ;/* debug info only: This is the last instr of a function with a special return */ RTS } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _SET_PAGE_REG_HCS12X(void) { /* Sets the page contained in A to the register controlling the logical addr contained in X. */ /* saves the old page before and returns it in A together with the page address just below the return address. */ /* X/Y both remain valid. */ asm { PSHX /* 0000..FFFF */ CPX #0x8000 BLO _LO8000 LDX #__PPAGE_ADR__ BRA Handle _LO8000: /* 0000..7FFF */ CPX #0x1000 BLO _LO1000 LDX #__RPAGE_ADR__ BRA Handle _LO1000: LDX #__EPAGE_ADR__ Handle: LDAA 0,X ;/* load old page register content */ STAB 0,X ;/* set new page register */ STX 4,SP PULX RTS } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_GLOBAL_LOGICAL_RC(void) { asm { STAB __GPAGE_ADR__ EXG X,Y TFR A,B PSHY ;/* space to store size */ PSHX ;/* allocate some space where _SET_PAGE_REG_HCS12X can return the page */ LDY 4,SP ;/* load return address */ LDX 2,Y+ ;/* load size */ STY 4,SP LDY 2,SP ;/* restore dest pointer */ STX 2,SP ;/* store size */ LDX 0,SP ;/* reload src pointer */ __PIC_JSR(_SET_PAGE_REG_HCS12X) Loop: GLDAB 1,Y+ STAB 1,X+ DECW 2,SP BNE Loop PULX ;/* reload page register address */ STAA 0,X ;/* restore old page content (necessary if it was PPAGE) */ PULX ;/* clean up stack */ _SRET ;/* debug info only: This is the last instr of a function with a special return */ RTS } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_LOGICAL_GLOBAL_RC(void) { asm { STAA __GPAGE_ADR__ PSHY ;/* space to store size */ PSHX ;/* allocate some space where _SET_PAGE_REG_HCS12X can return the page */ LDY 4,SP ;/* load return address */ LDX 2,Y+ ;/* load size */ STY 4,SP LDY 2,SP ;/* restore dest pointer */ STX 2,SP ;/* store size */ LDX 0,SP ;/* reload src pointer */ __PIC_JSR(_SET_PAGE_REG_HCS12X) Loop: LDAB 1,X+ GSTAB 1,Y+ DECW 2,SP BNE Loop PULX STAA 0,X ;/* restore old page content (necessary if it was PPAGE) */ PULX ;/* clean up stack */ _SRET ;/* debug info only: This is the last instr of a function with a special return */ RTS } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_LOGICAL_LOGICAL_RC(void) { asm { PSHA __PIC_JSR(_CONV_LOGICAL_TO_GLOBAL); PULA __PIC_JMP(_FAR_COPY_GLOBAL_LOGICAL_RC); } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_NEAR_GLOBAL_RC(void) { asm { CLRB __PIC_JMP(_FAR_COPY_LOGICAL_GLOBAL_RC); } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_NEAR_LOGICAL_RC(void) { asm { PSHA __PIC_JSR(_CONV_NEAR_TO_GLOBAL); PULA __PIC_JMP(_FAR_COPY_GLOBAL_LOGICAL_RC); } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_GLOBAL_NEAR_RC(void) { asm { CLRA /* near to logical (we may have to use another runtime if this gets non trivial as well :-( */ __PIC_JMP(_FAR_COPY_GLOBAL_LOGICAL_RC); } } #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_LOGICAL_NEAR_RC(void) { asm { EXG A,B EXG X,Y PSHA __PIC_JSR(_CONV_NEAR_TO_GLOBAL); PULA EXG A,B EXG X,Y __PIC_JMP(_FAR_COPY_LOGICAL_GLOBAL_RC); } } /* _FAR_COPY_LOGICAL_GLOBAL: is used by some old wizard generated projects. Not used by current setup anymore */ #ifdef __cplusplus extern "C" #endif #pragma NO_ENTRY #pragma NO_EXIT #pragma NO_FRAME void NEAR _FAR_COPY_LOGICAL_GLOBAL(void) { asm { STAA __GPAGE_ADR__ PSHX ;/* allocate some space where _SET_PAGE_REG_HCS12X can return the page */ __PIC_JSR(_SET_PAGE_REG_HCS12X) Loop: LDAB 1,X+ GSTAB 1,Y+ DECW 4,SP BNE Loop PULX STAA 0,X ;/* restore old page content (necessary if it was PPAGE) */ LDX 4,SP+ ;/* load return address and clean stack */ JMP 0,X } } #endif /* __HCS12X__ */ /*----------------- end of code ------------------------------------------------*/ /*lint --e{766} , runtime.sgm is not a regular header file, it contains a conditionally compiled CODE_SEG pragma */