CQ-FRK-NXP-ARM (12) Cで書くスタートアップ (1) ― 2015年03月17日 19時21分02秒
昨年、某誌で「アセンブリ言語は極力使わない!ベクタ・テーブル&スタートアップ・ルーチンはCで書く」
という記事があった。これはおもしろいと、とびついたが期待とは違ってアセンブリが普通に使ってあり
タイトルとは異なっていた。(いや、異なっていたわけではないが...)
そこで、私もやってみようと言うわけだ。やるからには某誌のような手抜きではなくフルサポートをしたい。
Cortex-M シリーズは既にアセンブラを使わないスタートアップが普及しているので ARM7 でやってみる。
ARM7 と言えば、私の手持ちでは CQ-FRK-NXP-ARM (LPC2388) しかないのでこれで進める。
とはいっても何かベースとなるものが必要だ。LPCXpresso の cr_startup_lpc8xx.c と Ride7 の crt0_lpc23x.s を参考にする。
さて、最初の問題はジャンプテーブルだ。安直に関数を作りその中にインラインアセンブラで書いてみた。
Cortex-M シリーズだとアドレスなので配列の中に埋め込んでいけばよい。
ところが、ARM7 はここにインストラクションジャンプテーブルが入るので Cortex-M と同じ方法は取れないのだ。
また、この関数は return する必要が無いのでその部分を削除したかったがその方法が分からない。
というわけで、以下の通り。
次は、Reset_Handler だ。この部分の問題はスタックの設定をしなければならないこと。
Cでは直接レジスタを触ることができないはずだからこの部分もインラインアセンブラで書く。(今の所アセンブラだらけだ)
最後は、データエリアの初期化とクロックの設定。
これは cr_startup_lpc8xx.c のソースがそのまま使えるのではないかと思う。
そしてクロックの設定は SystemInit() を呼び出すことにする。
こうしてできたのが以下のソースだ。思ったより短時間でできたがやはりベクタ・テーブルや
Reset_Handler はCで書くのが難しい。タイトルと内容が異なると言われても仕方が無いかな。
今日の所はこの辺で勘弁しておいてやろう!。
残っているのは、リンカースクリプトと SystemInit() 。
Cで書いて移植性をよくするというのが目的だと思うが中身はインラインアセンブラごりごりで
移植性も何も無い感じになってしまった。やはりスタートアップは MPU に依存する部分が多いので
アセンブラで書いても問題ないような気がしてきた。その方が分かりやすいかな?
追記:
__attribute__((noreturn)) ではなく __attribute__ ((naked)) を使えばいいのだった。
これですっきりしたね。上記のソースも修正した。
参照:
LPCXpresso
RAISONANCE Ride7
という記事があった。これはおもしろいと、とびついたが期待とは違ってアセンブリが普通に使ってあり
タイトルとは異なっていた。(いや、異なっていたわけではないが...)
そこで、私もやってみようと言うわけだ。やるからには某誌のような手抜きではなくフルサポートをしたい。
Cortex-M シリーズは既にアセンブラを使わないスタートアップが普及しているので ARM7 でやってみる。
ARM7 と言えば、私の手持ちでは CQ-FRK-NXP-ARM (LPC2388) しかないのでこれで進める。
とはいっても何かベースとなるものが必要だ。LPCXpresso の cr_startup_lpc8xx.c と Ride7 の crt0_lpc23x.s を参考にする。
さて、最初の問題はジャンプテーブルだ。安直に関数を作りその中にインラインアセンブラで書いてみた。
Cortex-M シリーズだとアドレスなので配列の中に埋め込んでいけばよい。
ところが、ARM7 はここにインストラクションジャンプテーブルが入るので Cortex-M と同じ方法は取れないのだ。
また、この関数は return する必要が無いのでその部分を削除したかったがその方法が分からない。
というわけで、以下の通り。
void ResetISR(void){ __asm(" ldr PC, =Reset_Handler\n"); __asm(" ldr PC, =Undef_Handler\n"); __asm(" ldr PC, =SWI_Handler\n"); __asm(" ldr PC, =PAbt_Handler\n"); __asm(" ldr PC, =DAbt_Handler\n"); __asm(" nop\n"); __asm(" ldr PC, =IRQ_Handler\n"); __asm(" ldr PC, =FIQ_Handler\n"); }Cで書いたといっても記述内容はアセンブラそのものだ。他の方法を思いつかなかったのでしょうがない。
次は、Reset_Handler だ。この部分の問題はスタックの設定をしなければならないこと。
Cでは直接レジスタを触ることができないはずだからこの部分もインラインアセンブラで書く。(今の所アセンブラだらけだ)
__asm(" MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit\n" " LDR SP, =_ABT_Stack\n"); __asm(" MSR CPSR_c, #Mode_UNDEF|I_Bit|F_Bit\n" " LDR SP, =_UND_Stack\n"); __asm(" MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit\n" " LDR SP, =_SVC_Stack\n"); __asm(" MSR CPSR_c, #Mode_FIQ\n" " LDR SP, =_FIQ_Stack\n"); __asm(" MSR CPSR_c, #Mode_IRQ\n" " LDR SP, =_IRQ_Stack\n"); __asm(" MSR CPSR_c, #Mode_USR\n" " LDR SP, =_USR_Stack\n");Mode_... を define で宣言したかったがうまく行かないのでこの宣言部分もインラインアセンブラ。
最後は、データエリアの初期化とクロックの設定。
これは cr_startup_lpc8xx.c のソースがそのまま使えるのではないかと思う。
そしてクロックの設定は SystemInit() を呼び出すことにする。
こうしてできたのが以下のソースだ。思ったより短時間でできたがやはりベクタ・テーブルや
Reset_Handler はCで書くのが難しい。タイトルと内容が異なると言われても仕方が無いかな。
今日の所はこの辺で勘弁しておいてやろう!。
残っているのは、リンカースクリプトと SystemInit() 。
Cで書いて移植性をよくするというのが目的だと思うが中身はインラインアセンブラごりごりで
移植性も何も無い感じになってしまった。やはりスタートアップは MPU に依存する部分が多いので
アセンブラで書いても問題ないような気がしてきた。その方が分かりやすいかな?
追記:
__attribute__((noreturn)) ではなく __attribute__ ((naked)) を使えばいいのだった。
これですっきりしたね。上記のソースも修正した。
参照:
LPCXpresso
RAISONANCE Ride7
コメント
トラックバック
このエントリのトラックバックURL: http://syslab.asablo.jp/blog/2015/03/18/7593129/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。