arm forth

『数学者たちの楽園』(新潮社)なんて本を読んだ。アメリカの長寿番組、 ザ・シンプソンズ って、アニメ漫画があるそうなんだけど、そこの脚本に 数学者達が、色々と仕掛けをしてるそうな。

何故コンピュータ科学者達は、ハロウィンとクリスマスを混同するのか?

答えは、Oct. 31 = Dec. 25

だからってジョーク。

ハロウィンは、10月31日、クリスマスは、12月25日。それを米国風に書くと、上記。 コンピュータ屋は、それを、オクタルの31と、10進数の25と解釈する性質が有る。 よって、両者は同じ数字を表している。

このジョーク、分かる人にしか分からない。でも脚本家は、そういうのを こっそりと忍び込ませて楽しんでいる。見る人達も、そういうこっそりを 真剣になって探す楽しみがあるそうな。

さざえさん家は、そういうエスプリなさそうだもんなあ。

極めつけは、

1782^12 + 1841^12 = 1922^12

なんて言う数式。これが確かか、電卓で計算すると、成り立ってしまうらしい。 普通の人は、よくそんな組み合わせ見つけたねって、感心して終わり。

鋭い人は、 フェルマーの最終定理 がなんたらと言い出すだろう。脚本家はそれを狙って仕込んだ。

お手の物のコンピュータに計算の労力を担って貰ってね。

#include <stdio.h>
#include <math.h>

main(){
  double x,y,i,z,az,d,umin,dmin;
  umin = 0.0000001;
  dmin = -umin;
  for(x=51.0; x <= 2554.0; x++) {
//    printf("[%.1f]", x);
    for (y=x+1.0; y<= 2555.0; y++){
      for (i=7.0; i<= 77.0; i++){
        z = pow(x,i) + pow(y,i);
        if (z == HUGE_VAL){
          printf("[*]");
          break;
        }
        z = pow(z, (1.0/i));
        az = floor(z + 0.5);
        d = z - az;
        if (az == y) break;
        if ((d < 0.0) && (d >= dmin)){
          dmin = d;
          printf("\n%.1f, %.1f, %.1f = %13.10f\n", x,y,i,z);
        } else if ((d > 0.0) && (d <= umin)){
          umin = d;
          printf("\n%.1f, %.1f, %.1f = %13.10f\n", x,y,i,z);
        }
        if (z < (y + 1.0)) break;
      }
    }
  }
  return(1);
}

久しぶりに写経して、理解した。

sakae@debian:~$ ./a.out

280.0, 305.0, 10.0 = 315.9999999269

1279.0, 1347.0, 40.0 = 1351.0000000272

1782.0, 1841.0, 12.0 = 1921.9999999559

2323.0, 2456.0, 65.0 = 2457.0000000168

pow関数の良い使用例になってるな。

最新ARM

たまたま、ARMの本社を訪ねたら、日本語の案内が出てた。昔からそうだったっけ? 日本語、英語、中文って、今のARMの顧客層が分かるってもんです。

それより面白いのは、SoftBank + ARM って所。

次世代スパコン、運用開始1~2年遅れに 半導体開発難しくって記事が出てたけど、ARMな連中が、 石のアーキテクチャ拡張に難色を示しているからだろうね。そこん所は、親分に 調停をお願いしたらどうでっしゃろ?

そして、目出度く仕様が決まったら、 Intel、ソフトバンク傘下になるARMベースのSoC製造へという事で、最新プロセスで製造する。

これぞ、英米日の連合でっせ。近江商人のモットー、三方佳しの実現ですよ。

問題になっていそうなアーキテクチャは、64Bitの拡張についてだろうね。どんな 仕様が公開されてるか知らないので、少しお勉強するか。

仮想 Arm64 マシンの作り方下の 層から上に登っていかれる、有名な方のページ。実ボードを試してみたけど、 「実機を入手するまでもないよ」と考えている人向けに Arm64 の仮想マシンの作り方を紹介します。って、優しいお心使いが嬉しい。

決して、貧ピーーーと、ズバリな事を言わない、奥ゆかしさですね。

で、このページをずーと読み進めて行くと、最後の所で、64Bitの石にリンクしてます。 決してサブルーチンコールではなくて、えーと、ブランチとリンクだったかな。 ARM用語炸裂。

64Bitマシンになって一番変わったのは、汎用レジスタが16本から32本になった事で しょうかね。そうなっても、命令は32Bitに押さえたい。よって、32Bit時代の特徴 フラグの判定と実行の制御を犠牲にした。そして、Bitを浮かせて、レジスタの指定に 割り当てたって事ですかね。なんか、ARMらしさが無くなって、つまんない石に なっちゃった感がするぞ。

きっと、理研の裏にいる富あたりの人は、これに異議を唱えたんでしょうかね。 そんな事されたら、ARMな石じゃ無くなっちゃうぞ、徹底抗戦の構え。 日英の綱引きが、水面下で行われているに違いない。いえ、これは単なる、下衆の 極み、もとえ、勘ぐりですから、真に受けないように。

serial.c

前回見つけた、ARM用のforthコードを見ている。qemuで動かすのに苦労したけど、 その元凶は、serial.cだった。(それと、qemuの特性が実石と違う所)

emacsから、serial.cを眺めると、

/*
 * Initialize serial UART to use GPIO pins 14 (TX) and 15 (RX)
 */
void
serial_init()
{
#ifdef USE_SERIAL_UART0...
#endif /* USE_SERIAL_UART0 */
#ifdef USE_SERIAL_UART1...
#endif /* USE_SERIAL_UART1 */
}

こんな風に見える。後に続く、serial_in_ready()とかも、同様。これって、どう 見たって、本体の定義が無いじゃん。しょうがないので、アセンブル結果である serial.oを、obudumpしてみると、

[sakae@fedora pijFORTHos]$ arm-none-eabi-objdump -S serial.o
Disassembly of section .text:

00000000 <serial_init>:
/*
 * Initialize serial UART to use GPIO pins 14 (TX) and 15 (RX)
 */
void
serial_init()
{
   0:   e92d4070        push    {r4, r5, r6, lr}
#ifdef USE_SERIAL_UART0
    u32 r0;

    UART0->CR = 0;
   4:   e3a06000        mov     r6, #0
   8:   e59f4064        ldr     r4, [pc, #100]  ; 74 <serial_init+0x74>

    r0 = GPFSEL1;
   c:   e59f5064        ldr     r5, [pc, #100]  ; 78 <serial_init+0x78>
serial_init()
{
#ifdef USE_SERIAL_UART0
    u32 r0;

    UART0->CR = 0;
  10:   e5846030        str     r6, [r4, #48]   ; 0x30

    r0 = GPFSEL1;
  14:   e5953004        ldr     r3, [r5, #4]

なんで、こんなコードが湧いて出て来るの? それに、二重定義っぽい。でも よく見ると、PCのだぶりは無い。ここで、密かに、toolchineを疑うはめに。 こういう場合は、大体自分がへまをやってるものだ。しょうがないので、舞台を FreeBSDに移してみたら、ちゃんと、ソースが見られる。

よくよく考えたら、emacsのモジュールとして、ifdefを検出して、ソースを 畳んでくれるやつがうざいので、FreeBSDでは殺していたんだった。fedoraでは 有効になってて、畳まれてた。何と言うお粗末。

それから、objdumpの-Sは、誤動作してるっぽい。欲張らない、-Dだと

00000000 <serial_init>:
   0:   e92d4070        push    {r4, r5, r6, lr}
   4:   e3a06000        mov     r6, #0
   8:   e59f4064        ldr     r4, [pc, #100]  ; 74 <serial_init+0x74>
   c:   e59f5064        ldr     r5, [pc, #100]  ; 78 <serial_init+0x78>
  10:   e5846030        str     r6, [r4, #48]   ; 0x30
  14:   e5953004        ldr     r3, [r5, #4]
  18:   e3c33a3f        bic     r3, r3, #258048 ; 0x3f000

まともに表示した。それから、コードの書き方が勉強になるなあ。

struct uart0 {
    u32         DR;     //_00;
    u32         RSRECR; //_04;
    u32         _08;
    u32         _0c;
    :
    u32         ICR;    //_44;
    u32         DMACR;  //_48;
};
#define UART0           ((volatile struct uart0 *)0x20201000)

非常にすっきりした、旨い書き方だと思うぞ。それにしても、UARTを制御するのに 12本もレジスタが必要なんですかね。

それから、何か設定した時、160サイクル待てってのは、何故?バスの裏側で、 ごにょごにょやってるから? こういう些細な事が気になるぞ。まあ、そんな 事を気にしてたら、先に進まんから、そういう物と割り切るしかないか。

markdown

最近、よくGitHubのお世話になる。Webブラウザーで閲覧してる時はいいんだけど、 一端 clone して手元に持ってくると、README.md あたりが、微妙によみずらい。

このへんてこりんな文書は何? 調べてみたら、 Markdown - Wikipedia

markdownってmarkupに対抗意識を持ってたんだな。そんなのが過去にもunixに 有ったな。more vs. less とか、perl vs. ruby とか、vi vs. emacs とか。 おかげで、ユーザーは選択子が増えて大助かり。

色々な方言が有るのね。オイラーもpikiで原稿を書いているけど、これは、はてな記法 の一部らしい。その原稿をhaskellのアプリでhtmlにしてる。

こちらの方も、何って調べて、GitHub方言を解説されてた。こういう需要が有るのね。 Markdownで行こう! · GitHub

で、GitHubとねんごろになるには、本家がリリースしてるのを使うのが妥当らしい。 Atom凄い!Markdownをリアルタイムでプレビューしながら書ける!HTML出力もできる! そうでしょ、MAC,Windows,Linux上でサポートされたGUIらしいです。こりゃ、オイラー には使えんな。

普通に使うなら、w3mでアクセスしたのをテキストに落としておけばいいんでないかい。 そりゃそうなんだけど、それじゃ当初の目的を果たさない。

こういう時は、何でも揃っている、emacsに助けを求めるべき。ぐぐったら、 EmacsでMarkdown記法での執筆環境を整えた って人が居たので、真似させてもらう。

markdown原稿をhtmlに変換するアプリ、markdown.plが入っていなかったので、pkg から入れてみた。

C-c C-c m で、変換したhtmlファイルの出来栄えが確認出来る。C-c C-c p で、それを ブラウザーに送って、閲覧出来る。勿論、ブラウザーは、w3mを指定してますよ。

Fedoraの場合は、markdownずばりが無かった。FreeBSDから輸入してきても良かったん だけど、それじゃリナだけに頼っているいる人に申し訳ないので、実験。

python3-markdown をインストールして、markdown_py-3をmarkdownにしておけばok。 ウブも同様にすればいいんだろうね。オイラーはうぶじゃなくて、擦り切れているから どうでもいいんだけど。。。

どうでもいいんだけどと言うと、perl vs. python なんてのも有りますなあ。 markdown戦争では、pythonが勝ったようで、OpenBSDでも、Python版が提供されて ました。OpenBSDには鋭い目利きな人が居ますから、勝負有りって所でしょうか。

idle

普通のOSに採用されたARMでは、何もする事が無くなった時に、ジャンプ 自分の所へ、 って無駄な事はしてないだろう。そうじゃなきゃ、電気無駄使いになっちゃうからね。

世のスマホとかipadのOSで、どうなってるか調べてみたいけど、そんなのかなわぬ夢 なんで、OpenBSDで調べてみる。

いきなりだんご(熊本名物)じゃなくて、arch/arm/の下あたりを、アイドル目当てに 探ってみましたよ。そしたら、それらしいのが、cpuswitch.Sに出てました。

/*
 * Idle loop, exercised while waiting for a process to wake up.
 */
ENTRY(cpu_idle_enter)
        mov     pc, lr

ENTRY(cpu_idle_cycle)
        stmfd   sp!, {r6, lr}

        ldr     r6, .Lcpu_do_powersave
        ldr     r6, [r6]                /* r6 = cpu_do_powersave */

        teq     r6, #0                  /* cpu_do_powersave non zero? */
        ldrne   r6, .Lcpufuncs
        ldrne   r6, [r6, #(CF_SLEEP)]

        teq     r6, #0                  /* Powersave idle? */
        beq     .Lidle_return           /* Nope. Just continue. */

        /*
         * Before going into powersave idle mode, disable interrupts.
         */
        IRQdisableALL
        mov     lr, pc
        mov     pc, r6                  /* If so, do powersave idle */
        IRQenableALL

何か有ったらすぐ起きるモードに設定して、仮眠するのかな。石自体にそんな機能が 備わっていたような。

forth

Minimal FORTH compiler and tutorial

: FORTH

Tiny Forthインタープリタ:

06-04.pdf:

Forthを作ってみる2 / 構造を考える

Cannon catとFORTHプログラムによるアプリケーション

前回、armでforthなんてのをやったので、思い出したようにforthの資料を集めてみた。 サラリーマン時代、某田舎言語で、forthを自作して、出張清算の電卓がわりを させていた事が有った。

そんなの、電卓が有れば一発じゃんと言うなかれ。昔は携帯(の中に入っている電卓は 無かった)も無し、持ち運び出来るパソコンも無し、かと言って、電卓を持って行く のも、荷物が増えるので御免こうむりたい。

そこで、自社製品に採用されてる某言語で動くforthを開発して、それを保守用アプリが 入っているフロッピーに入れてた。

出張先で、空き時間を見つけて清算書作成。それを郵送して、お金を振り込んでもらう。その金で、次の出張場所へって具合の、旅からすしてた。

出張費の清算なんで、少数点の端数は出てこない、せいぜい30万円ぐらいまでの、 合計が出せれば、それで事足りた。あこがれの、HPのRPN電卓を真似たって訳。 大活躍してたなあ、あの電卓。そんな事で、forthには思い入れが有るんよ。

jonesforth.sをしげしげと眺めている。arm語のコードだけど、最初にマクロ定義が 有って、後は、そのマクロを駆使して、forthのワード(サブルーチン相当)が、 定義されている。例えば

@ DROP ( a -- ) drops the top element of the stack
defcode "DROP",4,,DROP
        add DSP, DSP, #4        @ ( )
        NEXT

@ DUP ( a -- a a ) duplicates the top element
defcode "DUP",3,,DUP
        ldr r0, [DSP]           @ ( a ), r0 = a
        PUSHDSP r0              @ ( a a ), r0 = a
        NEXT

@ SWAP ( a b -- b a ) swaps the two top elements
defcode "SWAP",4,,SWAP
        POP2 DSP                @ ( ), r1 = a, r0 = b
        PUSHDSP r0              @ ( b ), r1 = a, r0 = b
        PUSHDSP r1              @ ( b a ), r1 = a, r0 = b
        NEXT

defcodeってのは、ワードを定義するためのマクロ。名前と名前の文字数、それに 内部での定義名。次の行からは、そのワードの定義が始まる。DSPとかNEXTとか、 大文字になってるのは、マクロだ。

そして、それがアセンブルされると、下記のようになる。何とも分かり易い。 lispなんかよりも、よっぽど単純で良い。

00010144 <code_DROP>:
   10144:       e28dd004        add     sp, sp, #4
   10148:       eaffffce        b       10088 <_NEXT>

0001014c <code_DUP>:
   1014c:       e59d0000        ldr     r0, [sp]
   10150:       e52d0004        push    {r0}            ; (str r0, [sp, #-4]!)
   10154:       eaffffcb        b       10088 <_NEXT>

00010158 <code_SWAP>:
   10158:       e8bd0003        pop     {r0, r1}
   1015c:       e52d0004        push    {r0}            ; (str r0, [sp, #-4]!)
   10160:       e52d1004        push    {r1}            ; (str r1, [sp, #-4]!)
   10164:       eaffffc7        b       10088 <_NEXT>

もう少し、コードを読んでみるかな。