前ページで示したリストは、CPUにおける命令をフェッチしてデコードし実行するコードです。命令をフェッチするのはよいのですが、その命令はどこに格納されているのでしょうか。それはメモリですよね。このメモリ機能はCPU内には含まれませんので別途記述する必要があります。このようにCPUとメモリとは別モジュールとして記述しています。リスト3は、メモリをVerilog-HDLで記述したコードになります。
module ram(clk, we, r_addr, r_data, w_addr, w_data); input clk, we; input [7:0] r_addr, w_addr; input [7:0] w_data; output [7:0] r_data; reg [7:0] mem [15:0]; initial begin mem[0] <= 8'b01100_110;// inc R6 mem[1] <= 8'b1001_0000;// jmp 0 end always @(posedge clk) begin if(we) mem[w_addr] <= w_data; end assign r_data = mem[r_addr]; endmodule
module行でこのモジュールの名前と入出力を定義しています。このメモリは読み書き可能な機能があるので、weやw_addr、w_dataがありますが、今回は読み出しのみの用途で使っていますので、これらの入出力インタフェースは使っていません。initial beginで囲まれている2行があらかじめこのメモリに書き込まれているコードです(これらについては後述します)。
リスト4はトップモジュールであるtestbenchのソースコードです。
module testbench( input clk, input rst, output [3:0]leds); wire [7:0] w_data; wire [7:0] r_data; wire [3:0] adr; wire [3:0] leds; wire [3:0] led; assign leds[0] = !led[0]; assign leds[1] = !led[1]; assign leds[2] = !led[2]; assign leds[3] = !led[3]; reg [23:0] counter; ram ram1(counter[23], 0, {4'b0000,adr}, r_data, adr, w_data); cpu cpu1(rst,counter[23],btn,led,adr,r_data); always @(posedge clk or negedge rst) begin if (!rst) counter <= 0; else counter <= counter + 1; end endmodule
このモジュールは3つあるモジュールの中の最上位モジュールです。他の下位のモジュールで定義されている入出力の関連付けを行います。ここではCPUとメモリをつないでいます。
もう1つの役割は、これらのコードを実装するハードウェア環境とのインタフェースを定義しています。この場合ですと、クロック入力、リセットボタン、それと4つのLEDへの接続です。Tang Nanoに搭載されている水晶発振器の周波数は27MHzでこれを基にクロック信号が生成されます。この発信周波数を24分周したものをCPUとメモリに提供しています。
ですからCPUは1秒間に1サイクル前後のクロックで動作します。リセットボタンはUSBコネクター脇の白いタクトスイッチをアサインしています。CPUからの出力である4つのLEDはTang Nanoの基板に搭載されている6つのLEDの内4つを割り当てています。図1は、Tang Nanoのボード上のリセットボタンの位置とLEDの位置を示しています。
リスト5は物理制約条件ファイル(Physical Constraints file)の中身を示しています。クロックのピン番号、リセットボタンのピン番号そして4つのLEDのピン番号を指定しています。
IO_LOC "clk" 52; IO_LOC "rst" 4; IO_LOC "leds[0]" 10; IO_LOC "leds[1]" 11; IO_LOC "leds[2]" 13; IO_LOC "leds[3]" 14;
リスト6はあらかじめメモリに書き込まれているサンプルプログラムです。CPUが起動するとこのプログラムが動作します。
mem[0] <= 8'b01100_110;// inc R6 mem[1] <= 8'b1001_0000;// jmp 0
このサンプルプログラムはメモリモジュール(ram.v)のinitial blockに定義されています。メモリの0番地にinc R6、メモリの1番地にjmp 0が書き込まれています。このプログラムが動作するとr6が0から15まで1つずつ加算されます。R6は4つのLEDに直結されるレジスタですので、クロックを刻むごとに加算された値がTang Nanoの基板上のLEDに反映されます。図2はこのサンプルプログラムが動作しているところです。R6の値を示すオレンジのLEDの幾つかが点灯しているのが分かります。
今回はインテル系のFPGAのIDEでコーディングしたVerilog-HDLのソースコードをGOWINのIDEで開発できるよう移植作業を行いました。短いコードですがTang NanoでDL166が動作することが確認できました。本稿では言及していませんが、Tang Nano用に手を加えたソースコードはインテルのIDEに同梱されているModelSimでも動作を確認しています。
そろそろTang Nanoでバイナリコーディングの演習を行いたいところですが、そのためにはもう少し機能を追加せねばなりません。あと少しお付き合いいただければと思います。
Copyright © ITmedia, Inc. All Rights Reserved.