* buntan-pc #5
-(by [[K]], 2025.06.11)
** (0)
-https://github.com/buntan-pc/
-これにかかわる開発の話

** 2025.06.13 Fri #0
-buntan-pcのCPUについて勉強したいっ!
-[Q]っていうか今まで、分からないままアセンブラ作ってたの?
-[A]ええそうなんです。仕様書やサンプルのアセンブラがよくできていて、CPUに対する理解が浅くてもアセンブラを作れてしまったのです・・・。

-まずここを見る。 https://github.com/buntan-pc/buntan-pc/blob/main/cpu/cpu.sv

-たぶんfpがフレームポインタでローカル変数を置けばいいと思う。
-gpはグローバル変数を置けばいいと思う。

-ということは、kharcをこのCPUでやるとしたらこうかな?
 R0:[gp+0], R1:[gp+2], R2:[gp+4], R3:[gp+6],
 A0:[gp+8], A1:[gp+10], A2:[gp+12], RP:[gp+14], SP:fp
-そうすると、こうすればいいかな?
 LodRMd(R0,SP,8);    → LD fp+8; ST gp+0;
 StoRMd(R1,SP,12);   → LD gp+2; ST fp+12;
 AddRI(R2,3);        → LD gp+4; PUSH 3; ADD; ST gp+4;
 CmpJneRII(R0,0,lb); → LD gp+0; NOT; JZ xxx;
-[Q]x86と違って、kharcの1命令がbuntan-pcの2命令とかになっているけど、それはいいの?
-[A]スタックマシンなのでしょうがない。たとえ命令数が2倍でその分遅くなったとしても、kharcが動かせることが大事だって言われるようになりたい。
-まあレジスタマシンで32bitのやつがあればいいなーとは思う・・・。

** 2025.06.14 Sat #0
-[Q]スタックトップの値をR0にすればいいんじゃないの?
-[A]それは一案なのだけど、もしR0の値をどこかにSTしたら、R0はスタックからなくなってしまう。それだと困るので、DUPしてからSTすることになる。そうすると命令数は全く減らない・・・。
-[Q]いやでもさ、R0をどこかに書き込む命令があったとして、その直後にR0へのロード命令があるかどうかを確認して、もしそうならDUPを省略するようにすればいいじゃないか。これでbuntan-pcでも効率よく動かせるんじゃない?
-[A]それもそうだなあ。じゃあfibどうなるかやってみよう。

-以下ではintのサイズが4バイトのままになっているけど、これはもちろん本番では2に直すとする。
 LbI(9); // fib()
  SubAI(SP,24);         ADD fp,-24;
  StoAMd(RP,SP,20);     (なし)          // あえてRPの管理をしないで、CPUの機能に任せるモードを作る。このモードの時はsetjmp/longjmp的なことはしない想定。
  LodRMd(R0,SP,24);     LD  fp+24;
  CgtRI(R0,1);          PUSH 1; LE; NOT;  // GT命令がないので、LE+NOTにした。
  StoRMd(R0,SP,8);      (無視)          // ムダ命令なので無視
  LodRMd(R0,SP,8);      (無視)
  FreI(8);              (無視)
  CmpJeqRII(R0,0,12);   NOT; JZ xxx;      // これはNOTが連続しているので、あとで最適化でNOTを相殺させよう。そして直後にR0へのLodがあるので、DUPは入れない。
  LodRMd(R0,SP,24);     LD  fp+24;
  SubRI(R0,2);          PUSH 2; SUB;
  StoRMd(R0,SP,8);      (無視)
  LodRMd(R0,SP,8);      (無視)
  FreI(8);              (無視)
  StoRMd(R0,SP,0);      ST  fp+0;         // これはDUPするべきか迷うけど、Calの直前もDUPしないということにしよう。
  CalII(9,10);          CALL xxx;
  StoRMd(R0,SP,8);      ST  fp+8;         // 次にR0へのLodがあるので、DUPしない。
  LodRMd(R0,SP,24);     LD  fp+24;
  SubRI(R0,1);          PUSH 1; SUB;      // INCやINC2があるのに、DECはないんだなー。
  StoRMd(R0,SP,12);     (無視)
  LodRMd(R0,SP,12);     (無視)
  FreI(12);             (無視)
  StoRMd(R0,SP,0);      ST  fp+0;         // Cal直前なのでDUPしない。
  CalII(9,11);          CALL xxx;
  StoRMd(R0,SP,12);     ST  fp+12;        // 次にR0へのLodがあるので、DUPしない。
  LodRMd(R0,SP,8);      LD  fp+8;
  LodRMd(R1,SP,12);     LD  fp+12; ST  gp+2;
  AddRR(R0,R1);         LD  gp+2; ADD;    // この時、ST  gp+12; LD  gp+12; のペアが無駄だと気づけるとよい。FreR(R1);があるなら最適化できるなあ。これは対応しよう。
  StoRMd(R0,SP,16);     (無視)
  FreI(8);              (無視)
  FreI(12);             (無視)
  LodRMd(R0,SP,16);     (無視)
  StoRMd(R0,SP,24);     ST  fp+24;        // 次にR0へのLodがあるので、DUPしない。
  FreI(16);             (無視)
 LbI(12);
  LodRMd(R0,SP,24);     LD  fp+24;
  JmpI(13);             (無視)
 LbI(13); // fib().ret: (無視) 
  LodAMd(RP,SP,20);     (なし)
  AddAI(SP,24);         ADD fp,24
  Ret();                RET
-なんとこのルールなら無駄なDUPを生成することは一度もなかった! kharcはスタックマシンに対しても有用ってことかー。最強じゃないか!!
-uchanさんのCコンパイラでコード生成したときと大差ない気がする。

-これ書いてわかった。Cal/RetでRPを使わないモードにするなら、JmpIをCal由来かそうではないか区別できるべきだ。いやでもRPへの代入直後のJmpはCal由来っていう判定基準で十分なのでは?
-そうだな、それで十分だ。これに従わないのなら、CPUの機能に任せるモードを使わないことにすればいい。

-ポインタとか使い始めてA0とかA1とかが出てきたら大変なことになるかもしれないけど、それはその時に考えよう。何かいい案を思いつけるかもしれない。

-GTやGEがないのは不便そうだなーって思ったけど、直前2つのPUSHやLDを入れ替えればLT←→GT、LE←→GEにできるから、問題ないってことかー。なるほど。
-JNZがなくても平気っていうのもたぶん同じ理由だな。
-JNZがなくても平気っていうのもたぶん同じ理由だな。・・・いやそんなことない。左辺と右辺を入れかえても、JNZはJZにはならないぞ?直前の比較を反転させる必要があるのかー。

-今頃になって気づいたけど、fib(20)ってやったら、fib(i-1)の項のせいで、最大で20個のコールスタックが必要になるのかな?(厳密には19とか18とかかもしれないけど)。buntan-pcは耐えられるだろうか・・・。まあ再帰fibをやらなければいいだけなんだけど。
-x86に対してもRP使わないモードっていうのはありだと思う。それで高速化できる可能性はある。

** 2025.06.14 Sat #1
-これのbuntan-pc用のアセンブラ出力を作ってuchanさんに相談すればよさそう。「これくらいの性能のCコンパイラ作ったんだけど、どうかな?」って。
 int main() { return fib(10); }
 int fib(int i) { if (i > 1) { i = fib(i - 2) + fib(i - 1); } return i; }
-余裕だぜ!

-x86のJITコンパイラでRPを使わないでCALL(e8)/RET(c3)で実行させたら、8%くらい速くなったー。fib()ではCALL/RETの実行時間が占める割合は大きいので、こんなにも差が出るのかー。

-uchanさんにアピールすることを考えると、まずやるべきは最適化じゃないかな。余計な記述を消して、こんな品質のコード生成ができるよ、って言うのが先だよね。そのあとでポインタとか配列とか構造体とかやればいい。
-uccはまだ構造体をサポートしてないっぽいので、それをやれば採用確率が上がりそう。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS