When the PIC, PIROD, or PID facility is used, the following processes in the startup routine need to be changed.
-  | Initialization of base registers  | 
 
-  | Initialization of RAM sections  | 
 
 
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.
 
When the PID facility is used, the RAM offset value is added to the address to which data is copied (r8 register).
 
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).
 
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 -------------------; 
 |