1982 lines
68 KiB
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 */
|