Qsysを使って自作モジュールをNios IIに接続する

またしてもこの本でVerilogだ。

FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?

FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?

この本の第6章で自作モジュールをNios IIのAvalon Busに接続する方法が紹介されている。
これをQsysを使ってやる方法を、例によって備忘録。

Quartus IIでプロジェクトを作成する

これは本の指定通り、プロジェクト名を"nios2mypio"とする。
プロジェクトの作成方法はこちら

自作モジュールを作成する

こんな感じだ、名前は"mypio.v"で保存しておく。

module mypio(
	// Avalon Bus
	input wire in_clk,
	input wire in_reset,
	input wire in_address,
	input wire in_write,
	input wire in_read,
	input wire [7:0] in_write_data,
	output wire [7:0] out_read_data,
	// Ports
	input wire [3:0] in_4bit_switch,
	output reg [7:0] out_8bit_q);
	//
	always @(posedge in_clk or posedge in_reset)
	begin
		if (in_reset)
			out_8bit_q <= 8'hff;
		else if (in_write && in_address == 1'b0)
				out_8bit_q <= in_write_data;
	end
	//
	assign out_read_data = (in_read == 1'b0)? 8'h00:
		(in_address == 1'b0)? out_8bit_q: {4'h0, in_4bit_switch};
endmodule

Nios IIのAvalon Busに接続できるPIOで、例題通り

  • アドレス0x0に書くとFFに保存され、それがqとして出力される
  • アドレス0x0を読むとFFの内容が読み出せる、0x01を読むと接続されているスイッチの値が読み出せる(in_switch[3:0])

モジュールだ。

Qsysを開く

Quatrus IIのメニューから、"Tools" -> "Qsys"で開く。

Qsysに"mypio"を新規の部品として登録する

まず、"Library" -> "Project" -> "New Component..."をダブルクリック、もしくは"File"メニューで"New Component..."を選択する。

Component Editorが開くので、"Component Type"タグで、"Name"と"Display Name"を入力する、ここでは"mypio"。
次に"Files"タブに移動する、下の"Next"ボタンを押してもよい。

赤丸のついている"Synthesis Files"のセクションの下の"+"ボタンを押す。
ファイル選択画面になるので、上記で作成したVerilogファイル(mypio.v)を選択する。
ついで、同じく赤丸のついている"Analyze Synthesis Files"を押す。
文法チェックがされ、問題がなければAvalon Busのインターフェースポートと、モジュールのポートがennumerateされる。
次に"Signals"タブに移動し、各信号を以下のように設定する。

  • in_clkはinterfaceで"new Clock Input..."を選択する
  • in_resetはinterfaceで"new Reset Input..."を選択する
  • in_4bit_switchはinterface "new Conduit..."を選択する、自動的にconduit_end_1が割り振られる

残りについては、プルダウンメニューに図のような選択肢が既にあるはずだ。
次に"Interface"タブに移動する。
まず最初に、下にある"Remove Interfaces With No Signals"を押す。
これでほとんどのエラーが消えるはずだ。

次に、"avalon_slave_0"で、"Associated Clock"を"clock_sink"に、"Associated Reset"を"reset_sink"に設定する。

次に、"reset_sink"で"、"Associated Clock"を"clock_sink"に設定する。
これでエラーがすべて消えるはずだ。

最後に後でわかりやすくするために、2つのConduit_endをリネームしておく。
これで下の"Finish"を押せば、部品の登録が完了する。

QsysでIPを組み込む

こちらと同じ要領で、自作のモジュール(IP)も含めて、IPを組み込み、クロックとリセット、メモリー・命令バス、JTAGの割り込み、Reset Vector、Exception Vectorを設定して、各IPのメモリーアドレスを設定する。
今回組み込むIPは、

  • Nios II/e
  • On-chip Memory (RAM or ROM) 8192bytes
  • System ID Peripheral
  • JTAG UART
  • (自作の)mypio

だ。
完成図はこちら。

最後に、"Generate" -> "Generate"でモジュールを生成すれば、完成だ。


ちなみにQsysではネイティブバスはサポートされておらず、ダイナミックバスでしか作成できない。
ゆえに、Nios IIのコードを以下のように変更する。

#include "system.h"
#include "io.h"
int main()
{ 
	int in, out;
  /* Event loop never exits. */
  while (1)
  {
	  in = IORD_8DIRECT(MYPIO_0_BASE, 1);
	  switch(in)
	  {
	  case 0x0:
		  out = 0xc0;
		  break;
	  case 0x1:
		  out = 0xf9;
		  break;
	  case 0x2:
		  out = 0xa4;
		  break;
	  case 0x3:
		  out = 0xb0;
		  break;
	  case 0x4:
		  out = 0x99;
		  break;
	  case 0x5:
		  out = 0x92;
		  break;
	  case 0x6:
		  out = 0x82;
		  break;
	  case 0x7:
		  out = 0xd8;
		  break;
	  case 0x8:
		  out = 0x80;
		  break;
	  case 0x9:
		  out = 0x90;
		  break;
	  case 0xa:
		  out = 0x88;
		  break;
	  case 0xb:
		  out = 0x83;
		  break;
	  case 0xc:
		  out = 0xc6;
		  break;
	  case 0xd:
		  out = 0xa1;
		  break;
	  case 0xe:
		  out = 0x86;
		  break;
	  case 0xf:
		  out = 0x8e;
		  break;
	  default:
		  out = 0xff;
		  break;
	  }
	  IOWR_8DIRECT(MYPIO_0_BASE, 0, out);
  }
  return 0;
}