blob: 1bef12d24c00d29f3db2b97d87325058659c145c [file] [log] [blame]
;
; 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