openblt/Target/Demo/HCS12_DevKit_S12G128_CodeWa.../Prog/lib/datapage.c

1982 lines
68 KiB
C

/******************************************************************************
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 */