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