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