8.6.6 Startup routine

When the PIC, PIROD, or PID facility is used, the following processes in the startup routine need to be changed.

-

Reset vector

-

Initialization of base registers

-

Initialization of RAM sections

-

Branch to main function

 

(1)

Reset vector

When the entire program is to be configured as position-independent, it is necessary to jump from the reset vector to a desired position. Therefore, the branch destination address should be written to a specific RAM area or data flash area as an example. To restart the program without shutting off the power supply of the microcontroller, the branch destination address should be stored in a specific register.

 

In the reset vector, the address to be jumped to is acquired and a register indirect branch is executed.

    cstart_address .set 0xXXXXXXXX    ; Address storing the branch destination 
                                      ; address to be executed
 
    .section "RESET", text
    .align   512
    mov cstart_address, r10
    ld.w 0[r10], r10
    jmp [r10]

 

(2)

Initialization of base registers

When the PID facility is used, first the means of passing the offset information (hereafter referred to as the RAM offset value), such as how much to shift the allocation position at execution from the start address of the RAM section that was specified at linkage, has to be decided in advance. For example, the RAM offset value should be written to a specific RAM area or data flash area.Note

Note

Since the specific area has to be referenced with an absolute address in this case, the PID or PIROD facility is not supported.

 

To restart the program without shutting off the power supply of the microcontroller, the RAM offset value should be stored in a specific register.

The RAM offset value that was received is added to the base register, and this address will be used as the base address at execution.

    mov      0xfedf0000, r28       ; Memory address for passing RAM offset value
    ld.w     0[r28], r28           ; Offset (RAM offset) between data arrangement
                                   ; at linkage and data arrangement at execution
 
    mov      #_stacktop, sp        ; set sp register
    mov      #__gp_data, gp        ; set gp register
    mov      #__ep_data, ep        ; set ep register
    add      r28, sp
    add      r28, gp
    add      r28, ep

 

(3)

Initialization of RAM sections

The _INITSCT_RH() function cannot be used for initializing sections when the PID facility is used because the section information table is only for input. Due to this, the initial values are to be directly copied in the startup routine.

The offset between the allocation address of the code area or constant data area at linkage and execution is obtained as an advance preparation. Hereafter, this offset is referred to as the ROM offset value.

    jarl     .pic_base, r29   ; Address of .pic_base label at execution is stored
                              ; in r29
.pic_base:
    mov      #.pic_base, r10  ; Address of .pic_base label at linkage is stored 
                              ; in r10
    sub      r10, r29         ; Value obtained by subtracting r10 from r29 is the
                              ; ROM offset value

 

Next, initialization of sections with initial value is performed.

For a section to be initialized, the start and end addresses of the copy source of the initial value and the copy destination address are stored in the r6, r7, and r8 registers, respectively.

    mov      #__s.sdata32, r6
    mov      #__e.sdata32, r7
    mov      #__s.sdata32.R, r8

 

When the PIROD facility is used, the ROM offset value is added to the start address (r6 register) and end address (r7 register) of the copy source of the initial value.

    add      r29, r6
    add      r29, r7

 

When the PID facility is used, the RAM offset value is added to the address to which data is copied (r8 register).

    add      r28, r8

 

The copy routine is called here because the preparation for copy is completed.

    jarl     _copy4, lp
....
    ; r6: source begin  (4-byte aligned)
    ; r7: source end  (r6 <= r7)
    ; r8: destination begin  (4-byte aligned)
    .align    2
_copy4:
    sub      r6, r7
.copy4.1:
    cmp      4, r7
    bl       .copy4.2
    ld.w     0[r6], r10
    st.w     r10, 0[r8]
    add      4, r6
    add      4, r8
    add      -4, r7
    br       .copy4.1
.copy4.2:
    cmp      2, r7
    bl       .copy4.3
    ld.h     0[r6], r10
    st.h     r10, 0[r8]
    add      2, r6
    add      2, r8
    add      -2, r7
.copy4.3:
    cmp      0, r7
    bz       .copy4.4
    ld.b     0[r6], r10
    st.b     r10, 0[r8]
.copy4.4:
    jmp      [lp]

 

Processing up to this point is repeated for the number of sections that require an initial value.

 

Next, sections with no initial value are initialized with 0. The start address and end address of a target section are stored in the r6 and r7 registers, respectively.

    mov      #__s.sbss32, r6
    mov      #__e.sbss32, r7

 

When the PID facility is used, the RAM offset value is added to the start address (r6 register) and end address (r7 register).

    add      r28, r6
    add      r28, r7

 

The initialization routine is called and the target sections are initialized with 0.

    jarl     _clear4, lp
....
    ; r6: destination begin (4-byte aligned)
    ; r7: destination end  (r6 <= r7)
    .align   2
_clear4:
    sub      r6, r7
.clear4.1:
    cmp      4, r7
    bl       .clear4.2
    st.w     r0, 0[r6]
    add      4, r6
    add      -4, r7
    br       .clear4.1
.clear4.2:
    cmp      2, r7
    bl       .clear4.3
    st.h     r0, 0[r6]
    add      2, r6
    add      -2, r7
.clear4.3:
    cmp      0, r7
    bz       .clear4.4
    st.b     r0, 0[r6]
.clear4.4:
    jmp      [lp]

 

Processing up to this point is repeated for the number of sections that need to be initialized.

 

(4)

Branch to main function

When the PIC facility is used and a jump is to be made to the main function with the FERET instruction, the ROM offset value is added to the value that is stored in FEPC.

    mov      #_exit, lp       ; lp <- #_exit
    mov      #_main, r10
 
    add      r29, lp          ; ROM offset value is added
    add      r29, r10         ; ROM offset value is added
 
    ldsr     r10, 2, 0        ; FEPC <- #_main
 
             ; apply PSW and PC to start user mode
    feret

 

Coding example

A coding example for using the PIC, PIROD, or PID facility is shown below.

$ifdef __PIC
  .TEXT .macro
    .section .pctext, pctext
  .endm
$else
  .TEXT .macro
    .section .text, text
  .endm
$endif
$ifdef __PID
  .STACK_BSS .macro
    .section .stack.bss, sbss32
  .endm
$else
  .STACK_BSS .macro
    .section .stack.bss, bss
  .endm
$endif
 
;-----------------------------------------------------------------------------
;   system stack
;-----------------------------------------------------------------------------
STACKSIZE    .set    0x200
    .STACK_BSS
    .align   4
    .ds      (STACKSIZE)
    .align   4
_stacktop:
 
;-----------------------------------------------------------------------------
;   startup
;-----------------------------------------------------------------------------
    .TEXT
    .public  __cstart
    .align   2
__cstart:
 
$ifdef __PIC
    jarl     .pic_base, r29
.pic_base:
    mov      #.pic_base, r10
    sub      r10, r29
$endif
 
$ifdef __PID
    mov      0xfedf0000, r28       ; Memory address for passing RAM offset value
    ld.w     0[r28], r28           ; Offset (RAM offset) between data arrangement
                                   ; at linkage and data arrangement at execution
$endif
 
    mov      #_stacktop, sp        ; set sp register
    mov      #__gp_data, gp        ; set gp register
    mov      #__ep_data, ep        ; set ep register
$ifdef __PID
    add      r28, sp
    add      r28, gp
    add      r28, ep
$endif
 
    ; initialize 1 data section
$ifdef __PID
  $ifdef __PIROD
    mov      #__s.sdata32, r6
    add      r29, r6
    mov      #__e.sdata32, r7
    add      r29, r7
    mov      #__s.sdata32.R, r8
    add      r28, r8
  $else
    mov      #__s.sdata32, r6
    mov      #__e.sdata32, r7
    mov      #__s.sdata32.R, r8
    add      r28, r8
  $endif
$else
  $ifdef __PIROD
    mov      #__s.data, r6
    add      r29, r6
    mov      #__e.data, r7
    add      r29, r7
    mov      #__s.data.R, r8
  $else
    mov      #__s.data, r6
    mov      #__e.data, r7
    mov      #__s.data.R, r8
  $endif
$endif
    jarl     _copy4, lp
 
    ; initialize 1 bss section
$ifdef __PID
    mov      #__s.sbss32, r6
    mov      #__e.sbss32, r7
    add      r28, r6
    add      r28, r7
$else
    mov      #__s.bss, r6
    mov      #__e.bss, r7
$endif
    jarl     _clear4, lp
 
    ; enable FPU
$if 1 ; disable this block when not using FPU
    stsr     6, r10, 1         ; r10 <- PID
    shl      21, r10
    shr      30, r10
    bz       .L1               ; detecting FPU
    stsr     5, r10, 0         ; r10 <- PSW
    movhi    0x0001, r0, r11
    or       r11, r10
    ldsr     r10, 5, 0         ; enable FPU
 
    movhi   0x0002, r0, r11
    ldsr    r11, 6, 0          ; initialize FPSR
    ldsr    r0, 7, 0           ; initialize FPEPC
.L1:
$endif
 
    ; set various flags to PSW via FEPSW
 
    stsr    5, r10, 0          ; r10 <- PSW
    ;xori   0x0020, r10, r10   ; enable interrupt
    ;movhi  0x4000, r0, r11
    ;or     r11, r10           ; supervisor mode -> user mode
    ldsr    r10, 3, 0          ; FEPSW <- r10
    mov     #_exit, lp         ; lp <- #_exit
    mov     #_main, r10
$ifdef __PIC
    add     r29, lp
    add     r29, r10
$endif
    ldsr    r10, 2, 0          ; FEPC <- #_main
 
    ; apply PSW and PC to start user mode
    feret
 
_exit:
    br      _exit              ;  end of program
 
;-----------------------------------------------------------------------------
;   copy routine
;-----------------------------------------------------------------------------
    ; r6: source begin  (4-byte aligned)
    ; r7: source end  (r6 <= r7)
    ; r8: destination begin  (4-byte aligned)
    .align  2
_copy4:
    sub     r6, r7
.copy4.1:
    cmp     4, r7
    bl      .copy4.2
    ld.w    0[r6], r10
    st.w    r10, 0[r8]
    add     4, r6
    add     4, r8
    add     -4, r7
    br      .copy4.1
.copy4.2:
    cmp     2, r7
    bl      .copy4.3
    ld.h    0[r6], r10
    st.h    r10, 0[r8]
    add     2, r6
    add     2, r8
    add     -2, r7
.copy4.3:
    cmp     0, r7
    bz      .copy4.4
    ld.b    0[r6], r10
    st.b    r10, 0[r8]
.copy4.4:
    jmp     [lp]
 
;-----------------------------------------------------------------------------
;   clear routine
;-----------------------------------------------------------------------------
    ; r6: destination begin (4-byte aligned)
    ; r7: destination end  (r6 <= r7)
    .align  2
_clear4:
    sub     r6, r7
.clear4.1:
    cmp     4, r7
    bl      .clear4.2
    st.w    r0, 0[r6]
    add     4, r6
    add     -4, r7
    br      .clear4.1
.clear4.2:
    cmp     2, r7
    bl      .clear4.3
    st.h    r0, 0[r6]
    add     2, r6
    add     -2, r7
.clear4.3:
    cmp     0, r7
    bz      .clear4.4
    st.b    r0, 0[r6]
.clear4.4:
    jmp     [lp]
 
;-----------------------------------------------------------------------------
;   dummy section
;-----------------------------------------------------------------------------
$ifdef __PID
    .section .sdata32, sdata32
.L.dummy.sdata32:
    .section .sbss32, sbss32
.L.dummy.sbss32:
$else
    .section .data, data
.L.dummy.data:
    .section .bss, bss
.L.dummy.bss:
$endif
 
$ifdef __PIROD
    .section .pcconst32, pcconst32
.L.dummy.pcconst32:
$else
    .section .const, const
.L.dummy.const:
$endif
;-------------------- end of start up module -------------------;