H8/3052F をGNU環境でアセンブリする
今年の更新は、H8/3052FをGNU環境でアセンブリすることについて。
研修で、HEWとルネサス純正コンパイラを用いてH8/3048Fを扱った。純正コンパイラは高いので頑張ってGNU環境で出来るようにする。半年前に、どこかのページを参考にして h8300-hms-gcc など環境を整えた。(もうどうやったか覚えてない。cygwin 上で動かしている。)
とりあえず、研修で覚えたアセンブリで動かすことが目標。ボードは秋月電子のH8/3052Fの開発セット。
プログラム本体
; startup.s .h8300h .equ P5DDR, 0xFFFC8 .equ P5DR , 0xFFFCA .globl LED .section .text LED: mov.l #0xFFF00, sp ; ポート5 0,1を出力モード ;bset #0, @P5DDR ;bset #1, @P5DDR mov.b #0x03, r0l mov.b r0l, @P5DDR ; LED0,1を点灯 ;bset #0, @P5DR ;bclr #1, @P5DR mov.b r0l, @P5DR EXIT: bra EXIT .section .vectors .data.l LED .END
純正のコンパイラ(?)との違いについて
- 数値記述法
- #H'FFFFF が #0xFFFFF
- EQU文
- (ラベル: .EQU 数値) が (.equ ラベル, 数値)
- レジスタ名が小文字限定
.global が .globl- 嘘でした。ごめなさい。
- 8ビット絶対アドレス内でもメモリ上のアドレスに対しbsetなどビット演算子が使えないっぽい
- .section でアドレスの開始指示の仕方が不明
- .res系が使えない??.byteなどを使うのか?(未確認)
参考: http://akita-nct.jp/~yamamoto/comp/H8/ASM_linux/ASM_linux.html
リンカスクリプト
/* linkerScript.x */ SECTIONS { . = 0x00000; .vectors : { *(.vectors) } . = 0x00100; .text : { *(.text) } }
初めて自力で書いたので、こんなもん^^;まぁいいかw
参考: http://www.sra.co.jp/wingnut/ld/ld-ja_3.html
Makefile
PROJECT = led OBJS = startup.o LINKS = linkerScript.x LDFLAGS = -Xlinker -Map -Xlinker $(PROJECT).map CC = h8300-hms-gcc OBJCOPY = h8300-hms-objcopy $(PROJECT).mot : $(PROJECT).coff $(OBJCOPY) -O srec $^ $@ $(PROJECT).coff : $(OBJS) $(CC) -o $@ -T $(LINKS) -nostdlib $(OBJS) $(LDFLAGS) startup.o : startup.s $(CC) -c $^ clean : rm -f *.o *.mot *.coff
最低限の使い方がわかったので、後は
*'``・* 。 | `*。 ,。∩ * + (´・ω・`) *。+゜ もうどうにでもなーれ `*。 ヽ、 つ *゜* `・+。*・' ゜⊃ +゜ ☆ ∪~ 。*゜ `・+。*・ ゜
アドエスでニコニコ動画が観たかったんだ。。
あけましておめでとうございます。今年もよろしく^^たまには更新しようと思いこのページにやってきたら6記事前は2005年に書いたものでした。月日の早さには僕もビックリです。
さて、Willcom の Advanced/W-ZERO3[es] が学生向きに安くなっているので買いました^^色々ソフトをいれて遊んでいるのですが、どうやらニコニコ動画は観れないらしい。。。しょうがないので、少し(ものすごく?)妥協して一度パソコンでみたことあるニコニコ動画の動画をコメントなしでアドエスで見れるようにした^^;一度観たことがある動画をコメントなしで見る価値がどのくらいあるのか、自分でもかなり微妙だけどとりあえず出来たので書いておこう。
- nicoCacheを導入してflvファイルをcacheに保存
- Orbを導入して動画公開フォルダに上記のcacheを設定
- アドエスでアクセスする
以上終わり!細かい説明は省略です。動画配信のエンコード(Orb配信)のところでCPUパワーをたくさん使います。本当は、動画をコメント付で保存することが出来るψ(プサイ)さんの「さきゅばす」というソフトを配信時に挟むと(リアルタイムでコメントを反映させるのは難しいしCPUいっぱい食うだろうけど)それっぽく見せられそうですね。
では、また数ヵ月後にお会いしましょう。
D言語でGnuplot 2
Cygwin用のgdcでコンパイルしたものは、実行速度がやけに遅かったので、Windows用バイナリが作成されるようMinGW + gdc をインストールしてみた。こちらでもちゃんと、popen も pclose も使えたのでやっぱり dmd の設定が悪かったのかなぁ。せっかくの機会だったので、Windows上の各コンパイラで作った実行ファイルの実行速度をtimeコマンドを使って測ってみた。このプログラムの内容は、ファイルを読み込み、読み込んだ値をクラスのメンバーに入れたあと、すべてのオブジェクトのあるメンバーにアクセスする、という内容。読み込んだファイルのサイズは約4.5MBのテキスト。
$ time ./WinGdc.exe real 0m16.760s user 0m0.031s sys 0m0.031s $ time ./WinDmd.exe real 0m16.299s user 0m0.031s sys 0m0.031s $ time ./LinGdc.exe real 1m57.082s user 0m45.484s sys 1m11.202s
WinGdc.exeはWindows用gdc(MinGW用gdc)でコンパイルしたもの。WinDmd.exeはWindows用dmdでコンパイルしたもので、LinGdc.exeはCygwin用gdcを用いてコンパイルしたもの。約8倍速度が違うことがわかる。恐ろしや。。
D言語でgnuplot
前回、ファイルからデータを読み込んで処理を加えることができたので、今度はそれをグラフにしてみることを考える。今までC++を使っていたので、CERNのROOTを読み込んでグラフを作っていたがD言語では使えないので、とりあえずパイプを使ってgnuplotを動かそうとした。C言語でいうpopenとpcloseのようなものを使えばいいが、結論から言ってわからなかった^^;しょうがないから、extern (C) を用いてCのpopenとpcloseを用いることにする。
とりあえず、popenとpcloseが使えるかどうかを確認。
import std.c.stdio; extern (C) FILE *popen(char *cmd, char *type); extern (C) int pclose(FILE *fp); int main(char [][] args) { FILE *gp; gp = popen("gnuplot -persist","w"); fprintf(gp,"plot sin(x)\n"); pclose(gp); return 0; }
これを、DMD 2.0 Windows版でコンパイルするが、Error 42: Symbol Undefined _popenと_pclose と出てリンクエラー。ここで数日悩む^^;C言語をバイナリは共通とのことなので、Cygwinのgdcを試すとうまくいった^^;例によってCygwinのgdcはまだバージョンが古いので公式サイトからCygwin用のgdc最新バージョンを導入する。うまくいくwとりあえずこれ(cygwin用gdc最新版)でコンパイル自体は上手くいった。X Windowを立ち上げて、実行してみるとgnuplotが立ち上がってsinカーブがちゃんと出てしばし感動w使い方がわかったので、自分の作ったものに組み込んでみると、実行速度が遅い^^;
Windows 上で dmd でコンパイルするとある環境では11秒で終了。gdc だと71秒^^;オワタ。。。試しにLinux上でdmdとgdcを入れて確認してみると、こちらはどっちも11秒。あぁ、つまりCygwin通してるから遅いのかと納得。よって、Windows版 dmd でpopenがきちんと使えるようにすれば多分実行速度が速いであろう。ってなわけで、なぜかWin版dmdで popen がリンク出来ないので設定などを確認してみようと思う。
ファイル出入力
設定ファイルを読み込みパラメータをセッティングするために、ファイルの出入力部分を作ってみた。
ファイルオープン
とりあえず、テスト用 inputFile.dat は以下のような形式だと仮定。
001 North 0x0a 002 South 0x0b 003 East 0x0c (以下同様).. .. ..
まずは、ファイルオープン。
import std.cstream; import std.stream; import std.c.stdio; import std.string; int main(char[][] args) { char [] input = "inputFile.dat"; File fp = new File(input,FileMode.In); // process.. fp.close(); return 0; }
引数使えよ。って突っ込みはなしで^^;
読み込み実装1
実際に読み込む部分の実装方法1。foreachを使って読み込んでみる。ファイルの最初から最後まで同じ形式のファイルならばいけるけれど、普通はそんなことないから、実用的ではないかも。
int i = 0; int [] number1,number2; char *c_type; char [][] direction; char [] tmp; c_type = toStringz(tmp); foreach(char [] line; fp){ number1.length = number1.length + 1; number2.length = number2.length + 1; direction.length = direction.length + 1; sscanf(toStringz(line),"%d %s 0x%x",&number1[i],c_type,&number2[i]); direction[i] = toString(c_type).dup; i++; }
なぜ、number1.lenght += 1 が使えないのだろう。。。C言語のsscanfと同じような機能をもったD言語の関数を見つけられなかったのでC言語のsscanfを利用。文字列の扱いがC言語とD言語で違うためtoString()とtoStringz()を用いてCとDの文字列のやり取りをしている。あと、基本的にD言語の配列のコピーを使いたいときは、.dupをつけないと参照先が同じため一箇所変更を加えると全部変わってしまうので注意。
読み込み実装2
行ごとに読み込むのではなく、1単語ごとに読み込んで処理する。フラグなど立てておけば分岐が出来るのでこっちのほうが色々できそう。
int i = 0; int [] number1,number2; char *c_type; char [][] direction; char [] tmp; char [] line; c_type = toStringz(tmp); int mode = 0; while(1){ fp.readf("%s",&line); if(fp.eof()) break; switch(mode){ case 0: number1.length = number1.length+1; sscanf(toStringz(line),"%d",&number1[i]); mode++; break; case 1: direction.length = direction.length + 1; sscanf(toStringz(line),"%s",c_type); direction[i] = toString(c_type).dup; mode++; break; case 2: number2.length = number2.length+1; sscanf(toStringz(line),"0x%x",&number2[i]); mode = 0; i++; break; } }
それにしても、もっと上手にやる方法を考えなくては^^;まだ全然わからん^^;