Everything
8.2.2 ユーザ・プログラム向けの初期化ルーチン

ユーザ・プログラム向けの初期化処理は次の要素で構成されます。

サンプルではcstart.asmに配置しています。

 

(1)

スタック領域

コンパイラが生成するコードが使用するスタック領域です。CC-RHは,スタック・ポインタ(sp)の値が4バイト境界に位置していることを前提としたコードを生成し,スタック領域をアドレスの0x0番地方向に成長させます。そのため,スタック・ポインタ(sp)には,.stack.bssセクションの0xffffffff番地側の4バイト境界に整列されたアドレスを指定する必要があります。

STACKSIZE    .set    0x200
    .section ".stack.bss", bss
    .align   4
    .ds      (STACKSIZE)
    .align   4
_stacktop:

 

(2)

エントリ・ポイント

ハードウェア向け初期化ルーチンから分岐してくるラベル(アドレス)です。

    .public __cstart_pm1
    .align  2
__cstart_pm1:

 

(3)

ベース・レジスタ初期化

スタック・ポインタ,gpレジスタ,epレジスタの3つを初期化します。

    mov     #_stacktop, sp      ;  set sp register
    mov     #__gp_data, gp      ;  set gp register
    mov     #__ep_data, ep      ;  set ep register

__gp_data, __ep_dataの詳細は,8.4 シンボルを参照してください。

 

(4)

RAMセクションの初期化

Cソースやアセンブリ・ソース上で定義した変数領域を初期化します。初期化する対象のセクションのアドレスを格納したテーブルを用意し,ライブラリ関数_INITSCT_RHにテーブルのアドレスを渡して呼び出します。

初期値ありデータセクションの初期化テーブルは次の書式で記述します。

    .section ".INIT_DSEC.const", const
    .align   4
    .dw    #__sセクション名1, #__eセクション名1, 
           #__sセクション名1の初期化対象のRAMセクション名
    .dw    #__sセクション名2, #__eセクション名2, 
           #__sセクション名2の初期化対象のRAMセクション名
     :
    .dw    #__sセクション名n, #__eセクション名n, 
           #__sセクション名nの初期化対象のRAMセクション名

 

初期化対象のRAMセクションは,最適化リンカの-romオプションで指定します。

-rom=.data=.data.R
-rom=.sdata=.sdata.R

 

この場合は次のような初期化テーブルの記述になります。

    .section ".INIT_DSEC.const", const
    .align   4
    .dw      #__s.data,  #__e.data,  #__s.data.R
    .dw      #__s.sdata, #__e.sdata, #__s.sdata.R

 

初期値なしデータセクションの初期化テーブルは次の書式で記述します。

    .section ".INIT_BSEC.const", const
    .align   4
    .dw      #__sセクション名1, #__eセクション名1
    .dw      #__sセクション名2, #__eセクション名2
     :
    .dw      #__sセクション名n, #__eセクション名n

 

初期値データを配置するROMセクションと,初期化する対象のRAMセクションのアドレスは,最適化リンカの-startオプションで指定します。

-start=.data,.sdata/00008000
-start=.data.R,.sdata.R/fedf0000
-start=.bss,.sbss/fedf8000

注意

ROM,RAMセクションの配置先アドレスは,デバイスのメモリ・マップに依存します。デバイスのユーザーズ・マニュアルを参照して決定してください。

 

初期化テーブルの先頭アドレス,末尾アドレスを_INITSCT_RHの引数で渡し,初期化を実行します。

それぞれの初期化テーブルの先頭は4バイトに整列している必要があります。

    mov     #__s.INIT_DSEC.const, r6
    mov     #__e.INIT_DSEC.const, r7
    mov     #__s.INIT_BSEC.const, r8
    mov     #__e.INIT_BSEC.const, r9
    jarl32  __INITSCT_RH, lp	     ; initialize RAM area

_INITSCT_RHの使用方法は7.4.11 RAMセクション領域初期化関数を参照してください。

 

(5)

FPUの初期設定

PIDレジスタを参照して,FPUを搭載しているかどうかを確認します。

搭載している場合は,各種の初期設定を行います。

PSW.CU0ビットに1を設定して,FPUを使用可能に設定します。

FPSRレジスタに対してFPUの動作モードの設定を行います。

ロックステップ機能を使用する準備として,FPEPCレジスタの初期化を行います。

    stsr    6, r10, 1        ; r10 <- PID
    shl     21, r10
    shr     30, r10
    bz      .L1              ; detect 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:

FPUを使用しないプログラムでは,これらの記述を削除してください。

 

(6)

例外処理の初期設定

PSW.IDビットに0を設定して,例外発生を許可します。

PSW.UMビットに1を設定して,ユーザ・モードへ遷移します。

main関数への分岐と同時に設定を反映させるために,PSWではなくFEPSWへ書き込み,feret命令でFEPSWからPSWへ設定を反映させます。

    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

 

(7)

main関数への分岐

FEPCレジスタにmain関数のアドレスを,r31レジスタにmain関数の実行が終わった後に実行したい_exit関数のアドレスを設定して,feret命令を実行することでmain関数へ分岐します。

    mov     #_exit, lp       ; lp <- #_exit
    mov     #_main, r10
    ldsr    r10, 2, 0        ; FEPC <- #_main
    feret