| ; | |
| ; 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 |