FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

xv6を移植するときに書き換えるルーチンについて調査(2)

xv6はx86用に実装されているのだが、それを他のアーキテクチャに移植する場合に、何が必要かについて調査している。 最近は仕事も忙しくて、まったく調査できていなかったのだが、少し時間ができたので、続きをやっていこう。

msyksphinz.hatenablog.com

cpuステータス変数について、コンパイル時にハマったこと

proc.hには、以下のように定義されている。これに気が付かずに、結構長い時間ハマってしまった。

  • proc.h
// Per-CPU state
struct cpu {
  uchar id;                    // Local APIC ID; index into cpus[] below
  struct context *scheduler;   // swtch() here to enter scheduler
  struct taskstate ts;         // Used by x86 to find stack for interrupt
  struct segdesc gdt[NSEGS];   // x86 global descriptor table
  volatile uint started;       // Has the CPU started?
  int ncli;                    // Depth of pushcli nesting.
  int intena;                  // Were interrupts enabled before pushcli?

  // Cpu-local storage variables; see below
  struct cpu *cpu;
  struct proc *proc;           // The currently-running process.
};

// Per-CPU variables, holding pointers to the
// current cpu and to the current process.
// The asm suffix tells gcc to use "%gs:0" to refer to cpu
// and "%gs:4" to refer to proc.  seginit sets up the
// %gs segment register so that %gs refers to the memory
// holding those two variables in the local cpu's struct cpu.
// This is similar to how thread-local variables are implemented
// in thread libraries such as Linux pthreads.
extern struct cpu *cpu asm("%gs:0");       // &cpus[cpunum()]
extern struct proc *proc asm("%gs:4");     // cpus[cpunum()].proc

GSというのは、Gセグメントの略称らしい。GはFの次、ということ?

X86アセンブラ/x86アーキテクチャ - Wikibooks

FSやGSはこの決まりの例外となっており、スレッド独自のデータを指し示すのに使われる。

このgsレジスタが各コア用のcpu変数を持っている。さらにオフセットを4つずらすことで、procを参照している?そんな馬鹿な。

Gnu Assembler

%gs:foo [gs]:[foo] セッションは"%gs"で示され、オフセットは変数"foo"の内容で示される。

とりあえず、移植するときはgsは省略するようにした。

extern struct cpu *cpu;       // &cpus[cpunum()]
extern struct proc *proc;     // cpus[cpunum()].proc

trapframeの移植について

trapframeはx86用に定義されている。これをRISC-V用に移植するとどうなるだろう。

//PAGEBREAK: 36
// Layout of the trap frame built on the stack by the
// hardware and by trapasm.S, and passed to trap().
struct trapframe {
  // registers as pushed by pusha
  uint edi;
  uint esi;
  uint ebp;
  uint oesp;      // useless & ignored
  uint ebx;
  uint edx;
  uint ecx;
  uint eax;

  // rest of trap frame
  ushort gs;
  ushort padding1;
  ushort fs;
  ushort padding2;
  ushort es;
  ushort padding3;
  ushort ds;
  ushort padding4;
  uint trapno;

  // below here defined by x86 hardware
  uint err;
  uint eip;
  ushort cs;
  ushort padding5;
  uint eflags;

  // below here only when crossing rings, such as from user to kernel
  uint esp;
  ushort ss;
  ushort padding6;
};

すべてのレジスタを定義して、プロセスが切り替わるときに退避するときに利用するとしたらこうなるだろうか。

//PAGEBREAK: 36
// Layout of the trap frame built on the stack by the
// hardware and by trapasm.S, and passed to trap().
struct trapframe {
  // registers as pushed by pusha
  uint ra;
  uint s0;
  uint s1;
  uint s2;
  uint s3;
  uint s4;
  uint s5;
  uint s6;
  uint s7;
  uint s8;
  uint s9;
  uint s10;
  uint s11;
  uint sp;
  uint tp;
  uint v0;
  uint v1;
  uint a0;
  uint a1;
  uint a2;
  uint a3;
  uint a4;
  uint a5;
  uint a6;
  uint a7;
  uint t0;
  uint t1;
  uint t2;
  uint t3;
  uint t4;
  uint gp;

  uint mepc;
  uint mcause;
  uint mstatus;
};

このときに、mepc, mcause, mstatusを対比しているが、ここは勉強不足で疑問が残る。mxxxレジスタはマシンモード時のステートを保存するためのシステムレジスタだが、実際にプロセスが実行されるのはユーザモードの時ではないのか?そうすると、ユーザモードの状態を保持しているシステムレジスタを保存するのが適切ではないだろうか。 あるいは、すべてのレジスタを保存しておくべきかなあ。

xchgの代替にはamoswapを使う?

xchgについても、まだ勉強不足で分かっていないのだが、同様の機能を持っているものとしたらRISC-Vだとamoswapが使えるかもしれない。

static inline uint
xchg(volatile uint *addr, uint newval)
{
  uint result;

  // The + in "+m" denotes a read-modify-write operand.
  asm volatile("lock; xchgl %0, %1" :
               "+m" (*addr), "=a" (result) :
               "1" (newval) :
               "cc");
  return result;
}
  • riscv.h
static inline uint
xchg(volatile uint *addr, uint newval)
{
  uint result;
  asm volatile ("amoswap.w %0, %0, (%1)":
                "=r" (result), "+r" (*addr) :
                "r" (newval));
  return result;
}

「ガベージコレクション 自動的メモリ管理を構成する理論と実装」を買った

これは本屋に行ったときに何も考えずに面白そうだから買った(笑)

結構難しそうだ。

ガベージコレクション

ガベージコレクション

この手の本は積読になりそうなので、そうならないように頑張ります。 分かったことがあれば、日記に書いてみたり、GitHubに上げてみたりしよう。

関係ないけど、今はこれを読んでいるよ。AMDのアウトオブオーダ実行についてかなり詳しく書いてある。

Chip Architect: Detailed Architecture of AMD's Opteron

翻訳を少しずつGitHubにアップロードしている。

github.com

「ドキュメント作成システム構築ガイド」を購入(RedPenをカスタマイズしてみる)

前のブログでもちょっと書いたけど。

ドキュメントと仕様書(一緒か)、そして実装は常に一体であるべき、というのは基本的な考え方。 ドキュメントから実装が生成される、実装からドキュメントが作られる、というのは究極の理想だけど、もうちょっとドキュメント作成が簡単になればね、ということで購入。

主に内容はMarkdownやAsciiDoc、さらに著者らが開発に参加しているRedPenなどの使用方法の紹介。GitHubによるドキュメント管理の方法からgitの使い方まで書いてあるけど、簡単すぎるので省略。 一番しっかり読んだのはRedPenの使い方の部分だ。キュメントを書くときはAsciiDocかSphinxを使うつもりだから、AsciiDocとAsciiDoctorの部分もしっかり読まなければならない。 とりあえず現状は今ある文章を校正しなければならないということでRedPenに注力。

RedPenで今ある文章を校正してみる

これは前回もやった。前回はネットの情報だけで試してみたけど、今回は書籍も買ったし、いろいろカスタマイズできるはずだ!

msyksphinz.hatenablog.com

トライしたのは、例によって数年前に翻訳したxv6のドキュメントである。

github.com

MingWでRedpenを使える環境を構築する

書籍の中では、RedPenのインストール方法としてMacOS XLinuxしか書いていなかった。ちょっとー、Windows使っている人だってたくさんいるんだよ!むしろ、WindowsのWordか何かで書いている人たちをRedPenに移行させたいなら、Windowsでの環境構築手順をしっかりしないと意味ないんじゃないかなあ?大企業でMac使っているところなんて、聞いたことがない。

といっても、MingWをインストールしているので、特に困ったことはなかった。RedPenのパッケージをダウンロードして、パスを通し、Javaをインストールすればそれで終了だ。 MingWの.bashrcに、以下を記述していればそれで終了。

export PATH=/c/Program\ Files\ \(x86\)/Java/jre1.8.0_77/bin/:${PATH}
export PATH=~/work/redpen-distribution-1.5.4/bin:${PATH}
export JAVA_HOME=/c/Program Files (x86)/Java/jre1.8.0_77/

一文字の接続詞で死ぬほど怒られる

エラーの大半は"DoubledWord"という、文章内に同じ文字を連続して書いてしまった時のものだ。

chapter0.md:6: ValidationError[DoubledWord], 一文に二回以上利用されている単語 "動作" がみつかりました。 at line: オペレーティングシステムはハードウェアを分割させ、多くのプログラムがコンピュータを共有し同時動作(もしくは動作しているように見える)を実現している。
chapter0.md:6: ValidationError[DoubledWord], 一文に二回以上利用されている単語 "し" がみつかりました。 at line: オペレーティングシステムはハードウェアを分割させ、多くのプログラムがコンピュータを共有し同時動作(もしくは動作しているように見える)を実現している。
chapter0.md:6: ValidationError[DoubledWord], 一文に二回以上利用されている単語 "し" がみつかりました。 at line: オペレーティングシステムはハードウェアを分割させ、多くのプログラムがコンピュータを共有し同時動作(もしくは動作しているように見える)を実現している。
chapter0.md:6: ValidationError[DoubledWord], 一文に二回以上利用されている単語 "て" がみつかりました。 at line: オペレーティングシステムはハードウェアを分割させ、多くのプログラムがコンピュータを共有し同時動作(もしくは動作しているように見える)を実現している。
chapter0.md:6: ValidationError[DoubledWord], 一文に二回以上利用されている単語 "いる" がみつかりました。 at line: オペレーティングシステムはハードウェアを分割させ、多くのプログラムがコンピュータを共有し同時動作(もしくは動作しているように見える)を実現している。

でも、これはひどいんじゃない?単純にセンテンスを解析しているだけとはいえ、これは直しようが無いよ?

最初は最小限のエラーを出力するようにすべきか

以上のように、RedPenの出してくるエラーはあまりにも過剰だ。 なので、最初はRedPenのルールをかなり甘々に設定し、エラーが減ってくると少しずつ厳しくしていくのが良いのではないだろうか?

半角括弧を許可する

技術文書なら、半角括弧はOKでしょ!redpenのconfに、以下を追加する。

  <symbols>
    <symbol name="LEFT_PARENTHESIS" value="(" invalid-chars="(" after-space="true" />
    <symbol name="RIGHT_PARENTHESIS" value=")" invalid-chars=")" after-space="true" />
  </symbols>

最初はかなり戸惑ったのだが、ドキュメントを一生懸命読むとわかった。半角とか、特定の文字のためのルールが存在するのね。

RedPen 1.5 Documentation

f:id:msyksphinz:20160403015642p:plain

doubledwordのルールをかなり甘めに設定する

そうでないとこの大量のエラーは処理しきれない。下の例では、「読点、で、を」を文中に2回以上登場させても良い設定にしているが、もっと別の接続詞も追加しておくべきだろう。そうでないと何のために文章を校正しているのかわからなくなる。

    <validator name="DoubledWord">
      <property name="list" value="、,で,を" />
    </validator>

かなり粗削りなツールな印象。今後の発展に期待

というわけで、デフォルトで使ってみると、申し訳ないが「相当使い物にならない」。自分でカスタマイズして、適材適所で使っていくべきツールだと思う。

とはいえ、これだけ大量に怒られると、「普段どういう部分に意識して文章を書くべきか」というのくらいはちょっと分かったかな。投稿する前にちゃんと読み直せとか(笑)

もしくは、今はやりのディープラーニングで、学習させて適切な校正をしてくれるように進化してくれてもいいよ!

RedHat Enterprise Linux 7.2 が開発者向けに無償公開されたので早速インストールしてみた

pc.watch.impress.co.jp

RedHatより、RedHat Enterprise Linux 7.2が開発者向けに無償公開された。

RedHat Enterprise Linuxといえば開発者向けに推奨されているLinux OSであり、ハードウェア設計者にとってはEDAツールのインストール先として推奨されているケースが多い。 僕も会社ではRedHat Enterprise Linuxを使っている。別にCentOSでも構わないが、しっかりサポートを得られるのはRHELだし、インストール時にトラブルに合う確率も低い。 RedHat系で動作確認をしたいときは一度は試しておきたいディストリビューションだったりする。

これまではRedHatを使いたいときは有償だったのだが、どうやら今回開発者向けに無償公開されたようだ。 このあたりの解説を見れば大体分かる。

Red Hat Enterprise Linux Developer Program - Red Hat Customer Portal

https://access.redhat.com/webassets/avalon/g/rhel_dev_overview.png

どうやら、開発者向けのバージョンDeveloper Suiteは全くサポートは受けられないということだろうか。 ただしソフトウェアのアップデートにはしっかりアクセスできるし、別に趣味のプログラミングの環境として使うだけなので個人利用ならば問題ないだろう。

早速ダウンロードして、仮想環境上にインストールしてみよう。

www.redhat.com

RedHat Enterprise Linux 7.2をダウンロードしてインストールする

ダウンロードにはRedHatのDeveloper Subscriptionに登録する必要がある。僕はGoogleのアカウントを使って登録した。 この後、ユーザ登録するとダウンロードできるようになる。インストールガイドもその時に入手できるようになった。

インストール中にはいくつかライセンスの契約の確認をする操作があった。これまで結構CentOS系や、Scientific LinuxなどのRedHat系のLinuxをインストールをしてきたが、これ系のメッセージと確認が出てきたのは初めてだったなあ。

インストール時に「パッケージとして開発者用のソフトウェア」と「GUI」をインストールしておいた。これはダウンロード時に参照できるインストールガイドに載っている。

developers.redhat.com

f:id:msyksphinz:20160402030046p:plain

このページを見るとわかるとおり、ベアメタル、Hyper-VVirtualBox, VMwareでのインストール方法のガイドが載っている。僕はVirtualBoxを利用した。

無事にインストール完了した。また、Guest Additionもインストール出来た。

f:id:msyksphinz:20160402030141p:plain

GUIUbuntuと比較すると非常に軽快な印象だ。まあ、GUIはどっちにしろ開発用とならば使わないし、そのうちどうせSSH経由でアクセスするようになるんだから、大したことではないだろう。

とりあえずは、せっかくインストールしたので活用して行きたい。以下の記事にも興味がある。

pc.watch.impress.co.jp

なお、Red HatMicrosoftと協業し、Microsoftの.NETをRHEL上で動作できるようにすることを2015年の11月に発表したが、今回Microsoftの開発者向けイベント「Build 2016」で、この動作デモをステージ上で行なうとともに、.NET coreおよびASP.NET、Entity Frameworkのオープンソース版をGitHubで公開した。また同時に、.NETファウンデーションへの参画を表明した。

Vivado Simulatorで波形デバッグする環境を構築する

僕は波形デバッグはあまり好きではなく、基本的に波形を水にログファイルだけでデバッグできるようにしておきたいのだが、ベーシックな部分を観測するためには最後には波形デバッグが必要だ。 そこで、Vivado Simulatorを使った時の波形デバッグの環境を構築しよう。やりたいことは、GUI付きでのシミュレーション、波形の追加などの操作だ。

波形ダンプ付きのコンパイル

Vivado Simulatorにおいて、GUI付きでデバッグをするためには、xsimにおいて-guiを追加すると良い。

xsim run_tb_mag_top -gui

ただしこれだけでは波形のダンプは取得できず、コンパイル時にデバッグオプションを追加しておかないと怒られる。

xelab -debug wave -s run_tb_mag_top work.tb_mag_top --timescale 1ns/100ps

Vivado Simulator実行時のさまざまなコマンド

自分がはまったのは、-R と -onfinishの考え方だ。

-R : シミュレーションを最後まで実行し、終了します (「run -all; exit」を実行)。

これを最初つけていたのだが、これを付けたままGUIを起動すると、シミュレーションが終了するとすぐにウィンドウも閉じられてしまう。これではデバッグできない。 結論としては、-Rオプションを除くだけでよい。ついでに、シミュレーション終了時の挙動を変えるためには、onfinishオプションも使用できる。

-onfinish stop|quit : シミュレーションが終了したときの動作を指定します。有効な値はquit および stop で、デフォルトは stop です。

基本的にstopのままで良いと思われるが、-Rを使わずにウィンドウも閉じたいときは、-onfinish quitを指定しておけばよいのかな。

Vivado SimulatorでのFPGA Primitiveモジュールの指定方法

Vivado Simulatorにおいて、XilinxのIPを使ってシミュレーションをしようとしたところ、Primitiveなモジュールが存在しないと怒られてしまった。

ERROR: [VRFC 10-2063] Module <GND> not found while processing module instance <GND> [... funcsim.v:2047]
  GND GND
       (.G(\<const0> ));

そういえば、Vivado Simulatorにおいてfsblのようなモジュール群を読み込むためにはどうしたらよいのかと思い調査したところ、ちゃんとVivadoにもunisimのようなライブラリ群が存在していた。

っていうか、以下のFAQを見る限り、これらのライブラリは別に指定しなくても読み込まれるという理解だったんだけどな。

AR# 64052 - Vivado シミュレーション ライブラリの使用 - UNISIM ライブラリ

Vivado 2015.4ならば、以下のVerilogファイルがそれに相当するようだ。

c:/Xilinx/Vivado/2015.4/data/verilog/src/unisim_comp.v

とりあえずfilelistにこのファイルを追加すると、無事にコンパイルされるようになった。

それともう一つ、このunisim_comp.vにはタイムスケールの指定が無いため、コンパイルに失敗するケースがある。

ERROR: [XSIM 43-4099] "c:/Xilinx/Vivado/2015.4/data/verilog/src/unisim_comp.v" Line 3236. Module GND doesn't have a timescale but at least one module in design has a timescale.

これもオプションを調査して行くと、xelabの実行時にタイムスケールを指定すれば良さそうだ。

  COMMAND xelab -s run_tb_mag_top work.tb_mag_top --timescale 1ns/100ps

これで、コンパイルとシミュレーションが無事に通るようになった。

Vivado Simulatorを使ってシミュレーションを行う環境を立ち上げる(Mingwで挑戦)

以前、CMakeを使ってVerilogシミュレーションの環境を整える準備を行った。趣味でVerilogを書いている中で、Windows上のVivadoでシミュレーションを行う必要が出てきたため、環境を構築しよう。

msyksphinz.hatenablog.com

利用したのは、Cygwinから若干進化して、MingW64上で構築を行っている。

MingW上での必要なパッケージのインストール

Verilogの自動生成のための環境として、rubyと、cmakeのインストールを行った。 これはパッケージインストールをするだけで完了できる。

pacman -S ruby cmake

Vivadoの環境の構築

MingWの環境では、vivado_settingsもちゃんと動作した。

/c/Xilinx/Vivado/2015.4/settings64.sh

あとは、CMakeで必要なVerilogファイルを記述するだけだ。ファイルリストは、以下のようにしたものを利用している。

HW_DIR/mag_core/mag_top/sim/tb_mag_top.v
#include "../rtl/mag_top.f"

シミュレーションベンチと、RTLファイルリストを分けて記述している。 あとは、以前の記事でテンプレートを作成したCMakeLists.txtを移植して、cmakeの実行と、シミュレーションを実行するだけだ。

ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:85]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:93]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:101]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:109]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:117]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:125]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:133]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:141]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:149]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:157]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:165]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:173]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:181]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:189]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:205]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:565]
ERROR: [VRFC 10-1412] syntax error near , [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:573]
ERROR: [VRFC 10-91] IF_INST is not declared [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:53]
ERROR: [VRFC 10-91] IF_INST is not declared [C:/msys64/home/masayuki/work/magnetor-1/hardware/mag_core/mag_idu/rtl/riscv_ctrl.v:61]

いろいろと怒られてしまった。あとで修正しよう。