/****************************************************************************** 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" #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. If some of the -Cp options are given an adapted versions which only covers the needed cases is produced. */ /* if no compiler option -Cp is given, it is assumed that all possible are given : */ /* Compile with option -DHCS12 to activate this code */ #if defined(HCS12) || defined(_HCS12) || defined(__HCS12__) /* HCS12 family has PPAGE register only at 0x30 */ #define PPAGE_ADDR (0x30+REGISTER_BASE) #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 */ #define PPAGE_ADDR (0xFF+REGISTER_BASE) #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+1) #define PPAGE_HIGH_BOUND 0xBFFFu #define REGISTER_BASE 0x0u #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+1 != 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 HCS12X Logical Memory map (RAM mapped) 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 RAM 0xFA1000..0xFD1FFF Not Paged 0FC000 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 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. Do 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 now 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 LDAA 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 DMA Registers are also only addressable with global addresses. - The PPAGE can 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. This has the implication that the logical address 0x001000 is strictly seen not valid. */ #if __OPTION_ACTIVE__("-MapRAM") #define __HCS12XE_RAMHM_SET__ #endif /*--------------------------- 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 ------------------------------------------------*/