; | |
; This file should only be included in the 78K0R_Kx3L demo. The 78K0R_Kx3 demo | |
; uses the standard startup file. This is work around a bug in the startup | |
; file provided with the IAR tools. | |
; | |
;------------------------------------------------------------------------------ | |
; CSTARTUP source for 78K | |
; | |
; This module contains the code executed before the C/C++ "main" | |
; function is called. | |
; | |
; The code usually must be tailored to suit a specific hardware | |
; configuration. | |
; | |
; Assembler options: | |
; | |
; -D__STANDARD_MODEL__ To assemble for use with compiler standard | |
; code model. | |
; | |
; -D__BANKED_MODEL__ To assemble for use with compiler banked | |
; code model. | |
; | |
; -D__NEAR_MODEL__ To assemble for use with compiler near | |
; code model. | |
; | |
; -D__FAR_MODEL__ To assemble for use with compiler far | |
; code model. | |
; | |
; Linker options: | |
; | |
; -D_CODEBANK_REG=0 To link for use with "standard" code model, | |
; no banked functions. | |
; | |
; -D_CODEBANK_REG='addr' To link for use with "banked" code model or | |
; "standard" code model with banked functions. | |
; 'addr' = bank switch register address. | |
; | |
;------------------------------------------------------------------------------ | |
; Copyright (c) 2003-2008 IAR Systems AB. | |
; $Revision: 3577 $ | |
;------------------------------------------------------------------------------ | |
#if !defined(__STANDARD_MODEL__) && !defined(__BANKED_MODEL__) && !defined(__NEAR_MODEL__) && !defined(__FAR_MODEL__) | |
#error One of the macros __STANDARD_MODEL__, __BANKED_MODEL__, __NEAR_MODEL__ or __FAR_MODEL__ must be defined ! | |
#endif | |
;------------------------------------------------------------------------------ | |
; The stack segment. | |
; The stack size is defined in the linker command file | |
;------------------------------------------------------------------------------ | |
MODULE ?CSTARTUP | |
RSEG CSTACK:DATA:ROOT(1) | |
;------------------------------------------------------------------------------ | |
; The interrupt vector segment. | |
; Interrupt functions with defined vectors will reserve | |
; space in this area as well as conformingly written assembly | |
; language interrupt handlers | |
;------------------------------------------------------------------------------ | |
COMMON INTVEC:CODE:ROOT(1) | |
DC16 __program_start_fr ; Reset vector | |
;------------------------------------------------------------------------------ | |
; The actual startup code | |
; | |
; Entry: __program_start | |
;------------------------------------------------------------------------------ | |
RSEG RCODE:CODE:ROOT(0) | |
PUBLIC ?C_STARTUP | |
PUBLIC `@cstart` ; NEC debugger specific | |
PUBLIC __program_start_fr | |
EXTERN __low_level_init | |
EXTERN __MAIN_CALL | |
#if defined(__STANDARD_MODEL__) || defined(__BANKED_MODEL__) | |
EXTERN _CODEBANK_REG | |
#else | |
EXTERN _NEAR_CONST_LOCATION | |
PMC DEFINE 0xFFFFE | |
#endif | |
#if defined(__BANKED_MODEL__) | |
EXTERN ?FAR_CALL_L07 | |
SFRTYPE BANK_REG BYTE, READ, WRITE = _CODEBANK_REG | |
#endif | |
REQUIRE __MAIN_CALL | |
;------------------------------------------------------------------------------ | |
; Perform the run-time initialization. | |
;------------------------------------------------------------------------------ | |
?C_STARTUP: | |
`@cstart`: | |
__program_start_fr: | |
DI | |
#if defined(__BANKED_MODEL__) | |
MOV BANK_REG, #0 ; Banked, clear bank register | |
#elif defined(__STANDARD_MODEL__) | |
MOVW AX, #_CODEBANK_REG | |
OR A, X | |
BZ nobank ; Standard, no banked functions, no bank register (=0) | |
MOVW HL, #_CODEBANK_REG | |
XOR A, A | |
MOV [HL], A ; Standard with banked functions, clear bank register | |
nobank: | |
#else | |
MOV A, #(_NEAR_CONST_LOCATION & 1) ; Near/Far, set mirror area | |
MOV1 CY, A.0 | |
MOV1 PMC.0, CY | |
#endif | |
#if __CORE__ != __78K0S__ | |
MOVW SP, #sfe(CSTACK) | |
#else | |
MOVW AX, #sfe(CSTACK) | |
MOVW SP, AX | |
#endif | |
; Init stack segment for 78K0R, as the generated code may sometimes | |
; access the 4th byte of a return address before it is initialized | |
#if __CORE__ == __78K0R__ | |
MOVW HL, #sfb(CSTACK) | |
MOVW BC, #LWRD(sizeof(CSTACK)) | |
CMP0 C | |
SKZ | |
INC B | |
MOV A, #0xCD | |
loop_s: | |
MOV [HL], A | |
INCW HL | |
DEC C | |
BNZ loop_s | |
DEC B | |
BNZ loop_s | |
#endif | |
#if __CORE__ == __78K0R__ | |
MOV CS, #0 | |
#endif | |
;------------------------------------------------------------------------------ | |
; Here is the place to put user initializations. | |
;------------------------------------------------------------------------------ | |
; User initialization code | |
;------------------------------------------------------------------------------ | |
; Call __low_level_init to perform initialization before initializing | |
; segments and calling main. | |
; If the function returns 0, no segment initialization should take place. | |
; | |
; Link with your own version of __low_level_init to override the | |
; default action: to do nothing but return 1. | |
;------------------------------------------------------------------------------ | |
#if defined(__FAR_MODEL__) | |
CALL F:__low_level_init | |
#elif defined(__BANKED_MODEL__) | |
MOV E, #byte3(__low_level_init) | |
MOVW HL, #lwrd(__low_level_init) | |
CALL ?FAR_CALL_L07 | |
#else | |
CALL __low_level_init | |
#endif | |
OR A, X | |
#if __CORE__ == __78K0R__ | |
SKNZ | |
BR N:__MAIN_CALL | |
#else | |
BZ __MAIN_CALL | |
#endif | |
ENDMOD | |
#if defined(__NEAR_MODEL__) || defined(__FAR_MODEL__) | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; FAR_Z "uninitialized far data" are filled with zero | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_FAR_Z | |
RSEG FAR_Z:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_FAR_Z | |
__INIT_FAR_Z: | |
MOV ES, #BYTE3(sfb(FAR_Z)) | |
MOVW HL, #LWRD(sfb(FAR_Z)) | |
MOV D, #BYTE3(sizeof(FAR_Z)) | |
MOVW BC, #LWRD(sizeof(FAR_Z)) | |
CMP0 C | |
SKZ | |
INC B | |
CMP0 B | |
SKZ | |
INC D | |
CLRB A | |
loop: | |
MOV ES:[HL], A | |
INCW HL | |
MOV A, H | |
OR A, L | |
CLRB A | |
SKNZ | |
INC ES | |
DEC C | |
BNZ loop | |
DEC B | |
BNZ loop | |
DEC D | |
BNZ loop | |
ENDMOD | |
#endif | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; NEAR_Z "uninitialized near data" are filled with zero | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_NEAR_Z | |
RSEG NEAR_Z:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_NEAR_Z | |
__INIT_NEAR_Z: | |
#if __CORE__ == __78K0R__ | |
LIMIT sfb(NEAR_Z)>=0xF0000,1,1,"NEAR_I not placed in near memory" | |
#endif | |
MOVW HL, #sfb(NEAR_Z) | |
MOVW BC, #sizeof(NEAR_Z) | |
#if __CORE__ == __78K0R__ | |
CMP0 C | |
SKZ | |
INC B | |
CLRB A | |
#else | |
MOV A, C | |
OR A, A | |
BZ cont | |
INC B | |
XOR A, A | |
cont: | |
#endif | |
loop: | |
MOV [HL], A | |
INCW HL | |
#if __CORE__ == __78K0R__ | |
DEC C | |
BNZ loop | |
DEC B | |
BNZ loop | |
#else | |
DBNZ C, loop | |
DBNZ B, loop | |
#endif | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; SADDR_Z "uninitialized saddr data" are filled with zero | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_SADDR_Z | |
RSEG SADDR_Z:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_SADDR_Z | |
__INIT_SADDR_Z: | |
#if __CORE__ == __78K0R__ | |
LIMIT sfb(SADDR_Z),0xFFE20,0xFFF1F,"SADDR_Z not within saddr memory range" | |
LIMIT sfe(SADDR_Z),0xFFE20,0xFFF1F,"SADDR_Z not within saddr memory range" | |
#else | |
LIMIT sfb(SADDR_Z),0xFE20,0xFF1F,"SADDR_Z not within saddr memory range" | |
LIMIT sfe(SADDR_Z),0xFE20,0xFF1F,"SADDR_Z not within saddr memory range" | |
#endif | |
MOVW HL, #sfb(SADDR_Z) | |
MOV B, #sizeof(SADDR_Z) | |
#if __CORE__ == __78K0R__ | |
CLRB A | |
#else | |
XOR A, A | |
#endif | |
loop: | |
MOV [HL], A | |
INCW HL | |
#if __CORE__ == __78K0R__ | |
DEC B | |
BNZ loop | |
#else | |
DBNZ B, loop | |
#endif | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; WRKSEG short address work area is filled with zero | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_WRKSEG | |
RSEG WRKSEG:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_WRKSEG | |
__INIT_WRKSEG: | |
#if __CORE__ == __78K0R__ | |
LIMIT sfb(WRKSEG),0xFFE20,0xFFF1F,"WRKSEG not within saddr memory range" | |
LIMIT sfe(WRKSEG),0xFFE20,0xFFF1F,"WRKSEG not within saddr memory range" | |
#else | |
LIMIT sfb(WRKSEG),0xFE20,0xFF1F,"WRKSEG not within saddr memory range" | |
LIMIT sfe(WRKSEG),0xFE20,0xFF1F,"WRKSEG not within saddr memory range" | |
#endif | |
MOVW HL, #sfb(WRKSEG) | |
MOV B, #sizeof(WRKSEG) | |
#if __CORE__ == __78K0R__ | |
CLRB A | |
#else | |
XOR A, A | |
#endif | |
loop: | |
MOV [HL], A | |
INCW HL | |
#if __CORE__ == __78K0R__ | |
DEC B | |
BNZ loop | |
#else | |
DBNZ B, loop | |
#endif | |
ENDMOD | |
#if defined(__NEAR_MODEL__) || defined(__FAR_MODEL__) | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; FAR_ID is copied to FAR_I "initialized far data" | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_FAR_I | |
RSEG FAR_I:DATA(0) | |
RSEG FAR_ID:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_FAR_I | |
__INIT_FAR_I: | |
; First make sure FAR_I and FAR_ID have the same size | |
LIMIT sizeof(FAR_I)-sizeof(FAR_ID),0,0,"FAR_I and FAR_ID not same size" | |
; Sanity check | |
LIMIT (sfb(FAR_I)-sfb(FAR_ID))==0,0,0,"FAR_I and FAR_ID have same start address" | |
; FAR_I and FAR_ID must start at the same offset in a 64k page, unless sizeof | |
; FAR_I is less than 64k, then it's enugh if both segments reside within a 64k | |
; boundary | |
LIMIT (((sfb(FAR_I)^sfb(FAR_ID)) & 0xFFFF) == 0) || ( (sizeof(FAR_I)< 0x10000) && (((sfb(FAR_I)^sfe(FAR_I)) & 0xF0000) == 0) && (((sfb(FAR_I)^sfe(FAR_I)) & 0xF0000) == 0) ),1,1,"FAR_I and FAR_ID have same start address" | |
; LIMIT (sfb(FAR_I)^sfb(FAR_ID)) & 0xFFFF,0,0,"FAR_I and FAR_ID must start at the same offset into a 64k page" | |
MOV ES, #BYTE3(sfb(FAR_ID)) | |
MOVW HL, #LWRD(sfb(FAR_ID)) | |
MOV CS, #BYTE3(sizeof(FAR_ID)) ; CS is used as counter | |
MOVW AX, #LWRD(sizeof(FAR_ID)) | |
MOVW BC, AX | |
CMP0 C | |
SKZ | |
INC B | |
CMP0 B | |
SKZ | |
INC CS ; counter | |
MOV A, #BYTE3(sfb(FAR_I)) | |
MOVW DE, #LWRD(sfb(FAR_I)) | |
MOV X, A | |
loop: | |
MOV A, ES:[HL] | |
XCH A, X | |
XCH A, ES | |
XCH A, X | |
MOV ES:[DE], A | |
XCH A, X | |
XCH A, ES | |
XCH A, X | |
INCW HL | |
MOV A, H | |
OR A, L | |
SKNZ | |
INC ES | |
INCW DE | |
MOV A, D | |
OR A, E | |
SKNZ | |
INC X | |
DEC C | |
BNZ loop | |
DEC B | |
BNZ loop | |
DEC CS ; counter | |
BNZ loop | |
ENDMOD | |
#endif | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; NEAR_ID is copied to NEAR_I "initialized near data" | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_NEAR_I | |
RSEG NEAR_I:DATA(0) | |
RSEG NEAR_ID:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_NEAR_I | |
__INIT_NEAR_I: | |
#if __CORE__ == __78K0R__ | |
LIMIT sfb(NEAR_I)>=0xF0000,1,1,"NEAR_I not placed in near memory" | |
#endif | |
LIMIT sizeof(NEAR_I)-sizeof(NEAR_ID),0,0,"NEAR_I and NEAR_ID not same size" | |
#if __CORE__ == __78K0R__ | |
MOV ES, #BYTE3(sfb(NEAR_ID)) | |
#endif | |
MOVW HL, #sfb(NEAR_ID) | |
MOVW BC, #sizeof(NEAR_ID) | |
#if __CORE__ == __78K0R__ | |
CMP0 C | |
SKZ | |
INC B | |
#else | |
MOV A, C | |
OR A, A | |
BZ cont | |
INC B | |
cont: | |
#endif | |
MOVW DE, #sfb(NEAR_I) | |
loop: | |
#if __CORE__ != __78K0R__ | |
MOV A, [HL] | |
#else | |
MOV A, ES:[HL] | |
#endif | |
MOV [DE], A | |
INCW HL | |
INCW DE | |
#if __CORE__ == __78K0R__ | |
DEC C | |
BNZ loop | |
DEC B | |
BNZ loop | |
#else | |
DBNZ C, loop | |
DBNZ B, loop | |
#endif | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Segment initialization | |
; | |
; SADDR_ID is copied to SADDR_I "initialized saddr data" | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_SADDR_I | |
RSEG SADDR_I:DATA(0) | |
RSEG SADDR_ID:DATA(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_SADDR_I | |
__INIT_SADDR_I: | |
#if __CORE__ == __78K0R__ | |
LIMIT sfb(SADDR_I),0xFFE20,0xFFF1F,"SADDR_I not within saddr memory range" | |
LIMIT sfe(SADDR_I),0xFFE20,0xFFF1F,"SADDR_I not within saddr memory range" | |
#else | |
LIMIT sfb(SADDR_I),0xFE20,0xFF1F,"SADDR_I not within saddr memory range" | |
LIMIT sfe(SADDR_I),0xFE20,0xFF1F,"SADDR_I not within saddr memory range" | |
#endif | |
LIMIT sizeof(SADDR_I)-sizeof(SADDR_ID),0,0,"SADDR_I and SADDR_ID not same size" | |
#if __CORE__ == __78K0R__ | |
MOV ES, #BYTE3(sfb(SADDR_ID)) | |
#endif | |
MOVW HL, #sfb(SADDR_ID) | |
MOV B, #sizeof(SADDR_ID) | |
MOVW DE, #sfb(SADDR_I) | |
loop: | |
#if __CORE__ != __78K0R__ | |
MOV A, [HL] | |
#else | |
MOV A, ES:[HL] | |
#endif | |
MOV [DE], A | |
INCW HL | |
INCW DE | |
#if __CORE__ == __78K0R__ | |
DEC B | |
BNZ loop | |
#else | |
DBNZ B, loop | |
#endif | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Initialize constructors | |
; | |
; This segment part is required by the compiler when it is | |
; necessary to call constructors of global objects. | |
;------------------------------------------------------------------------------ | |
MODULE ?__INIT_CTORS | |
RSEG DIFUNCT(0) | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __INIT_CTORS | |
EXTERN __call_ctors | |
#if defined(__BANKED_MODEL__) | |
EXTERN ?FAR_CALL_L07 | |
#endif | |
__INIT_CTORS: | |
#if __CORE__ == __78K0R__ | |
MOV X, #byte3(sfe(DIFUNCT)) | |
PUSH AX | |
MOVW AX, #lwrd(sfe(DIFUNCT)) | |
PUSH AX | |
MOV X, #byte3(sfb(DIFUNCT)) | |
PUSH AX | |
MOVW AX, #lwrd(sfb(DIFUNCT)) | |
PUSH AX | |
CALL F:__call_ctors | |
#elif defined(__BANKED_MODEL__) | |
MOVW AX, #sfb(DIFUNCT) | |
MOVW BC, #sfe(DIFUNCT) | |
MOV E, #byte3(__call_ctors) | |
MOVW HL, #lwrd(__call_ctors) | |
CALL ?FAR_CALL_L07 | |
#else | |
MOVW AX, #sfb(DIFUNCT) | |
MOVW BC, #sfe(DIFUNCT) | |
CALL __call_ctors | |
#endif | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Enter main | |
; | |
; Call the actual "main" function | |
;------------------------------------------------------------------------------ | |
MODULE ?__MAIN_CALL | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __MAIN_CALL | |
PUBLIC `@cend` ; NEC debugger specific | |
EXTERN main | |
EXTERN exit | |
#if defined(__BANKED_MODEL__) | |
EXTERN ?FAR_CALL_L07 | |
#endif | |
__MAIN_CALL: | |
#if defined(__FAR_MODEL__) | |
CALL F:main | |
CALL F:exit | |
#elif defined(__BANKED_MODEL__) | |
MOV E, #byte3(main) | |
MOVW HL, #lwrd(main) | |
CALL ?FAR_CALL_L07 | |
MOV E, #byte3(exit) | |
MOVW HL, #lwrd(exit) | |
CALL ?FAR_CALL_L07 | |
#else | |
CALL main | |
CALL exit | |
#endif | |
`@cend`: | |
; STOP ; Should not return | |
ENDMOD | |
;------------------------------------------------------------------------------ | |
; Low level initialization function | |
; | |
; Entry: __low_level_init | |
; | |
; The only action of this default version of '__low_level_init' is to | |
; return 1. By doing so it signals that normal initialization of data | |
; segments should be done. | |
; | |
; A customized version of '__low_level_init' may be created in order to | |
; perform initialization before initializing segments and calling main | |
; and/or to skip initialization of data segments under certain | |
; circumstances. | |
;------------------------------------------------------------------------------ | |
MODULE ?__low_level_init_stub | |
RSEG RCODE:CODE:NOROOT(0) | |
PUBLIC __low_level_init | |
__low_level_init: ; By returning 1 this function | |
MOVW AX, #1 ; indicates that the normal | |
RET ; initialization should take place | |
ENDMOD | |
END |