スパイス  組み込み制御装置の受注製作

Hitech-Cコンパイラを組み込み用に移植する
平成26年4月24日

C言語の開始処理(続き2)
 C言語のスタートアップ処理に関して必要な処理内容の説明が終わりました。次は具体的な実装方法について説明します。C言語の開始処理で説明したように、スタートアップ処理では以下の処理を行います。
1.スタックポインタに初期値を設定する
2.割り込み処理アドレスに割り込み処理関数へのジャンプ命令を配置する。
3.初期値の無い(初期値がゼロである)変数の変数領域をゼロにクリアする。
(4.関数main()へジャンプする)

 ここでの疑問は、下記になります。
1.に関して、スタックポインタの初期値には何をセットすればいいか?
2.に関しては、モニタプログラムの移植で説明したようにRAM領域へのジャンプ命令を設定しますので疑問はありません。
3.に関しては、初期値の無い変数のアドレスは具体的には何処から何処までか?

 これらの疑問に対する答えはMAPファイルにあります。Hitech Cでは、Cコンパイラが管理する4つのグループのアドレス範囲をそれぞれ”__L<グループ名>”、”__H<グループ名>”というラベル名で定義してくれます。このアドレス情報を基にしてスタートアップ処理ルーチンを記述します。
 ROM化を指定した場合には、上記のラベルに加えてdataグループの初期値アドレスの先頭を示す”__Bdata”が定義されます(終わりを示すラベルは定義されません)。メモリマップを図にすると次のようになります。


      図(a). デバッグ時のメモリマップ         図(b). ROM化時のメモリマップ

     SPへの設定に関して
 ここでスタックポインタの初期値について、少し書いておきます。Cコンパイラの標準仕様では、スタックに必要なメモリ量をコンパイラに示すことでラベル__Hstackの値を計算させSPに設定するのが本来の使い方です。しかし組み込み用途ではヒープメモリを使用しないことも多く、この場合は製品に搭載されているRAMの上限アドレスをSPに設定することで、変数領域を除く残りのRAM全てをスタック領域として使用する方が合理的です。この方法の欠点は、製品が変わるとRAMの上限アドレスも変わってしまうので、製品ごとにスタートアップルーチンを書き変える必要が出てきます。
 いずれにしても、Hitech Cの使用するアセンブラでは、スタックの使用量を変更するだけでもスタートアップルーチンの修正が必要になります。これは外部から動的にラベルや定数を定義できない(コマンドラインからの定義が出来ない)ので、スタートアップルーチンを汎用的にライブラリ化するのは諦めた方が良いでしょう。無理にしようとすると変数の依存関係が複数のファイルにまたがるのでかえって分かりにくくなります。
(平成26年4月27日追記)
 リンクの段階でSPへの初期値を渡せないかと考えていたら、方法がありましたので内容を変更します。リンカでは各グループの開始アドレスを指定することが出来ます。これに対してSPにはスタック領域の上限アドレス(この場合は終了アドレスに相当)を設定する必要があります。このためスタック領域に見かけ上何も配置しなければ、開始アドレス=終了アドレスとなるので、リンカを介してSPの初期値を設定できます。
(追記ここまで)
 これでスタートアッププログラムを書くことが出来ます。以下にデバッグ用のstart.asと製品ROM化用のstart_r.asの主要部分を示します。
デバッグ用のstart.asリスト(主要部分のみ)
;   Hitech-c for z80(CP/M) startup(CRT)
;
    psect   text,global,pure
    psect   data,global
    psect   bss,global
    psect   stack,global

;   defs    256     ;SP値はリンカで設定する

psect text
__startup:
        JP  __start
        JP  RST8
        JP  RST10
        JP  RST18
        JP  RST20
        JP  RST28
        JP  RST30
        JP  RST38
        JP  NMI
;
__start:
    global _main, __Hstack, __Lbss, __Hbss
        ld sp, __Hstack
;
; 初期値のあるデータをROMからRAMへ転送する
;
;       LD  HL, __Hdata
;       LD  DE, __Ldata
;       XOR A               ;carry clear
;       SBC HL, DE
;       PUSH HL             ;cnt
;       POP BC
;       LD  HL, __Bdata     ;src
;       LDIR
;
; 初期値のないRAMエリアを0クリアする
;
        LD  IX, __Lbss
        LD  HL, __Hbss      ;
        LD  DE, __Lbss
        XOR A               ;carry clear
        SBC HL,DE           ;BSS size
        LD  DE,1
L1:     
        SBC HL,DE
        JP  C,L2
        LD  (IX),0  
        INC IX
        JP  L1
L2:
    call _main
    jp __startup   
製品ROM化用のstart_r.asリスト(主要部分のみ)
;   Hitech-c for z80(CP/M) startup(CRT)
;
    psect   vec,local,abs,pure
    psect   text,global,pure
    psect   data,global
    psect   bss,global
    psect   stack,global

;   defs    256     ;SP値はリンカで設定する

psect vec
        ORG 0
__startup:
        JP  __start

        ORG 08H
        JP RST8

        ORG 10H
        JP RST10

        ORG 18H
        JP RST18

        ORG 20H
        JP RST20

        ORG 28H
        JP RST28

        ORG 30H
        JP RST30

        ORG 38H
        JP RST38

        ORG 66H
        JP NMI
;
psect text
__start:
global _main, __Hstack, __Hdata, __Ldata, __Bdata, __Lbss, __Hbss
        ld sp, __Hstack
;
; 初期値のあるデータをROMからRAMへ転送する
;
        LD  HL, __Hdata
        LD  DE, __Ldata
        XOR A               ;carry clear
        SBC HL, DE
        PUSH HL             ;cnt
        POP BC
        LD  HL, __Bdata     ;src
        LDIR
;
; 初期値のないRAMエリアを0クリアする
;
        LD  IX, __Lbss
        LD  HL, __Hbss      ;
        LD  DE, __Lbss
        XOR A               ;carry clear
        SBC HL,DE           ;BSS size
        LD  DE,1
L1:     
        SBC HL,DE
        JP  C,L2
        LD  (IX),0  
        INC IX
        JP  L1
L2:
    call _main
    jp __startup
タイトル先頭へ 前へ  次へ