Hatena::ブログ(Diary)

七誌の開発日記(旧) このページをアンテナに追加 RSSフィード

新ブログ Twitter OneDrive Wiki

2011-06-25

[]alpha-elf-gccパッチ

坂井さん(@)主催の第12回 IT基礎技術勉強会(7/20 19:00)でまたまたアセンブラが取り上げられます。その関連で「フィーリングで読むアセンブラ入門」執筆の構想もあるようです。調査対象として各種CPUのアセンブリが並んでいるページがあります。Alphaがないのは寂しい(注:現在は追加されています)のでお尋ねしたところ、エラーでうまくいかなかったとのことでした。そのためパッチをまとめました。

昨年Alphaインタプリタを作っていた(id:n7shi:20100731)ときにalpha-elf-gccは使っていましたが、あまり深く考えず適当に修正してビルドを通していました。今まで問い合わせもなかったため、パッチが必須なのを意識していませんでした。

もはやAlphaの需要はないと思いますが、命令セットはきれいなので、比較対象として眺めるのには良いと思います。GP周りが直感的ではなく少し残念ですが、64bit長のアドレスを直書きするのは冗長ですし、即値をコードに埋め込むと再配置が面倒になるので、仕方ないかなと思います。

経緯

2010-07-31

[][][]高速化

id:n7shi:20100727Alphaアセンブラインタプリタ上で動かしましたが、あまりにも遅かったです。使用しているすべてのlibc関数をfopen()等と同じようにF#でインタプリタ側に実装して、ループの無駄等を見直しました。その結果、約10倍ほど高速化しました。

ある種のチートですが、インタプリタ言語ではよくある構造だと思います。Alphaコードの実行はインタプリタのままでJITは行っていません。JITがなくてもこのくらいの速度が確保できれば、簡易Cコンパイラホスティングも視野に入りそうです。

2010-07-27

[][][]逆アセンブラホスティング

C言語Alphaの逆アセンブラ(以下7d)を開発して、id:n7shi:20100712Silverlight化したAlphaインタプリタ上で動かしてみました。デフォルトでDisassembleのタブに出てくるアセンブリが7dの出力です。横のコンボボックスで従来の組み込み逆アセンブラと切り替えられるようになっています。

ファイルの読み書きはlibcをインタプリタ側でシミュレートしています。C言語からはアドレス決め打ちで呼び出して、インタプリタ側でフックして処理を返しています。

void (*exit)(int) = (void *)0x00ef0000;
int (*fputc)(int, FILE *) = (void *)0x00ef0004;
int (*fgetc)(FILE *) = (void *)0x00ef0008;
FILE *(*fopen)(const char *, const char *) = (void *)0x00ef000c;
int (*fclose)(FILE *) = (void *)0x00ef0010;
int (*fwrite)(const void *, int, int, FILE *) = (void *)0x00ef0014;
int (*fread)(void *, int, int, FILE *) = (void *)0x00ef0018;
int (*fseek)(FILE *, long, int) = (void *)0x00ef001c;

2010-07-12

[][][]逆アセンブラインタプリタ

id:n7shi:20100710の方法でVWD2010EEでもF#が使えるようになったので、id:n7shi:20100709でF#に移植したAlphaアセンブラインタプリタSilverlight化しました。

動作はC#版とまったく同じです。XAMLのコードビハインドはC#にして、C#からF#を呼び出しています。F#部分はGUIに依存していないためWindows Forms版と共通のコードです。VWDではF#のインテリセンスが効かないので、インテリセンスの効くVS2008Shellの方で開発を進めるという作戦です。そのためソリューションにはSilverlightとWinFormsのプロジェクトが同居して、F#のプロジェクトを共有しています。

2010-07-09

[][]逆アセンブラインタプリタ

id:n7shi:20100701で開発した逆アセンブラインタプリタをF#に移植しました。Visual Studio 2008 ShellでF# Integrationを使用しています。

SilverlightではなくWindows Formsを使用しています。Silverlight ToolsでF#がサポートされたようですが、Visual Studio 2008 Shellからxapを出力する方法が分からなかったためです。以下のように手動で作成するしかなさそうです。

この方法だとUIデザインやデバッグが大変そうなので断念しました。

【追記】Visual Web Developer 2010 Express EditionでF#のライブラリをビルドする方法が判明しました。 ⇒ id:n7shi:20100710

テーブルの初期化

C#よりもF#の方が自然に書けると感じたのはテーブルの初期化です。

C#ではstaticコンストラクタでテーブルの初期化を行っていました。

public class Alpha
{
    private static string[] regname = new string[32];
    private static ulong[] mask = new ulong[256];

    static Alpha()
    {
        for (int i = 0; i < regname.Length; i++)
            regname[i] = ((Regs)i).ToString().ToLower();

        for (int i = 0; i < 256; i++)
        {
            ulong m = 0xff;
            for (int j = 1; j < 256; j <<= 1, m <<= 8)
                if ((i & j) != 0) mask[i] |= m;
        }
    }
}

F#では定義と同時に初期化コードが書けるため、コードが分断されずに自然だと思いました。以下はC#を直訳したコードです。

let regname =
    let regname = Array.zeroCreate<string> 32
    for i in 0..31 do regname.[i] <- enum<Regs>(i).ToString().ToLower()
    regname

let mask =
    let mask = Array.zeroCreate<uint64> 256
    for i in 0..255 do
        let mutable m = 0xffUL
        let mutable j = 1
        while j < 256 do
            if (i &&& j) <> 0 then mask.[i] <- mask.[i] ||| m
            j <- j <<< 1
            m <- m <<< 8
    mask

maskでのjとmに対する破壊的代入をやめてみます。

let mask =
    let mask = Array.zeroCreate<uint64> 256
    for i in 0..255 do
        for j in 0..7 do
            if (i &&& (1 <<< j)) <> 0 then mask.[i] <- mask.[i] ||| (0xffUL <<< (8 * j))
    mask

配列の要素に対する破壊的代入をやめるため内包表記に書き換えます。

let regname = [| for i in 0..31 -> enum<Regs>(i).ToString().ToLower() |]

let mask = let bittest i j = if (i &&& (1 <<< j)) = 0 then 0UL else 0xffUL <<< (8 * j)
           [| for i in 0..255 -> Seq.sum(seq { for j in 0..7 -> bittest i j }) |]

配列に対するnewが言語機能として用意されていないのに不満を感じていましたが、こういうことだったのかと思いました。

内包表記への書き換えはパズルのように感じました。C#の知識だけでは読み方が分からないので、慣れが必要だと思います。C#でもクエリ式を使えば同じようなことができます。

private static string[] regname = (from i in Enumerable.Range(0, 32)
                                   select ((Regs)i).ToString().ToLower()).ToArray();

private static ulong[] mask = (from i in Enumerable.Range(0, 256)
                               select (ulong)Enumerable.Range(0, 8).Sum(
                                   j => (i & (1 << j)) == 0 ? 0L : 0xffL << (8 * j))).ToArray();

C#でも積極的にこういう書き方をするべきかは悩みます。私は常用するまでには至りませんでした。

2010-07-01

[][][]逆アセンブラインタプリタ

Alphaの命令について調査するため、Silverlightで逆アセンブラインタプリタを作成しました。以下でホスティングしています。ページ上部の[Test1]などのボタンを押すとサンプルを読み込んで実行します。

また、これを作りながらAlphaの命令表をまとめました。

gxemulのtestマシンを参考にしました。testalphaはまだ動かないようですが、OSや実機がなくても命令の調査ができることを教えてもらえました。ちなみにid:n7shi:20091216で取り上げたid:syuu1228さんの独自OS Shiitakeはtestmipsをターゲットとしています。

2010-06-23

[][]Personal Alpha

f:id:n7shi:20100623195147p:image:medium:right

Personal AlphaというAlphaエミュレータでNetBSDを起動してみました。GXemulやQEMUではOSが起動するところまで実装が進んでいないようです。

Personal AlphaはTru64とOpenVMSしかサポートしていないため、そのままではNetBSDは起動しません。クロック(mcclock)とSCSI(asc)で割り込みが掛からないらしく固まってしまいます。クロックは@さんのアドバイスでNetBSD 4.0を使用して、SCSIはid:syuu1228さんのアドバイスでカーネルから外したところ、起動しました。作成したISOイメージを置いておきます。

スクリーンショット

SRM(ファームウェア)からCD-ROMを指定して起動します。

f:id:n7shi:20100623195146p:image:medium

ルートのマウントで固まることが多いです。何度か試していると先に進みます。

f:id:n7shi:20100623195145p:image:medium

無事に起動しても、SCSIを外しているのでインストールすることはできません。

f:id:n7shi:20100623195144p:image:medium

NetBSDを停止させるとSRMに戻って来ます。

f:id:n7shi:20100623195143p:image:medium

SRMでpowerと入力すればエミュレータが停止します。