C プログラムの動作実験 4-1: ディスプレイへの繰り返し文字出力 2

実験の概要

本実験では、FPGAを搭載した実験基板を使用し、プロセッサをFPGA上に実現してその動作を確認する。 本動作実験では、 即値符号なし・セット・オン・レス・ザン命令(set on less than immediate unsigned:sltiu)とブランチ・ノット・イコール命令(branch on not equal:bne)、ロード・ワード命令(load word:lw)が未実装なプロセッサにおいて、それらの命令を含む簡単な機械語のマシン・コードを実行すると、どのような動作をするかを観察する。 本実験で観察した結果は、次のプロセッサの追加設計3において、sltiu,bne,lwが正しく動くプロセッサを完成させた後、動作確認の際の比較に用いる。

Cプログラムの動作実験 4-1

ディスプレイに61種類の文字を表示するCプログラムprint_all_char.cと、それを実行するプロセッサとして実験2-2で完成させたプロセッサをFPGA上に実現し、その動作を確認せよ。

本動作実験を下記の 1, 2, 3, 4, 5 の手順で行いなさい。
1. クロスコンパイル
2. MIPS マシン・コードからのメモリ・イメージファイルの作成
3. 命令メモリに格納される命令列の確認
4. 論理合成
5. FPGA を用いた回路実現

なお、本実験で使用する C プログラム print_all_char.c は、下記の URL からダウンロードできる。

C プログラム print_all_ahar.c:
http://www.ice.nuie.nagoya-u.ac.jp/jikken/hard/j2hard-mips/k04_sltiu_bne_lw_4_1/print_all_char.c
(実験 4-1 用の C プログラム)

1. クロスコンパイル

本実験では、Cプログラムの例としてディスプレイに61種類の文字を表示する図1のprint_all_char.cを使用する(ダウンロード)。
#define EXTIO_PRINT_STROKE (*(volatile unsigned int *) 0x0300)
#define EXTIO_PRINT_ASCII  (*(volatile unsigned int *) 0x0304)
main()
{
  unsigned int k;
  for (k = 0; k <= 60; k++) {
    EXTIO_PRINT_STROKE = (unsigned int)0x00000000;
    EXTIO_PRINT_ASCII = k;
    EXTIO_PRINT_STROKE = (unsigned int)0x00000001;
  }
}
          
図 1: print_all_char.c

クロスコンパイルには、「cross_compile.sh」を使用する。指導書2.2.1 節に示した環境設定を行ったのち、図 2 のようにして、print_all_char.c から MIPS マシン・コードを作成せよ。
cross_compile.sh print_all_char.c
図 2: cross_compile.sh を使った MIPS マシン・コードの生成

クロスコンパイルにより、MIPS マシン・コード print_all_char.bin が得られる。

2. MIPS マシン・コードからのメモリ・イメージファイルの作成

本実験では、MIPS マシン・コード print_all_char.bin を使用する。 また変換には、変換プログラム bin2v を使用する。図 3 のようにして、MIPS マシン・コード print_all_char.bin からメモリ・イメージファイルを作成せよ。
bin2v print_all_char.bin
図 3: bin2v を使った MIPS マシン・コードのメモリ・イメージファイルへの変換

この変換により、論理合成用のメモリ・イメージファイル rom8x1024_DE2.mif と、機能レベルシミュレーション用の命令メモリの Verilog HDL 記述 rom8x1024_sim.v が得られる。

なお、本実験で使用する MIPS マシン・コード print_all_char.bin は、正しいプロセッサ(sltiu 命令、bne 命令、lw 命令が実装済みのプロセッサ)で動作させると、以下のような動作をする命令列を含んだバイナリ・ファイルである。
  1. データメモリ(RAM)のREG[30]番地に0を格納
    sw $s0, 0x0000($s30)
  2. PC=0x040006c番地の命令にジャンプ
    j 0x040006c
  3. RAMのREG[30]番地の値と61を比較
    lw $s2, 0x0000($s30)
    sltiu $2, $2, 0x0000003d
  4. 比較結果が1ならPC=PC+4-17*4、そうでなければPC=PC+4

3. 命令メモリに格納される命令列の確認

本実験では、プロセッサの命令メモリに格納される命令列の確認を行う。この確認には、bin2v により生成された機能レベルシミュレーション用の Verilog HDL 記述 rom8x1024_sim.v を使用する。

図 4 に rom8x1024_sim.v の一部を示す。図 4 の case ブロック内の各行は、本実験で設計するプロセッサにおける、命令メモリの 10-bit アドレスとそこに格納される 32-bit 命令の機械語の記述である。また、各行の // 以降のコメント部には、その行に記述されているアドレスと命令に関する説明が記述されている。コメント部には、実際の MIPS の命令メモリにおけるアドレスと、命令名、命令の意味が記述されている。命令の意味の記述では、シンボル REG[0], REG[1], ..., REG[31] により、レジスタ 0 番から 31 番、$s0, ..., $s31 を表す。また、シンボル RAM[w] により、データメモリの w 番地を表す。

<省略>
case (word_addr)
 <省略>
 10'h00b: data = 32'hafc00000; // 0040002c: SW, RAM[REG[30]+0]<=REG[0];  ここが PC=0x002c の命令
 10'h00c: data = 32'h0810001b; // 00400030: J, PC<=0x0010001b*4(=0x0040006c);
 10'h00d: data = 32'h00000000; // 00400034: SLL, REG[0]<=REG[0]<<0;
 10'h00e: data = 32'h24020300; // 00400038: ADDIU, REG[2]<=REG[0]+768(=0x00000300);
 10'h00f: data = 32'hac400000; // 0040003c: SW, RAM[REG[2]+0]<=REG[0];
 10'h010: data = 32'h24030304; // 00400040: ADDIU, REG[3]<=REG[0]+772(=0x00000304);
 10'h011: data = 32'h8fc20000; // 00400044: LW, REG[2]<=RAM[REG[30]+0];  ここが 命令メモリ 0x011 の命令
 10'h012: data = 32'h00000000; // 00400048: SLL, REG[0]<=REG[0]<<0;
 10'h013: data = 32'hac620000; // 0040004c: SW, RAM[REG[3]+0]<=REG[2];
 10'h014: data = 32'h24030300; // 00400050: ADDIU, REG[3]<=REG[0]+768(=0x00000300);
 10'h015: data = 32'h24020001; // 00400054: ADDIU, REG[2]<=REG[0]+1(=0x00000001);
 10'h016: data = 32'hac620000; // 00400058: SW, RAM[REG[3]+0]<=REG[2];
 10'h017: data = 32'h8fc20000; // 0040005c: LW, REG[2]<=RAM[REG[30]+0];
 10'h018: data = 32'h00000000; // 00400060: SLL, REG[0]<=REG[0]<<0;
 10'h019: data = 32'h24420001; // 00400064: ADDIU, REG[2]<=REG[2]+1(=0x00000001);
 10'h01a: data = 32'hafc20000; // 00400068: SW, RAM[REG[30]+0]<=REG[2];
 10'h01b: data = 32'h8fc20000; // 0040006c: LW, REG[2]<=RAM[REG[30]+0];
 10'h01c: data = 32'h00000000; // 00400070: SLL, REG[0]<=REG[0]<<0;
 10'h01d: data = 32'h2c42003d; // 00400074: SLTIU, REG[2]<=(REG[2]<61(=0x0000003d))?1:0;  ここが 命令メモリ 0x01d の命令
 10'h01e: data = 32'h1440ffef; // 00400078: BNE, PC<=(REG[2] != REG[0])?PC+4+65519*4:PC+4;
 <省略>
endcase
<省略>
図 4: rom8x1024_sim.v の一部

図4のcaseブロック内の最後の記述は、本実験で設計するプロセッサの命令メモリの0x01e番地に機械語0x1440ffefが格納されることを表している。 また、この命令は実際のMIPSでは0x00400078に格納され、命令名はbne、レジスタ2番とレジスタ0番の値が等しくなければ、PCにPC+4+65519*4(PC+(1-17)*4)をセットし、等しければPCにPC+4をセットする命令であることを表している。

print_all_char.binから生成されたrom8x1024_sim.vまたは、図4のVerilog HDL記述を解析し、以下の1,2について答えよ。 なお、sltiuは即値符号なし・セット・オン・レス・ザン命令、bneはブランチ・オン・ノット・イコール命令、lwはロード・ワード命令はである。
  1. プロセッサが最初にPC=0x0074番地の命令を実行した直後のレジスタ2番目の値を予想せよ。
  2. プロセッサが最初にPC=0x0078番地の命令を実行した直後のPCの値を予想せよ。

3. 論理合成

本実験では、sltiu 命令と bne 命令、lw 命令が未実装なプロセッサならびに命令メモリ、その他周辺回路の論理合成を行う。 論理合成には、bin2v により生成された論理合成用のメモリ・イメージファイル rom8x1024_DE2.mif と実験 2-2 で完成させたプロセッサの Verilog HDL 記述一式を使用する。

命令メモリのメモリ・イメージファイル rom8x1024_DE2.mif をディレクトリ mips_de2-115 にコピーし、ディレクトリ mips_de2-115 に cd して、図 5 のように論理合成を行う。

quartus_sh --flow compile DE2_115_Default
図 5: quartus_sh を使ったプロセッサの論理合成

なお、論理合成には計算機の性能により 5 分から 20 分程度の時間がかかる。 論理合成が完了すると、ディレクトリ mips_de2-115 内に FPGA にダウンロード可能なプロセッサ等の回路一式のストリーム・アウト・ファイル DE2_115_Default.sof が生成される。

4. FPGA を用いた回路実現

本実験では、sltiu 命令と bne 命令、lw 命令が未実装なプロセッサの実際の動作を観察する。 観察した結果は、次のプロセッサの追加設計 3 において、sltiu, bne, lw が正しく動くプロセッサを完成させた後、動作確認の際の比較に用いる。 本実験には、論理合成により生成されたプロセッサなど回路一式のストリーム・アウト・ファイル DE2_115_Default.sof を使用する。 DE2_115_Default.sof を quartus_pgm を用いて DE2-115 ボード上の FPGA にダウンロードし、動作させよ。

今回プロセッサが実行するマシン・コードprint_all_char.binはディスプレイに61種類の文字を表示するプログラムである。 key3を連打してプロセッサにクロックパルスを送り、プロセッサにPC=0x0000番地から30個程度の命令を実行させ、ディスプレイ下部に文字が表示されるかどうかを確認せよ。 ディスプレイ下部に文字は1つも表示されないはずである。

ディスプレイ上部にはプロセッサ内部の主な信号線の現在の値が表示されている。 各信号線は、プロセッサのブロック図中の名前の似た信号線と、それぞれ対応している。 ブロック図中の線の幅はビット幅と対応しており、一番細い線は 1-bit の線、一番太い線は 32-bit の配線を表している。 また、ブロック図左下の ROM が、命令メモリである。 プロセッサはここから命令を読み、命令毎に決められた処理を行う。 ブロック図右下の RAM は、データメモリである。 3 の命令メモリに格納される命令列の確認の、1, 2 で予想した結果と同じ正しい動作かどうかを確認せよ。 予想と異なる正しくない動作のはずである。

プロセッサが、sltiu 命令と bne 命令、lw 命令を正しく実行できていないことが分かる。 これらの命令を正しく実行するために、プロセッサ内部で行われるデータ転送や演算などを制御しているメイン制御回路を、これらの命令を適切に処理できるものにする必要がある。

参考書