巣鴨でトゲ抜き

巣鴨というと「とげぬき地蔵」を思い浮かべる。
そして、なぜか毒蝮三太夫も一緒に頭に浮かぶ。
トゲは漢字で「刺」とか「棘」とか書くらしい。
今まで書いたこともないし、
いきなり出てきたら読みもあやふやだ。
唐突ではあるが、今月のインタフェースをちょっとみてみよう。
特集は「ゼロから作るOS」とあり、まぁこちらの専門分野だ。
Interface 2023年7月号
「IEEE で標準規格になった。」2018 年と書いてある。
知らなかった。で、どういう標準規格のだろうか?
どこを参照したらいいのだろう?
記事とIEEEの関連性が(現時点では)不明だが(読みながら書いてるんでね)、
その先を進めよう。
Windows の NT Kernel について記述がある。あ、竹岡さんのコラムだった。
RISC-V には PMP というのがあるのか。
勉強になる。
第1章は RTOS の話だ。そういえば 1980 年代にインタフェースの記事を
読んで RTOS を勉強したのを思い出した。当時はタスクなんて言葉を使ってた。
いまもタスクなのか。
第2章で IEEE に準拠するという話が出てくる。
IEEE 2050-2018 は日本の TRON をベースにしているらしい。
あれ〜 tk_cre_tsk? まじかよ。T-Kernel じゃん。
余談だけど、T-Kernel の提唱者はどうも PC-9801 のモニターを
雛形にしてものを作ろうとしているようだ。
そして、ARM のレジスタの使い方(コンベンション)を無視して
作られている(サンプル実装?)
シーラカンスのような仕様と実装はやめてほしい。
イベント・フラグとセマフォかよ。
セマフォはともかく、なんでイベント・フラグなんていう
退行した API 使わなきゃならんのよ。
POSIX には(pthreadには)ちゃんとした cond_wait に代表される
条件変数での制御が規定されている!!!
これもう30年前の話で、決着ついてるはずなのに、、、
この感じだと IEEE はロビー活動の結果であって、
技術的に素晴らしいから採用されたわけじゃなさそうだぞ
(現時点の感想です)。
RTOS でバグの少ない見通しのよいプログラムを書くには
  • 順序性のあるものを切り分けること
  • 優先度の高い処理を明確にすること
この2つが大事だ。
とりわけ、初期化処理に代表される
「順序性のあるものの」
切り分け、切り出しは重要。
典型的な初期化処理では順序性がある。例えば、
1 → 2 → 3 → 4 → 5
これをイベント・フラグとかで実装しちゃうと
case 文使ったりして混乱してしまう。
ソースが汚くなる。
本来、順序性があって、一本道なのを
わざわざ case 文で分断してしまう。
もちろん、case 文を上から実行していくんだよという
風に書くことも出来る。
kaffe のソースは(昔読んだんだけど)、そうなっていて
感心した。そういう書き方も出来るんだなぁと。
技量があれば case 文を使ってもきれいに書くことは出来る。
しかし、複数の人が関わり、メンテナンスする RTOS の
アプリに case 文を入れると、
日本のソフトウェア業界の悪しき文化、
古いソースのコメント化と謎の担当者名+日付のコメントと
あいまってどんどん汚くなってくる。
最初から cond_wait を使いましょう。
cond_wait は semaphore と mutex の組み合わせでかけるので、
RTOS で最初に実装する関数は cond_wait だ。
これ、たぶん30年くらい前からの(私の)定番。
iTRON 系の OS が来たら、semaphore と mutex で cond_wait つくって
アプリケーションではフラグとかメッセージとか使わない。
cond_wait 使えば普通のプログラムになるんだよ!!
次に重要なのが「優先度の高い処理を明確にすること」。
RTOS いれても、全部同じ優先度にしたら、ポーリングと変わらないからね。
これ、理解してもらえなかったお客もいる。トホホ。
RTOS でアプリを組むから
リアルタイムなアプリケーションになる
のではなく、、、
RTOS 上で正しく優先順位をつけたタスクに分割するように
設計して記述するから、
リアルタイムなアプリケーションになるのよ。
よく見る間違いに、フラグやメッセージで管理してタスク分けして
制御順があやふやになってくると delay 入れたりして調整。
みたいなプログラム。
当たり前だけど、だめだから。

結論

mutex や semaphore は単体だと
すれ違いも起こしやすく
使いづらい。
そのために POSIX では cond_wait を規定していて
使いやすいインタフェースを用意している。
順序制御は cond_wait 一択で OK!!
イベント・フラグなんて使うな!!
(メッセージボックスは私も使うときがある。
ネットワーク系と相性がいいから)

30年前のバグを誘発しやすい API !!

その先読んでないから(読む気がなくなった)。
ちゃんとしたリカバリーがされているのかもしれないが。
現時点では(先読んでないからね)、だめすぎて相当がっかり。
相当過激な意見だから、他の専門家(TさんとかIさんとか)の意見ももらって
チェックしたい。

(このページを勝手に参照するのは不可。ちゃんと口頭で説明したい)
プログラミング学園も読んでおこう。
宇宙の数式
いい記事な気がする(深く読んでない。読むだけの知識がない)。
最初から読みたいから pdf でまとめほしいよ。

Forth と RISC-V

本当はこっちをメインで書きたかったんだけど
もう力尽き気味だよ。
CPU をつくりたいならまず Forth を検討しましょう。
Verilog でも書けますし、
Synthesijer でも Polyphony でも書けます。
FPGA の初学者にはとくに
HLS(High-level synthesis) で書くことをおすすめします。
私は以前、がんばってパタヘネをみながら VHDL で
独自CPUを
作ろうと思ったのですが、あっさり断念しました。

パイプラインとか複雑すぎ。
パタヘネとかみるとパイプライン化しないまでも
こんな絵が出てくるよね。
高位合成で書けばパイプライン考えなくて済みます。
パイプラインを考えなくていいのか?
それでいいのかという本質的な問題はある。
Polyphony で書けば Python で次のように書けます(抜粋です)。
簡単!!
   if opcode <= 30:
      if   opcode ==  0:   # nop
        pass

      elif opcode ==  1:   # lit
        ip += 1
        stack.push(memory[ip])

      elif opcode ==  2:   # dup
        stack.push(stack.top)

      elif opcode ==  3:   # drop
        stack.pop()

      elif opcode ==  4:   # swap
        stack.swap()

      elif opcode ==  5:   # push
        address.push(stack.pop())

      elif opcode ==  6:   # pop
        stack.push(address.pop())
CPU が出来たら今度はソフトウェアです。
qiita に素晴らしい記事が上がっています。
機械語手書きから言語処理系をブートストラップする
これみながらアプリの環境を作れば、コンパイラとかアセンブラとか必要ありません。
Forth をつくる!! 
是非、みなさんもトライしてみましょう!!
いやいや Forth 今更作ってどうする。
という人は RISC-V でしょう。
これも Polyphony で Python 言語でかけちゃいますよ!!
        if opcode == 0x63:
            if funct3 == 0:
                if self.get_reg_v(rs1) == self.get_reg_v(rs2):
                    self.pc += int32__31__7_30_25_11_8x2
            elif funct3 == 1:
                if self.get_reg_v(rs1) != self.get_reg_v(rs2):
                    self.pc += int32__31__7_30_25_11_8x2
            elif funct3 == 4:
                if self.get_reg_v(rs1) < self.get_reg_v(rs2):
                    self.pc += int32__31__7_30_25_11_8x2
            elif funct3 == 5:
                if self.get_reg_v(rs1) > self.get_reg_v(rs2):
                    self.pc += int32__31__7_30_25_11_8x2
            elif funct3 == 6:
                if cmp_32u(self.get_reg_v(rs1), self.get_reg_v(rs2)) == 1:
                    self.pc += int32__31__7_30_25_11_8x2
            elif funct3 == 7:
                if cmp_32u(self.get_reg_v(rs1), self.get_reg_v(rs2)) == -1:
                    self.pc += int32__31__7_30_25_11_8x2
            else:
                illegal_op = True
基本的な構造は Forth も RISC-V も同じです。
Python の if elif else のカタマリ。
その書き方どうなの?という気がしなくもないですが、
とにかく簡単に出来るからおすすめ。
ただし、スピードは出ません。Toy CPU です。
RISC-V を試すなら gowin の FPGA は候補の一つになると思います。
なんといっても安い!!
そして、RISC-V もついてくる。
CPU を作ったことにはならないかもしれませんが、
Gowin + RISC-V の環境で周辺機器を作ると
CPU 周りの理解が深まりますね。
詳しくはこちら(CMでした。まぁCMしてもべつに収入にはなりませんが)
2022年12月号 別冊付録2500円ボードで始めるFPGA開発
CPU に興味がある人だったら次の分野も興味ありそうですね。
  • OS
  • コンパイラ
であれば、ぜひ Lisp と Forth は押さえておきましょう。特に Lisp。
幾つかの大学で(多くが国公立)CPU実習なるものの講義があります。
私の記憶では東大が始めたと記憶してます。
iTRON の成功の一環ですね。
これがあるから今の日本に多くの優秀な技術者が育っている。

コンピュータ哲学

もうほとんどギブアップですが(書くの疲れてきた)、、、
「CPU演習」と似たような講義に関する資料は 1990 年代のはじめから
あります。
この辺がその走りじゃないですかね?
MIT の教科書だったらしい。
Turbo Pascal だからオワコンですが。
SICP もその一つかな。
やさしいコンピュータ科学
この手の本は今やいっぱい出ていて、
最近でも日本の著者で OS と CPU 作る的な本が複数ある。
詳しく紹介したいところですが、
もう力尽きたのでこのへんで終了。