1 /******************************************************************************
3 PURPOSE : paged data access runtime routines
4 MACHINE : Motorola 68HC12 (Target)
6 HISTORY : 21.7.96 first version created
7 ******************************************************************************/
10 According to the -Cp option of the compiler the
11 __DPAGE__, __PPAGE__ and __EPAGE__ macros are defined.
12 If none of them is given as argument, then no page accesses should occur and
13 this runtime routine should not be used !
14 To be on the save side, the runtime routines are created anyway.
15 If some of the -Cp options are given an adapted versions which only covers the
16 needed cases is produced.
19 /* if no compiler option -Cp is given, it is assumed that all possible are given : */
21 /* Compile with option -DHCS12 to activate this code */
22 #if defined(HCS12) || defined(_HCS12) /* HCS12 family has PPAGE register only at 0x30 */
23 #define PPAGE_ADDR (0x30+REGISTER_BASE)
24 #ifndef __PPAGE__ /* may be set already by option -CPPPAGE */
27 /* Compile with option -DDG128 to activate this code */
28 #elif defined DG128 /* HC912DG128 derivative has PPAGE register only at 0xFF */
29 #define PPAGE_ADDR (0xFF+REGISTER_BASE)
30 #ifndef __PPAGE__ /* may be set already by option -CPPPAGE */
33 #elif defined(HC812A4)
34 /* all setting default to A4 already */
38 #if !defined(__EPAGE__) && !defined(__PPAGE__) && !defined(__DPAGE__)
39 /* as default use all page registers */
45 /* modify the following defines to your memory configuration */
47 #define EPAGE_LOW_BOUND 0x400u
48 #define EPAGE_HIGH_BOUND 0x7ffu
50 #define DPAGE_LOW_BOUND 0x7000u
51 #define DPAGE_HIGH_BOUND 0x7fffu
53 #define PPAGE_LOW_BOUND (DPAGE_HIGH_BOUND+1)
54 #define PPAGE_HIGH_BOUND 0xBFFFu
56 #define REGISTER_BASE 0x0u
58 #define DPAGE_ADDR (0x34u+REGISTER_BASE)
61 #define EPAGE_ADDR (0x36u+REGISTER_BASE)
64 #define PPAGE_ADDR (0x35u+REGISTER_BASE)
68 The following parts about the defines are assumed in the code of _GET_PAGE_REG :
69 - the memory region controlled by DPAGE is above the area controlled by the EPAGE and
70 below the area controlled by the PPAGE.
71 - the lower bound of the PPAGE area is equal to be the higher bound of the DPAGE area + 1
73 #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
74 #error /* please adapt _GET_PAGE_REG for this non default page configuration */
77 #if DPAGE_HIGH_BOUND+1 != PPAGE_LOW_BOUND
78 #error /* please adapt _GET_PAGE_REG for this non default page configuration */
82 #include "non_bank.sgm"
83 #include "runtime.sgm"
85 /* this module does either control if any access is in the bounds of the specified page or */
86 /* ,if only one page is specified, just use this page. */
87 /* This behavior is controlled by the define USE_SEVERAL_PAGES. */
88 /* If !USE_SEVERAL_PAGES does increase the performance significantly */
89 /* NOTE : When !USE_SEVERAL_PAGES, the page is also set for accesses outside of the area controlled */
90 /* by this single page. But this is usually no problem because the page is set again before any other access */
92 #if !defined(__DPAGE__) && !defined(__EPAGE__) && !defined(__PPAGE__)
93 /* no page at all is specified */
94 /* only specifing the right pages will speed up these functions a lot */
95 #define USE_SEVERAL_PAGES 1
96 #elif defined(__DPAGE__) && defined(__EPAGE__) || defined(__DPAGE__) && defined(__PPAGE__) || defined(__EPAGE__) && defined(__PPAGE__)
97 /* more than one page register is used */
98 #define USE_SEVERAL_PAGES 1
101 #define USE_SEVERAL_PAGES 0
103 #if defined(__DPAGE__) /* check which pages are used */
104 #define PAGE_ADDR PPAGE_ADDR
105 #elif defined(__EPAGE__)
106 #define PAGE_ADDR EPAGE_ADDR
107 #elif defined(__PPAGE__)
108 #define PAGE_ADDR PPAGE_ADDR
109 #else /* we dont know which page, decide it at runtime */
110 #error /* must not happen */
116 #if USE_SEVERAL_PAGES /* only needed for several pages support */
117 /*--------------------------- _GET_PAGE_REG --------------------------------
118 Runtime routine to detect the right register depending on the 16 bit offset part
120 This function is only used by the functions below.
122 Depending on the compiler options -Cp different versions of _GET_PAGE_REG are produced.
125 - Y : offset part of an address
128 if address Y is controlled by a page register :
129 - X : address of page register if Y is controlled by an page register
131 - all other registers remain unchanged
133 if address Y is not controlled by a page register :
135 - all registers remain unchanged
137 --------------------------- _GET_PAGE_REG ----------------------------------*/
139 #if defined(__DPAGE__)
148 static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */
151 CPY #DPAGE_LOW_BOUND ; test of lower bound of DPAGE
152 #if defined(__EPAGE__)
153 BLO L_EPAGE ; EPAGE accesses are possible
155 BLO L_NOPAGE ; no paged memory below accesses
157 CPY #DPAGE_HIGH_BOUND ; test of higher bound DPAGE/lower bound PPAGE
158 #if defined(__PPAGE__)
159 BHI L_PPAGE ; EPAGE accesses are possible
161 BHI L_NOPAGE ; no paged memory above accesses
164 LDX #DPAGE_ADDR ; load page register address and clear zero flag
167 #if defined(__PPAGE__)
169 CPY #PPAGE_HIGH_BOUND ; test of higher bound of PPAGE
172 LDX #PPAGE_ADDR ; load page register address and clear zero flag
176 #if defined(__EPAGE__)
178 CPY #EPAGE_LOW_BOUND ; test of lower bound of EPAGE
180 CPY #EPAGE_HIGH_BOUND ; test of higher bound of EPAGE
184 LDX #EPAGE_ADDR ; load page register address and clear zero flag
189 ORCC #0x04 ; sets zero flag
194 #else /* !defined(__DPAGE__) */
196 #if defined( __PPAGE__ )
205 static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */
208 CPY #PPAGE_LOW_BOUND ; test of lower bound of PPAGE
209 #if defined( __EPAGE__ )
212 BLO L_NOPAGE ; no paged memory below
214 CPY #PPAGE_HIGH_BOUND ; test of higher bound PPAGE
217 LDX #PPAGE_ADDR ; load page register address and clear zero flag
219 #if defined( __EPAGE__ )
221 CPY #EPAGE_LOW_BOUND ; test of lower bound of EPAGE
223 CPY #EPAGE_HIGH_BOUND ; test of higher bound of EPAGE
226 LDX #EPAGE_ADDR ; load page register address and clear zero flag
230 L_NOPAGE: ; not in any allowed page area
231 ; its a far access to a non paged variable
232 ORCC #0x04 ; sets zero flag
237 #else /* !defined(__DPAGE__ ) && !defined( __PPAGE__) */
238 #if defined(__EPAGE__)
247 static void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */
250 CPY #EPAGE_LOW_BOUND ; test of lower bound of EPAGE
252 CPY #EPAGE_HIGH_BOUND ; test of higher bound of EPAGE
255 LDX #EPAGE_ADDR ; load page register address and clear zero flag
258 L_NOPAGE: ; not in any allowed page area
259 ; its a far access to a non paged variable
260 ORCC #0x04 ; sets zero flag
265 #endif /* defined(__EPAGE__) */
266 #endif /* defined(__PPAGE__) */
267 #endif /* defined(__DPAGE__) */
269 #endif /* USE_SEVERAL_PAGES */
271 /*--------------------------- _SET_PAGE --------------------------------
272 Runtime routine to set the right page register. This routine is used if the compiler
273 does not know the right page register, i.e. if the option -Cp is used for more than
274 one pageregister or if the runtime option is used for one of the -Cp options.
277 - offset part of an address in the Y register
278 - page part of an address in the B register
281 - page part written into the correct page register.
282 - the old page register content is destroyed
283 - all processor registers remains unchanged
284 --------------------------- _SET_PAGE ----------------------------------*/
293 void NEAR _SET_PAGE(void) {
294 #if USE_SEVERAL_PAGES
296 PSHX ; save X register
297 __PIC_JSR(_GET_PAGE_REG)
299 STAB 0,X ; set page register
301 PULX ; restore X register
304 #else /* USE_SEVERAL_PAGES */
306 STAB PAGE_ADDR ; set page register
309 #endif /* USE_SEVERAL_PAGES */
312 /*--------------------------- _LOAD_FAR_8 --------------------------------
313 This runtime routine is used to access paged memory via a runtime function.
314 It may also be used if the compiler option -Cp is not used with the runtime argument.
317 - offset part of an address in the Y register
318 - page part of an address in the B register
321 - value to be read in the B register
322 - all other registers remains unchanged
323 - all page register still contain the same value
324 --------------------------- _LOAD_FAR_8 ----------------------------------*/
333 void NEAR _LOAD_FAR_8(void) {
334 #if USE_SEVERAL_PAGES
336 PSHX ; save X register
337 __PIC_JSR(_GET_PAGE_REG)
339 PSHA ; save A register
340 LDAA 0,X ; save page register
341 STAB 0,X ; set page register
342 LDAB 0,Y ; actual load, overwrites page
343 STAA 0,X ; restore page register
344 PULA ; restore A register
345 PULX ; restore X register
348 LDAB 0,Y ; actual load, overwrites page
349 PULX ; restore X register
352 #else /* USE_SEVERAL_PAGES */
354 PSHA ; save A register
355 LDAA PAGE_ADDR ; save page register
356 STAB PAGE_ADDR ; set page register
357 LDAB 0,Y ; actual load, overwrites page
358 STAA PAGE_ADDR ; restore page register
359 PULA ; restore A register
362 #endif /* USE_SEVERAL_PAGES */
365 /*--------------------------- _LOAD_FAR_16 --------------------------------
366 This runtime routine is used to access paged memory via a runtime function.
367 It may also be used if the compiler option -Cp is not used with the runtime argument.
370 - offset part of an address in the Y register
371 - page part of an address in the B register
374 - value to be read in the Y register
375 - all other registers remains unchanged
376 - all page register still contain the same value
377 --------------------------- _LOAD_FAR_16 ----------------------------------*/
386 void NEAR _LOAD_FAR_16(void) {
387 #if USE_SEVERAL_PAGES
389 PSHX ; save X register
390 __PIC_JSR(_GET_PAGE_REG)
392 PSHA ; save A register
393 LDAA 0,X ; save page register
394 STAB 0,X ; set page register
395 LDY 0,Y ; actual load, overwrites address
396 STAA 0,X ; restore page register
397 PULA ; restore A register
398 PULX ; restore X register
401 LDY 0,Y ; actual load, overwrites address
402 PULX ; restore X register
405 #else /* USE_SEVERAL_PAGES */
407 PSHA ; save A register
408 LDAA PAGE_ADDR ; save page register
409 STAB PAGE_ADDR ; set page register
410 LDY 0,Y ; actual load, overwrites address
411 STAA PAGE_ADDR ; restore page register
412 PULA ; restore A register
415 #endif /* USE_SEVERAL_PAGES */
417 /*--------------------------- _LOAD_FAR_24 --------------------------------
418 This runtime routine is used to access paged memory via a runtime function.
419 It may also be used if the compiler option -Cp is not used with the runtime argument.
422 - offset part of an address in the Y register
423 - page part of an address in the B register
426 - value to be read in the Y:B registers
427 - all other registers remains unchanged
428 - all page register still contain the same value
429 --------------------------- _LOAD_FAR_24 ----------------------------------*/
438 void NEAR _LOAD_FAR_24(void) {
439 #if USE_SEVERAL_PAGES
441 PSHX ; save X register
442 __PIC_JSR(_GET_PAGE_REG)
444 PSHA ; save A register
445 LDAA 0,X ; save page register
446 STAB 0,X ; set page register
447 LDAB 0,Y ; actual load, overwrites page of address
448 LDY 1,Y ; actual load, overwrites offset of address
449 STAA 0,X ; restore page register
450 PULA ; restore A register
451 PULX ; restore X register
454 LDAB 0,Y ; actual load, overwrites page of address
455 LDY 1,Y ; actual load, overwrites offset of address
456 PULX ; restore X register
459 #else /* USE_SEVERAL_PAGES */
461 PSHA ; save A register
462 LDAA PAGE_ADDR ; save page register
463 STAB PAGE_ADDR ; set page register
464 LDAB 0,Y ; actual load, overwrites page of address
465 LDY 1,Y ; actual load, overwrites offset of address
466 STAA PAGE_ADDR ; restore page register
467 PULA ; restore A register
470 #endif /* USE_SEVERAL_PAGES */
474 /*--------------------------- _LOAD_FAR_32 --------------------------------
475 This runtime routine is used to access paged memory via a runtime function.
476 It may also be used if the compiler option -Cp is not used with the runtime argument.
479 - offset part of an address in the Y register
480 - page part of an address in the B register
483 - low 16 bit of value to be read in the D registers
484 - high 16 bit of value to be read in the Y registers
485 - all other registers remains unchanged
486 - all page register still contain the same value
487 --------------------------- _LOAD_FAR_32 ----------------------------------*/
496 void NEAR _LOAD_FAR_32(void) {
497 #if USE_SEVERAL_PAGES
499 PSHX ; save X register
500 __PIC_JSR(_GET_PAGE_REG)
502 LDAA 0,X ; save page register
503 PSHA ; put it onto the stack
504 STAB 0,X ; set page register
505 LDD 2,Y ; actual load, low word
506 LDY 0,Y ; actual load, high word
507 MOVB 1,SP+,0,X ; restore page register
508 PULX ; restore X register
511 LDD 2,Y ; actual load, low word
512 LDY 0,Y ; actual load, high word
513 PULX ; restore X register
516 #else /* USE_SEVERAL_PAGES */
518 LDAA PAGE_ADDR ; save page register
519 PSHA ; put it onto the stack
520 STAB PAGE_ADDR ; set page register
521 LDD 2,Y ; actual load, low word
522 LDY 0,Y ; actual load, high word
523 MOVB 1,SP+,PAGE_ADDR; restore page register
526 #endif /* USE_SEVERAL_PAGES */
529 /*--------------------------- _STORE_FAR_8 --------------------------------
530 This runtime routine is used to access paged memory via a runtime function.
531 It may also be used if the compiler option -Cp is not used with the runtime argument.
534 - offset part of an address in the Y register
535 - page part of an address in the B register
536 - value to be stored in the B register
539 - value stored at the address
540 - all registers remains unchanged
541 - all page register still contain the same value
542 --------------------------- _STORE_FAR_8 ----------------------------------*/
551 void NEAR _STORE_FAR_8(void) {
552 #if USE_SEVERAL_PAGES
554 PSHX ; save X register
555 __PIC_JSR(_GET_PAGE_REG)
557 PSHB ; save B register
558 LDAB 0,X ; save page register
559 MOVB 0,SP, 0,X ; set page register
560 STAA 0,Y ; store the value passed in A
561 STAB 0,X ; restore page register
562 PULB ; restore B register
563 PULX ; restore X register
566 STAA 0,Y ; store the value passed in A
567 PULX ; restore X register
570 #else /* USE_SEVERAL_PAGES */
572 PSHB ; save A register
573 LDAB PAGE_ADDR ; save page register
574 MOVB 0,SP,PAGE_ADDR ; set page register
575 STAA 0,Y ; store the value passed in A
576 STAB PAGE_ADDR ; restore page register
577 PULB ; restore B register
580 #endif /* USE_SEVERAL_PAGES */
583 /*--------------------------- _STORE_FAR_16 --------------------------------
584 This runtime routine is used to access paged memory via a runtime function.
585 It may also be used if the compiler option -Cp is not used with the runtime argument.
588 - offset part of an address in the Y register
589 - page part of an address in the B register
590 - value to be stored in the X register
593 - value stored at the address
594 - all registers remains unchanged
595 - all page register still contain the same value
596 --------------------------- _STORE_FAR_16 ----------------------------------*/
605 void NEAR _STORE_FAR_16(void) {
606 #if USE_SEVERAL_PAGES
608 PSHX ; save X register
609 __PIC_JSR(_GET_PAGE_REG)
613 LDAA 0,X ; save page register
614 STAB 0,X ; set page register
615 MOVW 1,SP, 0,Y ; store the value passed in X
616 STAA 0,X ; restore page register
617 PULA ; restore A register
618 PULX ; restore X register
622 STX 0,Y ; store the value passed in X
623 PULX ; restore X register
626 #else /* USE_SEVERAL_PAGES */
628 PSHA ; save A register
629 LDAA PAGE_ADDR ; save page register
630 STAB PAGE_ADDR ; set page register
631 STX 0,Y ; store the value passed in X
632 STAA PAGE_ADDR ; restore page register
633 PULA ; restore A register
636 #endif /* USE_SEVERAL_PAGES */
638 /*--------------------------- _STORE_FAR_24 --------------------------------
639 This runtime routine is used to access paged memory via a runtime function.
640 It may also be used if the compiler option -Cp is not used with the runtime argument.
643 - offset part of an address in the Y register
644 - page part of an address in the B register
645 - value to be stored in the X:A registers (X : low 16 bit, A : high 8 bit)
648 - value stored at the address
649 - all registers remains unchanged
650 - all page register still contain the same value
651 --------------------------- _STORE_FAR_24 ----------------------------------*/
660 void NEAR _STORE_FAR_24(void) {
661 #if USE_SEVERAL_PAGES
663 PSHX ; save X register
664 __PIC_JSR(_GET_PAGE_REG)
668 LDAA 0,X ; save page register
669 STAB 0,X ; set page register
670 MOVW 1,SP, 1,Y ; store the value passed in X
671 MOVB 0,SP, 0,Y ; store the value passed in A
672 STAA 0,X ; restore page register
673 PULA ; restore A register
674 PULX ; restore X register
678 STX 1,Y ; store the value passed in X
679 STAA 0,Y ; store the value passed in X
680 PULX ; restore X register
683 #else /* USE_SEVERAL_PAGES */
685 PSHA ; save A register
686 LDAA PAGE_ADDR ; save page register
687 STAB PAGE_ADDR ; set page register
688 MOVB 0,SP, 0,Y ; store the value passed in A
689 STX 1,Y ; store the value passed in X
690 STAA PAGE_ADDR ; restore page register
691 PULA ; restore A register
694 #endif /* USE_SEVERAL_PAGES */
696 /*--------------------------- _STORE_FAR_32 --------------------------------
697 This runtime routine is used to access paged memory via a runtime function.
698 It may also be used if the compiler option -Cp is not used with the runtime argument.
701 - offset part of an address in the Y register
702 - page part of an address is on the stack at 3,SP (just below the return address)
703 - value to be stored in the X:D registers (D : low 16 bit, X : high 16 bit)
706 - value stored at the address
707 - all registers remains unchanged
708 - the page part is removed from the stack
709 - all page register still contain the same value
710 --------------------------- _STORE_FAR_32 ----------------------------------*/
719 void NEAR _STORE_FAR_32(void) {
720 #if USE_SEVERAL_PAGES
722 PSHX ; save X register
723 __PIC_JSR(_GET_PAGE_REG)
727 LDAA 0,X ; save page register
728 MOVB 6,SP, 0,X ; set page register
729 MOVW 2,SP, 0,Y ; store the value passed in X (high word)
730 MOVW 0,SP, 2,Y ; store the value passed in D (low word)
731 STAA 0,X ; restore page register
732 PULD ; restore A register
736 MOVW 0,SP, 0,Y ; store the value passed in X (high word)
737 STD 2,Y ; store the value passed in D (low word)
739 PULX ; restore X register
740 MOVW 0,SP, 1,+SP ; move return address
743 #else /* USE_SEVERAL_PAGES */
745 PSHD ; save D register
746 LDAA PAGE_ADDR ; save page register
747 LDAB 4,SP ; load page part of address
748 STAB PAGE_ADDR ; set page register
749 STX 0,Y ; store the value passed in X
750 MOVW 0,SP, 2,Y ; store the value passed in D (low word)
751 STAA PAGE_ADDR ; restore page register
752 PULD ; restore D register
753 MOVW 0,SP, 1,+SP ; move return address
756 #endif /* USE_SEVERAL_PAGES */
759 /*--------------------------- _FAR_COPY --------------------------------
760 This runtime routine is used to access paged memory via a runtime function.
761 It may also be used if the compiler option -Cp is not used with the runtime argument.
764 - offset part of the source int the X register
765 - page part of the source in the A register
766 - offset part of the dest int the Y register
767 - page part of the dest in the B register
768 - number of bytes to be copied at 2,SP. The number of bytes is always > 0
772 - no registers are saved, i.e. all registers may be destroied
773 - all page register still contain the same value
776 stack-structure at the loop-label:
777 0,SP : destination offset
779 3,SP : destination page
781 6,SP : return address
783 --------------------------- _FAR_COPY ----------------------------------*/
792 void NEAR _FAR_COPY(void) {
793 #if USE_SEVERAL_PAGES
795 DEX ; source addr-=1, because loop counter ends at 1
796 PSHX ; save source offset
797 PSHD ; save both pages
798 DEY ; destination addr-=1, because loop counter ends at 1
799 PSHY ; save destination offset
800 LDX 8,SP ; load counter, assuming counter > 0
803 LDD 4,SP ; load source offset
804 LEAY D,X ; calcutate actual source address
805 LDAB 2,SP ; load source page
806 __PIC_JSR (_LOAD_FAR_8); load 1 source byte
808 LDD 0+1,SP ; load destination offset
809 LEAY D,X ; calcutate acual destination address
811 LDAB 3,SP ; load destination page
812 __PIC_JSR (_STORE_FAR_8); store one byte
815 LDX 6,SP ; load return address
816 LEAS 10,SP ; release stack
821 PSHD ; store page registers
823 ADDD 4,SP ; calculate source end address
825 PULB ; reload source page
826 LDAA PAGE_ADDR ; save page register
829 STAB PAGE_ADDR ; set source page
830 LDAA 1,X+ ; load value
831 MOVB 1,SP, PAGE_ADDR ; set destination page
836 LDAA 2,SP+ ; restore old page value and release stack
837 STAA PAGE_ADDR ; store it into page register
838 LDX 4,SP+ ; release stack and load return address