FC2ブログ

[C言語]undefined reference to '__ashlsi3'

構造体/共用体でレジスタ宣言して、BYTE/BIT両方でアクセス可能にしたい。

struct st_spi { /* struct SPI */
union { /* CTRL */
unsigned int DWORD;
struct {
unsigned int RESV1 :21;
unsigned char SSO :1;
unsigned char RESV4 :1;
unsigned char IE :1;
unsigned char IRRDY :1;
unsigned char ITRDY :1;
unsigned char RESV5 :1;
unsigned char ITOE :1;
unsigned char IROE :1;
unsigned char RESV6 :3;
} BIT;
} CTRL;


こんな構造体を宣言してから、BITアクセスの方法を検討。

SPI.CTRL.DWORD = SPI.CTRL.DWORD | (1<<4);


main関数内で上のように書いたら、エラー無し。
これでCTRLレジスタの4bit目をHに設定出来た。

$ bat.ccomp
INFO : gcc ---------------------------
INFO : as ---------------------------
INFO : ld ---------------------------
INFO : objcopy (srec) ----------------
INFO : objcopy (ihex) ----------------


ちなみにこのバッチは以下でCygwin上で実行してる。

#!/bin/csh -f

set src_name = uart_int

echo "INFO : gcc ---------------------------"
lm32-elf-gcc -c $src_name.c
echo "INFO : as ---------------------------"
lm32-elf-as startup.s -o startup.o
echo "INFO : ld ---------------------------"
lm32-elf-ld -Map $src_name.map -T memory.def startup.o $src_name.o -o $src_name
echo "INFO : objcopy (srec) ----------------"
lm32-elf-objcopy -O srec $src_name $src_name.srec
echo "INFO : objcopy (ihex) ----------------"
lm32-elf-objcopy -O ihex $src_name $src_name.hex



次に、main内の直書きではなくて関数化してみる。

void wr_1bit_h (int * reg_base){
*reg_base = *reg_base | (1<<4);
}


こんな関数を作って、mainから次のように呼び出し。

wr_1bit_h(&SPI.CTRL);


次のようなwarningが出るが、エラーは無い。
ちなみにこのワーニングは調べてみたが解決せず。ポインタの理解が間違っている事だと思うが。
シミュレーションでは、このままでも想定動作してたので一時的に放置。

$ bat.ccomp
INFO : gcc ---------------------------
uart_int.c: In function `main':
uart_int.c:170: warning: passing arg 1 of `wr_1bit_h' from incompatible pointer type
INFO : as ---------------------------
INFO : ld ---------------------------
INFO : objcopy (srec) ----------------
INFO : objcopy (ihex) ----------------




最後に、レジスタアドレスとbit番号を引数で渡すように関数を修正。

void wr_1bit_h (int * reg_base, int bit_num){
*reg_base = *reg_base | (1< }


関数を上のようにして、mainから下のように呼び出す。

wr_1bit_h(&SPI.CTRL, 4);



これをコンパイルすると、「undefined reference to `__ashlsi3'」と出た。

$ bat.ccomp
INFO : gcc ---------------------------
uart_int.c: In function `main':
uart_int.c:168: warning: passing arg 1 of `wr_1bit_h' discards qualifiers from pointer target type
INFO : as ---------------------------
INFO : ld ---------------------------
uart_int.o: In function `wr_1bit_h':
uart_int.c:(.text+0x220): undefined reference to `__ashlsi3'
INFO : objcopy (srec) ----------------
lm32-elf-objcopy: 'uart_int': No such file
INFO : objcopy (ihex) ----------------
lm32-elf-objcopy: 'uart_int': No such file



(2015.2.25追記)
ashlsi3不足に関して良い情報が見当たらない。
今不足している関数について、自分でアセンブラで自作出来ないものか?
そのためには、指定レジスタの指定ビットへHをライトする関数wr_1bit_hについて、
どこの機能が不足してるのか調べる。
リンカで問題あるため最終的なelfは生成されないが、オブジェクトファイルは出来てる。
objdumpで表示してみる。

lm32-elf-objdump.exe -d uart_int.o
 :
000001ec :
1ec: 37 9c ff ec addi sp,sp,-20  → spに-20を加算したものをspへ格納
1f0: 5b 8b 00 0c sw (sp+12),r11  → r11の値をアドレス(sp+12)へ格納
1f4: 5b 9b 00 08 sw (sp+8),fp  → fpの値をアドレス(sp+8)へ格納
1f8: 5b 9d 00 04 sw (sp+4),ra  → raの値をアドレス(sp+4)へ格納
<ここまでで、この関数内で使用するr11、fp、raの値をspへ保存した>

1fc: 34 1b 00 14 mvi fp,20  → addi rd, r0, imm16の疑似命令。r0が0だから省略されてる?
200: b7 7c d8 00 add fp,fp,sp  → add rX, rY, rZ。rYをrZへ加算しrXへ格納
204: 5b 61 00 00 sw (fp+0),r1  → r1の値をアドレス(fp+0)へ格納
208: 5b 62 ff fc sw (fp+-4),r2  → r2の値をアドレス(fp-4)へ格納
20c: 2b 61 00 00 lw r1,(fp+0)  → fpに即値0を加えたアドレスの値をr1へ格納
210: 28 2b 00 00 lw r11,(r1+0)  → r1に即値0を加えたアドレスの値をr11へ格納
214: 34 01 00 01 mvi r1,1  → addi rd, r0, imm16の疑似命令。r0が0だから省略されてる?
218: 2b 62 ff fc lw r2,(fp+-4)  → (fp-4)の値をr1へ格納
21c: f8 00 00 00 calli 21c   → 戻りアドレス「PC+4」をraへ格納。それから21c(=PC+0x30)へ無条件分岐。ここが__ashlsi3に該当する模様。
220: b9 61 10 00 or r2,r11,r1  → r11とr1のORを取って、その結果をr2へ格納
224: 2b 61 00 00 lw r1,(fp+0)  → (fp+0)の値をr1へ格納
228: 58 22 00 00 sw (r1+0),r2  → r2の値をアドレス(r1+0)へ格納

<ここから先で、main関数に戻るためr11、fp、raの値をspから復元させる>
22c: 2b 8b 00 0c lw r11,(sp+12)  → (sp+12)の値をr11へ格納
230: 2b 9b 00 08 lw fp,(sp+8)  → (fp+8)の値をfpへ格納
234: 2b 9d 00 04 lw ra,(sp+4)  → (fp+4)の値をraへ格納
238: 37 9c 00 14 addi sp,sp,20  → spに20を加算したものをspへ格納
23c: c3 a0 00 00 ret  → raのアドレスへ条件分岐



<スタックポインタ定義=0x20000000 +0x2000 -4>

. = 0x20000000 + (1024*8) - 4;
_sp_base = .;



<LatticeMico32 Processor Reference Manual>
ra= call命令における戻りアドレス保存用に使用される。しかしながら汎用レジスタ。
sp= 未使用領域の先頭を指す
fp= アクティブフレームで使用された領域の先頭を指す



参考:スタックポインタ、フレームポインタ
http://www.kijineko.co.jp/tech/creintro/stack.html
スポンサーサイト
カレンダー
01 | 2015/02 | 03
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
累積訪問者
現在の訪問者
現在の閲覧者数:
最新記事
最新トラックバック
最新コメント
月別アーカイブ
カテゴリ
プロフィール

bobgosso

Author:bobgosso
FPGAのブログへようこそ!

検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード