72
Altera Corporation セクション II–1 セクション II. HAL システム・ ライブラリ セクション HALHardware Abstraction Layer)システム・ ライブラリについて します。 セクション 、以 されています。 3 HAL システム・ライブラリ 4 HAL したプログラム 5 HAL デバイス・ドライバ 改定履歴 に、各 します。これら バージョン している Nios II キット Nios II プロセッサ バージョンに ありません。 日付 / バージョン 変更内容 3 2004 5 v1.0 初版 4 2004 12 v1.2 ブート・モード情報を追加 コンパイラの最適化について修正 コード・フットプリント削減のセクション を更新 2004 9 v1.1 DMA 受信チャネルのコード例を修正 2004 5 v1.0 初版 5 2004 12 v1.1 lwIP のバージョンの参照を 0.6.3 から 0.7.2 更新 2004 5 v1.0 初版

セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation セクション II–1

セクション II. HALシステム・ライブラリ

このセクションでは、HAL(Hardware Abstraction Layer)システム・ライブラリについて説明します。

このセクションは、以下の章で構成されています。

■ 第 3章 HALシステム・ライブラリの概要

■ 第 4章 HALを使用したプログラムの開発

■ 第 5章 HAL用デバイス・ドライバの開発

改定履歴 以下の表に、各章の改定履歴を示します。これらのバージョンは資料の改定を追跡しているのもので、Nios II 開発キットや Nios II プロセッサのバージョンには関係ありません。

章 日付 /バージョン 変更内容

3 2004年 5月v1.0

初版

4 2004年 12月v1.2

● ブート・モード情報を追加● コンパイラの最適化について修正● コード・フットプリント削減のセクションを更新

2004年 9月v1.1

DMA受信チャネルのコード例を修正

2004年 5月v1.0

初版

5 2004年 12月v1.1

lwIPのバージョンの参照を 0.6.3から 0.7.2に更新

2004年 5月v1.0

初版

myoshida
Text Box
この資料は、更新された最新の英語版が存在します。こちらの日本語版は参考用としてご利用下さい。 設計の際は、必ず最新の英語版で内容をご確認下さい。
Page 2: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

セクション II–2 Altera Corporation

HALシステム・ライブラリ Nios II ソフトウェア開発ハンドブック

Page 3: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 3–12004年 5月 Preliminary

3. HALシステム・ライブラリの概要

はじめに この章では、Nios® II プロセッサ用のHAL(Hardware Abstraction Layer)システム・ライブラリについて説明します。

HALシステム・ライブラリは、シンプルなデバイス・ドライバ・インタフェースを提供する軽量のランタイム環境です。プログラムはこのインタフェースを使用して基礎となるハードウェアと通信します。HALアプリケーション・プログラム・インタフェース(API)は、ANSI C標準ライブラリと統合されています。HAL API を使用すると、printf()、fopen()、fwrite()など、一般的な Cライブラリ関数によってデバイスおよびファイルにアクセスできます。

HALは Nios II プロセッサ・システムのボード・サポート・パッケージとして機能し、エンベデッド・システムのペリフェラルへの一貫したインタフェースを提供します。SOPC BuilderとNios II 統合開発環境(IDE)は緊密に統合されているため、HALシステム・ライブラリを自動的に生成できます。SOPC Builder がハードウェア・システムを生成すると、Nios II IDEは、そのハードウェア・コンフィギュレーションに合わせて、独自のHALシステム・ライブラリを生成できます。さらに、ハードウェア・コンフィギュレーションを変更すると、HALデバイス・ドライバのコンフィギュレーションに自動的に反映されます。このため、基本ハードウェアをわずかに変更したことによって発生するやっかいなバグがなくなります。

HALによってデバイス・ドライバが抽象化されるため、アプリケーションとデバイス・ドライバ・ソフトウェアが明確に区別されます。このようなドライバの抽象化によって、基本ハードウェアの変更に対応する再利用可能なアプリケーション・コードを容易に記述できます。さらに、既存のペリフェラル・ドライバに対応する新しいハードウェア・ペリフェラル用のドライバも簡単に記述できます。

使用開始にあたって

HAL の使用を開始する最も簡単な方法は、Nios II IDE に付属するオンライン・チュートリアルを実行することです。Nios II IDE で新規プロジェクトを作成するプロセスでは、HALシステム・ライブラリも同時に作成します。HALファイルを作成したりコピーしたりする必要はなく、また HALソース・コードを編集する必要もまったくありません。HALシステム・ライブラリは、Nios II IDEによって自動的に生成および管理されます。

NII52003-1.0

myoshida
Text Box
この資料は、更新された最新の英語版が存在します。こちらの日本語版は参考用としてご利用下さい。 設計の際は、必ず最新の英語版で内容をご確認下さい。
Page 4: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

3–2 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 5月

HALアーキテクチャ

HALシステム・ライブラリは、特定の SOPC Builderシステム上に構築する必要があります。SOPC Builderシステムとは、ペリフェラルおよびメモリと統合されたNios II プロセッサ・コア(SOPC Builderによって生成)を意味します。独自の SOPC Builder システムがない場合は、アルテラが提供するハードウェア・システムの例をベースにして、プロジェクトを作成できます。最初に、アルテラの Nios 開発ボードをターゲットとするプロジェクトを開発し、その後でプロジェクトのターゲットをカスタム・ボードに変更できます。ターゲットの SOPC Builder システムは、後から簡単に変更できます。

新規プロジェクトの開始に関する詳細は、Nios II IDEのオンライン・ヘルプを参照してください。

HALアーキテクチャ

このセクションでは、HALアーキテクチャの基本的な要素について説明します。

サービス

HALシステム・ライブラリは、次のサービスを提供します。

■ newlib ANSI C標準ライブラリとの統合使い慣れた C標準ライブラリ関数が利用できるようになります。

■ デバイス・ドライバシステム内の各デバイスへのアクセスが可能になります。

■ HAL APIデバイス・アクセス、割り込み処理、アラーム機能など、HALサービスへの一貫した標準インタフェースを提供します。

■ システムの初期化main()を実行する前に、プロセッサおよびランタイム環境用の初期化タスクを実行します。

■ デバイスの初期化main()を実行する前に、システムの各デバイスをインスタンス化および初期化します。

図 3-1は、ハードウェア・レベルからユーザ・プログラムまでのHALベースのシステムのレイヤを示します。

Page 5: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 3–32004年 5月 Nios II ソフトウェア開発ハンドブック

HALシステム・ライブラリの概要

図 3-1. HALベースのシステムのレイヤ

アプリケーションとドライバ

プログラマは、アプリケーション開発者とデバイス・ドライバ開発者の2つの明確なグループに区分されます。アプリケーション開発者にはユーザの大部分が該当し、各種ルーチンの中でも特にシステムの main()ルーチンの記述を担当します。アプリケーションは、C標準ライブラリまたは HALシステム・ライブラリ APIを介してシステム・リソースと通信します。デバイス・ドライバ開発者の役割は、アプリケーション開発者がデバイス・リソースを利用できるようにすることです。デバイス・ドライバは、低レベルのハードウェア・アクセス・マクロにより、ハードウェアと直接通信します。

このため、主要な HAL の資料は、次の 2 つの章に大きく分割されています。

■ 第 4章 HALを使用したプログラムの開発では HALを活用し、基本ハードウェアを意識しないでプログラムを記述する方法について説明しています。

■ 第 5章 HAL用デバイス・ドライバの開発では、ハードウェアと直接通信する方法、および抽象化された HAL API を介してハードウェア・リソースを利用可能にする方法について説明しています。

ユーザ・プログラム

C標準ライブラリ

HAL API

デバイス・ドライバ

デバイス・ドライバ...デバイス・

ドライバ

Nios IIプロセッサ・システム・ハードウェア

Page 6: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

3–4 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 5月

HALアーキテクチャ

汎用デバイス・モデル

HALは、タイマ、Ethernet MAC/PHYチップ、キャラクタ・データを伝送する I/Oペリフェラルなど、エンベデッド・システムで広く使用されるペリフェラルのクラスに対応する汎用デバイス・モデルを提供します。汎用デバイス・モデルは、HALシステム・ライブラリの中核となる機能です。汎用デバイス・モジュールを利用すれば、基本ハードウェアに関係なく、一貫した APIを使用してプログラムを記述することができます。

デバイス・モデル・クラス

HALは、次のデバイスのクラス用のモデルを提供します。

■ キャラクタ・モード・デバイスUART など、キャラクタをシリアルに送受信するハードウェア・ペリフェラルです。

■ タイマクロックをカウントし、周期的な割り込み要求を生成できるハードウェア・ペリフェラルです。

■ ファイル・サブシステム物理デバイス内に格納されたファイルにアクセスするためのメカニズムを提供します。内部実装に応じて、ファイル・サブシステム・ドライバは、基本デバイスに直接アクセスしたり、別のデバイス・ドライバを使用したりすることができます。例えば、フラッシュ・メモリ・デバイス用のHAL APIを使用して、フラッシュにアクセスするフラッシュ・ファイル・サブシステム・ドライバを記述できます。

■ イーサネット・デバイスアルテラが提供する軽量 IPプロトコル・スタックに対応したイーサネット接続へのアクセスを可能にします。

■ DMAデバイスデータ・ソースからディスティネーションへのバルク・データ転送を実行するペリフェラルです。イーサネット接続など、メモリやその他のデバイスをソースおよびディスティネーションにすることができます。

■ フラッシュ・メモリ・デバイス専用のプログラミング・プロトコルを使用してデータを格納する不揮発性メモリ・デバイスです。

Page 7: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 3–52004年 5月 Nios II ソフトウェア開発ハンドブック

HALシステム・ライブラリの概要

アプリケーション開発者の利点

HALシステム・ライブラリは、デバイスの各クラスの初期化とアクセスに使用する関数のセットを定義します。この APIは、デバイス・ハードウェアの基本実装状態に関係なく、一貫性が維持されています。例えば、キャラクタ・モードのデバイスおよびファイル・サブシステムにアクセスする場合には、printf()や fopen()などの C標準ライブラリ関数が使用できます。アプリケーション開発者の場合、これらペリフェラルのクラスに対するハードウェアとの基本的な通信を確立するためだけに、低レベルのルーチンを記述する必要はありません。

デバイス・ドライバ開発者の利点

各デバイス・モデルは、デバイスの特定のクラスを操作するのに必要なドライバ関数のセットを定義します。新しいペリフェラル用のドライバを記述する場合は、このドライバ関数のセットを提供するだけで十分です。結果として、ドライバ開発作業は事前定義され、記録されます。さらに、既存の HAL 関数とアプリケーションを使用してデバイスにアクセスし、ソフトウェア開発の労力を軽減させることもできます。HALシステム・ライブラリは、ドライバ関数をコールしてハードウェアにアクセスします。アプリケーション・プログラマは、ドライバ・ルーチンを直接呼び出すのではなく、ANSI Cまたは HAL APIを呼び出してハードウェアにアクセスします。したがって、ドライバの使用法は HAL APIの一部として記録されます。

C標準ライブラリ— NewlibHALシステム・ライブラリでは、ANSI C標準ライブラリがランタイム環境に統合されています。HALは、C標準ライブラリのオープン・ソース実装である newlib を使用しています。newlib は、エンベデッド・システムで使用するための Cライブラリであり、HALおよび Nios II プロセッサに最適です。newlibのライセンスでは、ソース・コードのリリースや newlibベースのプロジェクトに対するロイヤリティは不要です。

ANSI C標準ライブラリに関する文献は豊富にあります。最もよく知られた参考文献は、Prentice Hallから出版された、B.W.カーニハン /D.M.リッチー著のプログラミング言語 Cでしょう。この文献は、20以上の言語に翻訳されています。また、Redhat社は、http://sources.redhat.com/newlibで newlibのオンライン資料を提供しています。

Page 8: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

3–6 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 5月

サポートされているペリフェラル

サポートされているペリフェラル

アルテラは、Nios II プロセッサ・システムで使用する多数のペリフェラルを提供しています。大部分のアルテラ製ペリフェラルでは、HAL APIを介してハードウェアへのアクセスを可能にする HAL デバイス・ドライバが利用できます。次のアルテラ製ペリフェラルは、HALを完全にサポートしています。

■ キャラクタ・モード・デバイス:● UARTコア● JTAG UARTコア● LCD 16207ディスプレイ・コントローラ

■ フラッシュ・メモリ・デバイス● 共通フラッシュ・インタフェース準拠のフラッシュ・チップ● アルテラの EPCSシリアル・コンフィギュレーション・デバイス・コントローラ

■ ファイル・サブシステム● リード・オンリ zipファイル・システム

■ タイマ・デバイス● タイマ・コア

■ DMAデバイス● DMAコントローラ・コア

■ イーサネット・デバイス● LAN91C111 Ethernet MAC/PHY Controller

LAN91C111コンポーネントには、MicroC/OS- II ランタイム環境が必要です。詳細については、9–1ページの「イーサネットと Lightweight IP」を参照してください。

その他にも、ここに記載していないペリフェラルが、サードパーティ・ベンダから提供されています。Nios II プロセッサで利用可能なその他のペリフェラルは、アルテラのWebサイトwww.altera.comをご覧ください。

(アルテラおよびサードパーティ・ベンダの両方が提供する)すべてのペリフェラルは、ハードウェアに対するペリフェラルの低レベル・インタフェースを定義したヘッダ・ファイルを提供する必要があります。このため、すべてのペリフェラルはある程度 HALをサポートしています。ただし、デバイス・ドライバを提供していないペリフェラルもあります。ドライバを入手できない場合は、ヘッダ・ファイルに提供された定義のみを使用して、ハードウェアにアクセスしてください。ハード・コード化されたアドレスやその他の「マジック・ナンバ」を使用してペリフェラルにアクセスすることは、絶対にしないでください。

Page 9: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 3–72004年 5月 Nios II ソフトウェア開発ハンドブック

HALシステム・ライブラリの概要

特定のペリフェラルには、汎用 API では捕捉できない使用条件を持つハードウェア固有の機能が必ずあります。HAL システム・ライブラリは、UNIX 形式の ioctl() 関数を提供することによって、ハードウェア固有の要求に対応しています。ハードウェア機能はペリフェラルに依存するため、ioctl()オプションは、各ペリフェラルの説明書に記載されています。

一部のペリフェラルには、HAL汎用デバイス・モデルをベースにしていない専用のアクセス関数が用意されています。例えば、アルテラは、Nios II プロセッサ・システムで使用するための汎用パラレル I/O(PIO)コアを提供しています。この PIO ペリフェラルは、HAL が提供する汎用デバイス・モデルのどのクラスにも適合しないため、ヘッダ・ファイルと少数の専用アクセス関数のみが用意されています。

ペリフェラルのソフトウェア・サポートの詳細については、当該ペリフェラルの説明書を参照してください。アルテラ提供のペリフェラルの詳細については、Nios IIプロセッサ・リファレンス・ハンドブックを参照してください。

Page 10: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

3–8 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 5月

サポートされているペリフェラル

Page 11: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–12004年 12月 Preliminary

4. HALを使用したプログラムの開発

はじめにこの章では、アルテラのHAL(Hardware Abstraction Layer)システム・ライブラリをベースとして、プログラムを開発する方法について説明します。

HALベース・システムの APIは、Nios® II プロセッサを初めて使用するソフトウェア開発者の方でも、容易に利用できます。HALをベースとしたプログラムは、ANSI C 標準ライブラリ関数とランタイム環境を使用し、HAL APIの汎用デバイス・モデルを介してハードウェア・リソースにアクセスします。ANSI C標準ライブラリはHALシステム・ライブラリから独立していますが、HAL APIの大部分は、使い慣れた ANSI C標準ライブラリ関数で定義されています。ANSI C標準ライブラリとHALは緊密に統合されているため、HALシステム・ライブラリ関数を直接呼び出さない有効なプログラムを開発することができます。例えば、printf()、scanf()などの ANSI C標準ライブラリ I/O関数を使用して、キャラクタ・モードのデバイスとファイルを操作できます。

この章では、HAL システム・ライブラリ API を使用するための基本的な参考情報を記載します。いくつかのトピックは、他の章で詳細に扱われています。この章で扱っていない以下の重要なトピックについては、目次を参照してください。

■ デバイス・ドライバ、およびハードウェアと直接連携するコードの記述■ 例外処理および割り込みサービス・ルーチン■ キャッシュ・メモリを構成するためのプログラミング■ リアル・タイム・オペレーティング・システム(RTOS)■ イーサネット

本書では、ANSI C標準ライブラリについては説明していません。

Nios II IDEプロジェクト構造

HALシステム・ライブラリをベースとしたソフトウェア・プロジェクトの作成と管理は、Nios II 統合開発環境(IDE)に緊密に統合されています。このセクションでは、HAL を理解するための基礎として、Nios IIIDEプロジェクトについて説明します。

NII52004-1.2

myoshida
Text Box
この資料は、更新された最新の英語版が存在します。こちらの日本語版は参考用としてご利用下さい。 設計の際は、必ず最新の英語版で内容をご確認下さい。
Page 12: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–2 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

Nios II IDEプロジェクト構造

図 4-1 は、HAL システム・ライブラリの組み込み方法に重点を置いたNios II プログラムのブロックを示します。各ブロックのラベルはブロックの作成元または作成者を示し、矢印は各ブロック間の依存関係を示します。

図 4-1. Nios II IDEプロジェクトの構造

HAL ベースのシステムは、図 4-1 に示すように、2 つの Nios II IDE プロジェクトを使用して構築されます。ユーザのプログラムは、1 つのプロジェクト(ユーザ・アプリケーション・プロジェクト)に含まれ、別のシステム・ライブラリ・プロジェクト(HALシステム・ライブラリ・プロジェクト)に依存します。アプリケーション・プロジェクトには、ユーザが開発するすべてのコードが含まれています。プログラムの実行可能イメージは、このプロジェクトをビルドしたものを土台として作成されます。HAL システム・ライブラリ・プロジェクトには、プロセッサ・ハードウェアとのインタフェースに関連するすべての情報が含まれています。システム・ライブラリ・プロジェクトは Nios II プロセッサ・システムに依存し、SOPC Builderで生成された .ptfファイルによって定義されています。

HALベースのソフトウェア・アプリケーション

別名:ユーザ・プログラムまたはユーザ・プロジェクト 記述:.c、.h、.sファイル作成:ユーザ

別名:HALまたはシステム・ライブラリ・プロジェクト

記述:.ptfファイル

記述:Nios II IDE プロジェクト設定

別名:Nios IIプロセッサ・システムまたはハードウェア

作成:SOPC Builder

作成:Nios II IDE

ユーザ・アプリケーション・プロジェクト

HALシステム・ライブラリ・プロジェクト

SOPC Builderシステム

Page 13: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–32004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

このプロジェクトの依存関係のため、SOPC Builderシステムが変更された(つまり、.ptfファイルが更新された)場合でも、Nios II IDEによって HAL システム・ライブラリが管理され、システム・ハードウェアを正確に反映するようにドライバ・コンフィギュレーションが更新されます。HAL システム・ライブラリによって、ユーザのプログラムは基本ハードウェアが変更されても影響を受けることはありません。そのため、ユーザは、自分のプログラムがターゲット・ハードウェアに適合するかどうかを気にすることなく、コードの開発とデバッグを実行できます。つまり、HALシステム・ライブラリをベースとするプログラムは、常にターゲット・ハードウェアと同期化されます。

system.hシステム記述ファイル

system.h ファイルは、HAL システム・ライブラリの基礎となります。system.h ファイルには、Nios II システム・ハードウェアのソフトウェア記述がすべて含まれています。このファイルは、ハードウェアおよびソフトウェアのデザイン・プロセス間における引き渡し点となります。system.hのすべての情報が、必ずしもプログラマに役立つとは限りませんし、Cソース・ファイルで明示的に指定する必要があるとも限りません。しかし、system.h には、「このシステムにはどのようなハードウェアが存在するか ?」という基本的な疑問に対する解答があります。

system.hファイルには、システム内の各ペリフェラルの記述と以下の詳細情報が入っています。

■ ペリフェラルのハードウェア・コンフィギュレーション■ ベース・アドレス■ IRQの優先順位(該当する場合)■ ペリフェラルの識別名

system.h ファイルは、絶対に編集しないでください。system.h ファイルは、HALシステム・ライブラリ・プロジェクト用にNios II IDEによって自動的に生成されます。system.hの内容は、ユーザが Nios II IDEで設定するハードウェア・コンフィギュレーションおよび HALシステム・ライブラリ・プロパティの両方に依存します。

詳細については、Nios II IDEオンライン・ヘルプを参照してください。

Page 14: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–4 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

データ幅と HAL型の定義

system.hファイル内の以下のコードは、このファイルが定義するハードウェア・コンフィギュレーションの一部を示します。

例:system.hファイルの一部

/* * sys_clk_timer configuration * */

#define SYS_CLK_TIMER_NAME "/dev/sys_clk_timer"#define SYS_CLK_TIMER_TYPE "altera_avalon_timer"#define SYS_CLK_TIMER_BASE 0x00920800#define SYS_CLK_TIMER_IRQ 0#define SYS_CLK_TIMER_ALWAYS_RUN 0#define SYS_CLK_TIMER_FIXED_PERIOD 0

/* * jtag_uart configuration * */

#define JTAG_UART_NAME "/dev/jtag_uart"#define JTAG_UART_TYPE "altera_avalon_jtag_uart"#define JTAG_UART_BASE 0x00920820#define JTAG_UART_IRQ 1

データ幅とHAL型の定義

Nios II プロセッサなどのエンベデッド・プロセッサでは、多くの場合、データの正確な幅と精度を知ることが重要になります。ANSI C のデータ型では、データ幅が明示的に定義されていないため、HALは代わりに標準型定義のセットを使用します。ANSI C 型もサポートされていますが、これらのデータ幅はコンパイラの規約に依存します。

ヘッダ・ファイル alt_type.hでは、HAL型定義を定義しています。表 4–1にHAL型定義を示します。

表 4–1. HAL型定義

型 意味

alt_8 符号付 8ビット整数

alt_u8 符号なし 8ビット整数

alt_16 符号付 16ビット整数

alt_u16 符号なし 16ビット整数

alt_32 符号付 32ビット整数

alt_u32 符号なし 32ビット整数

Page 15: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–52004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

表 4–2 に、アルテラが提供する GNU Toolchain で使用するデータ幅を示します。

UNIX形式のインタフェース

HAL APIは、多数の UNIX形式の関数を提供します。UNIX形式の関数によって、新たに Nios II を使用するプログラマにも親しみやすい開発環境が提供され、既存のコードを移植して HAL 環境で実行させるための作業が容易になります。HAL は主にこれらの関数を使用して、ANSIC標準ライブラリ用のシステム・インタフェースを提供します。例えば、これらの関数は、stdio.h で定義された C ライブラリ関数が必要とするデバイス・アクセスを実行します。

以下に、利用可能な UNIX形式の関数の全リストを示します。

■ _exit()■ close()■ fstat()■ getpid()■ gettimeofday()■ ioctl()■ isatty()■ kill()■ lseek()■ open()■ read()■ sbrk()■ settimeofday()■ stat()■ usleep()■ wait()■ write()

最もよく使用される関数は、ファイル I/Oに関するものです。4–6ページの「ファイル・システム」を参照してください。

表 4–2. GNU Toolchainのデータ幅

型 意味

char 8ビット

short 16ビット

long 32ビット

int 32ビット

Page 16: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–6 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

ファイル・システム

これらの関数の使用法の詳細については、10–1 ページの「HAL APIリファレンス」を参照してください。

ファイル・システム

HALは、キャラクタ・モードのデバイスおよびデータ・ファイルを操作するのに使用可能なファイル・システムのコンセプトを提供します。newlib が提供する C 標準ライブラリのファイル I/O 関数(fopen()、fclose()、fread()など)、または HALシステム・ライブラリが提供する UNIX 形式のファイル I/O を使用して、ファイル・システム内のファイルにアクセスできます。

HALでは、ファイル操作に以下の UNIX形式の関数を利用できます。

■ close()■ fstat()■ ioctl()■ isatty()■ lseek()■ open()■ read()■ stat()■ write()

これらの関数の詳細については、10–1 ページの「HAL API リファレンス」を参照してください。

ファイル・システムは、自身をグローバル HAL ファイル・システム内のマウント・ポイントとして登録します。マウント・ポイントの下にあるファイルにアクセスを試みると、アクセスはそのファイル・サブシステムに対して実行されます。例えば、zip ファイル・サブシステムが/mount/zipfs() としてマウントされている場合、/mount/zipfs()/myfileを対象とした fopen()のコールは、関連付けられた zipfsファイル・サブシステムによって処理されます。

同様に、キャラクタ・モード・デバイスは、HALファイル・システム内のノードとして登録します。慣例的に、system.hファイルでは、デバイス・ノード名は、プリフィックス /dev/に続いて、SOPC Builderでハードウェア・コンポーネントに割り当てられた名前を付加して定義されます。例えば、SOPC Builderでの UARTペリフェラル uart1は、system.hでは /dev/uart1となります。

カレント・ディレクトリという概念はありません。すべてのファイルは、絶対パスを使用してアクセスする必要があります。

Page 17: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–72004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

以下に、HALファイル・システム内のノードとして登録されたリード・オンリ zip ファイル・サブシステム rozipfs から、キャラクタを読み取るコードを示します。

例:ファイル・サブシステムからのキャラクタの読み取り

#include <stdio.h>#include <stddef.h>#include <stdlib.h>

#define BUF_SIZE (10)

int main(void){FILE* fp;char buffer[BUF_SIZE];

fp = fopen (“/mount/rozipfs/test”, “r”);if (fp == NULL){

printf (“Cannot open file.\n”); exit (1);}

fread (buffer, BUF_SIZE, 1, fp);

fclose (fp);

return 0;}

これらの関数の使用法の詳細については、10–1 ページの「HAL APIリファレンス」を参照してください。

キャラクタ・モード・デバイスの使用

キャラクタ・モード・デバイスとは、UART(Universal AsynchronousReceiver/Transmitter)のように、キャラクタをシリアルに送受信するハードウェア・ペリフェラルです。キャラクタ・モード・デバイスは、HALファイル・システム内のノードとして登録されます。一般に、プログラムはファイル・ディスクリプタをデバイスの名前に関連付けた後に、file.hに定義された ANSI Cファイル操作を使用して、キャラクタをファイルから読み込んだり、ファイルに書き込んだりします。さらに、HALでは標準入力、標準出力、および標準エラーのコンセプトもサポートされているため、プログラムから stdio.h I/O 関数を呼び出すことができます。

Page 18: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–8 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

キャラクタ・モード・デバイスの使用

標準入力、標準出力および標準エラー

シンプルなコンソール I/O を実装するには、標準入力(stdin)、標準出力(stdout)、および標準エラー(stderr)を使用するのが最も簡単な方法です。HALシステム・ライブラリは、背後で stdin、stdout、stderr を管理するため、ファイル・ディスクリプタを明示的に管理することなく、これらのチャネルを介してキャラクタを送信および受信することが可能になります。例えば、システム・ライブラリは、printf()の出力は標準出力に、perror()は標準エラーに送ります。

各チャネルは、Nios II IDEでシステム・ライブラリ・プロパティを設定することによって、特定のハードウェア・デバイスに関連付けます。

詳細については、Nios II IDEオンライン・ヘルプを参照してください。

以下のコードは、定番の Hello Worldプログラムを示します。このプログラムでは、Nios II IDEでコンパイルしたときに stdoutに関連付けられる任意のデバイスへ、キャラクタを送信します。

例:Hello World

#include <stdio.h>int main (){ printf (“Hello world!”); return 0;}

UNIX形式のAPIを使用する場合は、unistd.hで定義されたファイル・ディスクリプタ STDIN_FILENO、STDOUT_FILENO、および STDERR_FILENOを使用すれば、stdin、stdout、stderrにそれぞれアクセスできます。

キャラクタ・モード・デバイスへの汎用アクセス

キャラクタ・モード・デバイス(stdin、stdout、または stderr を除く)へのアクセスは、ファイルを開いたり、ファイルに書き込んだりするのと同様に簡単です。以下に、uart1 という名前の UART にメッセージを書き込むコードを示します。

例:UARTへのキャラクタの書き込み

#include <stdio.h>#include <string.h>

int main (void){ char* msg = “hello world”; FILE* fp;

Page 19: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–92004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

fp = fopen (“/dev/uart1”, “w”); if (fp) { fprintf(fp, “%s”,msg); fclose (fp); } return 0;}

C++ストリームHALベースのシステムでは、C++からのファイル操作に C++ストリーム APIが使用できます。

/dev/null

デバイス /dev/null は、すべてのシステムに含まれています。/dev/nullに書き込んでも処理されず、データは破棄されます。/dev/nullは、システム起動中に、安全な I/Oリダイレクションを実現するために使用されます。また、このデバイスは、不適切なデータを出さないようにするアプリケーションにも役立ちます。

このデバイスは、完全にソフトウェアのみで構成されています。システム内の物理的なハードウェア・デバイスとは無関係です。

ファイル・サブシステムの使用

ファイル・サブシステム用の HAL汎用デバイス・モデルを利用すれば、C標準ライブラリのファイル I/O関数を使用して、関連付けられるメディアに格納されたデータにアクセスできます。例えば、アルテラの zipリード・オンリ・ファイル・システムを利用すると、フラッシュ・メモリに格納されたファイル・システムにリード・オンリでアクセスできます。

ファイル・サブシステムの役割は、所定のマウント・ポイントにおけるすべてのファイル I/O アクセスを管理することです。例えば、ファイル・サブシステムがマウント・ポイント /mnt/rozipfsに登録されている場合、fopen(“/mnt/rozipfs/myfile”, “r”)など、このディレクトリにおけるすべてのファイル・アクセスは、そのファイル・サブシステムに対して実行されます。

キャラクタ・モード・デバイスと同様に、ファイル・サブシステム内のファイルは、fopen()や fread()など、file.hで定義された Cのファイル I/O関数を使用して操作できます。これらの関数の使用法の詳細については、10–1ページの「HAL APIリファレンス」を参照してください。

Page 20: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–10 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

タイマ・デバイスの使用

タイマ・デバイスの使用

タイマ・デバイスとは、クロックをカウントし、周期的な割り込み要求を生成できるハードウェア・ペリフェラルです。タイマ・デバイスを使用すると、HALシステム・クロック、アラーム、時刻、時間測定など、時間に関連する多数の機能を実現できます。タイマ機能を使用するには、Nios II プロセッサ・システムのハードウェアにタイマ・ペリフェラルが含まれていることが必要です。

HAL APIは、2種類のタイマ・デバイス・ドライバを提供します。1つは、アラーム機能を可能にするシステム・クロック・ドライバ、もう 1つは、高精度の時間測定を可能にするタイムスタンプ・ドライバです。特定のタイマ・ペリフェラルは、どちらか一方のみ動作できますが、両方同時には動作できません。

HALでは、標準 UNIX関数の gettimeofday()、settimeofday()、および times()が実装されています。

タイマ・デバイスにアクセスするための HAL 特有の API 関数は、sys/alt_alarm.hおよび sys/alt_timestamp.hで定義されています。

これらの関数の使用法の詳細については、10–1 ページの「HAL APIリファレンス」を参照してください。

HALシステム・クロックHALシステム・クロック・ドライバは、周期的な「ハートビート」を供給して、各ビートごとにシステム・クロックを増加させます。システム・クロック機能を使用すると、指定した時間に関数を実行したり、タイミング情報を取得したりすることができます。特定のハードウェア・タイマ・ペリフェラルをシステム・クロック・デバイスとして関連付けるには、Nios II IDEでシステム・ライブラリのプロパティを設定します。

詳細については、Nios II IDEオンライン・ヘルプを参照してください。

システム・クロックは、「チック」の単位で時間を測定します。ハードウェアとソフトウェアの両方を扱うエンベデッド・エンジニアは、HALシステム・クロックと、Nios II プロセッサ・ハードウェアの同期化に使用されるクロック信号を混同しないように注意してください。HALシステム・クロック・チックの周期は、ハードウェア・システム・クロックよりもはるかに長くなります。

Page 21: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–112004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

システム・クロックの現在の値は、alt_nticks()関数を呼び出すと取得できます。この関数は、リセット以降の経過時間をシステム・クロック・チック単位で返します。システム・クロック・レート(チック /秒)は、関数 alt_ticks_per_second()を使用すれば取得できます。HALタイマ・ドライバは、システム・クロックのインスタンスを作成したときに、チック周波数を初期化します。

標準 UNIX関数 gettimeofday()を利用すれば、現在の時間を取得できます。まず、settimeofday() を呼び出して、時刻をキャリブレートすることが必要です。さらに、times() 関数を使用して、経過したチック数に関する情報を取得することもできます。これらの関数は、times.hで定義されています。

アラーム

HALアラーム機能を使用して、指定した時間に実行する関数が登録できます。アラームは、関数 alt_alarm_start() を呼び出すと、登録されます。

int alt_alarm_start (alt_alarm* alarm, alt_u32 nticks, alt_u32 (*callback) (void* context), void* context);

関数 callbackは、nticksが経過した後に呼び出されます。入力引数contextは、呼び出しが発生したときに、入力引数として callbackに渡されます。入力引数 alarm が示す構造体は、alt_alarm_start()への呼び出しによって初期化されます。この構造体を初期化する必要はありません。

このコールバック関数はアラームをリセットできます。登録したコールバック関数の戻り値は、次回の callback へのコールまでに経過するチック数です。戻り値がゼロであれば、アラームの停止が必要であることを意味します。alt_alarm_stop() を呼び出すと、アラームを手動でキャンセルできます。

アラーム・コールバック関数の記述には注意が必要です。これらの関数は、多くの場合、割り込み処理の中で実行され、機能に特定の制約が課されます(6–1ページの「例外処理」を参照してください)。

Page 22: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–12 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

タイマ・デバイスの使用

以下に、1 秒ごとに周期的なコールバックを行うように、アラームを登録する方法を示すコードの一部分を示します。

例:周期的なアラーム・コールバック関数の使用

#include <stddef.h>#include <stdio.h>#include “sys/alt_alarm.h”#include “alt_types.h”

/* * コールバック関数 */

alt_u32 my_alarm_callback (void* context){ /* この関数は、1秒ごとに呼び出されます。 */ return alt_ticks_per_second();}

...

/* alt_alarmは、アラームの期間存続することが必要です。 */static alt_alarm alarm;

...

if (alt_alarm_start (&alarm, alt_ticks_per_second(), my_alarm_callback, NULL) < 0) { printf (“No system clock available\n”); }

高精度時間測定

場合によっては、HALシステム・クロック・チックで得られるレベルを上回る精度で、時間間隔の測定が必要になることも考えられます。HALは、タイムスタンプ・ドライバを使用する高精度タイミング関数を提供しています。タイムスタンプ・ドライバは、単調に増加するカウンタを提供するため、このカウンタをサンプリングして、タイミング情報を取得できます。HALはシステム内に 1つのタイムスタンプ・ドライバのみサポートします。

タイムスタンプ・ドライバが存在すれば、関数alt_timestamp_start()および alt_timestamp() が利用可能になります。アルテラが提供するタイムスタンプ・ドライバは、Nios II IDEのシステム・ライブラリ・プロパティ・ページで、ユーザが選択したタイマを使用します。

Page 23: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–132004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

関数 alt_timestamp_start()を呼び出すと、カウンタが動作を開始します。続いて alt_timestamp()を呼び出すと、タイムスタンプ・カウンタの現在の値が返されます。再び alt_timestamp_start()を呼び出せば、カウンタはゼロにリセットされます。カウンタが(232 – 1)に達したときのタイムスタンプ・ドライバの動作は定義されていません。

関数 alt_timestamp_freq()を呼び出すと、タイムスタンプ・カウンタが増加するレートを取得できます。一般にこのレートは、Nios II プロセッサ・システムが動作するハードウェア周波数(通常、毎秒数百万サイクル)です。タイムスタンプ・ドライバは、alt_timestamp.hヘッダ・ファイルで定義されます。

以下のコードは、タイムスタンプ機能を使用して、コード実行時間を測定する方法の一部分です。

例:コード実行時間を測定するためのタイムスタンプの使用

#include <stdio.h>#include “sys/alt_timestamp.h” #include “alt_types.h”

int main (void){ alt_u32 time1; alt_u32 time2; alt_u32 time3;

if (alt_timestamp_start() < 0) { printf (“No timestamp device available\n”); } else { time1 = alt_timestamp(); func1(); /* 最初にモニタする関数 */ time2 = alt_timestamp(); func1(); /* 2番目にモニタする関数 */ time3 = alt_timestamp();

printf (“time in func1 = %u ticks\n”, (unsigned int) (time2 – time1));

printf (“time in func2 = %u ticks\n”, (unsigned int) (time3 – time2));

printf (“Number of ticks per second = %u\n”, (unsigned int)alt_timestamp_freq());

} return 0;}

Page 24: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–14 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

フラッシュ・デバイスの使用

フラッシュ・デバイスの使用

HALは、不揮発性フラッシュ・メモリ・デバイス用の汎用デバイス・モデルを提供します。フラッシュ・メモリは、専用のプログラミング・プロトコルを使用して、データを格納します。HAL API は、データをフラッシュに書き込むための関数を提供します。例えば、これらの関数を使用して、フラッシュ・ベースのファイル・サブシステムを実装できます。

また、HAL APIは、フラッシュを読み取るための関数を提供します。ただし、一般にこの機能は不要です。大部分のフラッシュ・デバイスでは、プログラムは読み取りの際にフラッシュ・メモリ空間をシンプルなメモリとして扱うことができ、専用の HAL API 関数を呼び出す必要はありません。フラッシュ・デバイスに、アルテラ EPCSシリアル・コンフィギュレーション・デバイスなど、データ読み取り専用プロトコルが用意されている場合、データの読み取りと書き込みのどちらも、HAL APIを使用して実行する必要があります。

このセクションでは、フラッシュ・デバイス・モデル用の HAL API について説明します。以下の 2つの APIは、異なるレベルでフラッシュへのアクセスを可能にします。

■ シンプル・フラッシュ・アクセス-バッファをフラッシュに書き込み、フラッシュからその内容を読み取るためのシンプルな APIです。他のフラッシュ消去ブロックの以前の内容は保持されません。

■ 高精度フラッシュ・アクセス-個々のブロックへの書き込みまたはブロックの消去において、制御を必要とするプログラム用の高精度な関数です。一般に、この機能はファイル・サブシステムの管理に必要です。

フラッシュ・デバイスにアクセスするための API関数は、sys/alt_flash.hで定義されています。

これらの関数の使用法の詳細については、10–1 ページの「HAL APIリファレンス」を参照してください。

Page 25: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–152004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

シンプル・フラッシュ・アクセス

このインタフェースは、alt_flash_open_dev()、alt_write_flash()、alt_read_flash()、およびalt_flash_close_dev()で構成されています。4–16 ページの「例:シンプル・フラッシュ API 関数の使用」のコードは、これらすべての関数の使い方を、1 つのコード例で示しています。alt_flash_open_dev()を呼び出してフラッシュ・デバイスをオープンすると、フラッシュ・デバイスへのファイル・ハンドルが返されます。この関数は、system.h で定義されているとおり、唯一の引数としてフラッシュ・デバイスの名前を受け取ります。

ハンドルを取得すれば、alt_write_flash()関数を使用して、フラッシュ・デバイスにデータを書き込むことができます。プロトタイプは以下のとおりです。

int alt_write_flash(alt_flash_fd* fd, int offset, const void* src_addr, int length )

この関数を呼び出すと、ハンドル fd で識別されるフラッシュ・デバイスに、先頭から offset バイトの書き込みが実行されます。書き込むデータは、src_addrで指定されるアドレスから送られ、そのデータ量は lengthです。

また、フラッシュ・デバイスからのデータの読み取りには、alt_read_flash() 関数も利用できます。プロトタイプは以下のとおりです。

int alt_read_flash( alt_flash_fd* fd, int offset, void* dest_addr, int length )

この関数を呼び出すと、ハンドル fd を持つフラッシュ・デバイスの先頭から offset バイトが読み取られます。データは、dest_addr で示される位置に書き込まれ、データ量は length です。大部分のフラッシュ・デバイスでは、標準メモリとしてメモリ内容にアクセスできるため、alt_read_flash()を使用する必要はありません。

関数 alt_flash_close_dev() は、ファイル・ハンドルを受け取ってデバイスをクローズします。この関数のプロトタイプは以下のとおりです。

void alt_flash_close_dev(alt_flash_fd* fd )

Page 26: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–16 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

フラッシュ・デバイスの使用

以下のコードは、system.hで定義された /dev/ext_flashという名前のフラッシュ・デバイスに、シンプル・フラッシュAPI関数を使用してアクセスする方法を示します。

例:シンプル・フラッシュ API関数の使用

#include <stdio.h>#include <string.h>#include “sys/alt_flash.h”#define BUF_SIZE1024

int main (){alt_flash_fd* fd;int ret_code;

char source[BUF_SIZE]; char dest[BUF_SIZE]; /* ソース・バッファをすべて 0xAAに初期化 */ memset(source, 0xa, BUF_SIZE);

fd = alt_flash_open_dev(“/dev/ext_flash”); if (fd) { ret_code = alt_write_flash(fd, 0, source, BUF_SIZE); if (!ret_code) { ret_code = alt_read_flash(fd, 0, dest, BUF_SIZE); if (!ret_code) { /*

* 成功* この時点で、フラッシュはすべて 0xaとなり、* フラッシュの内容がすべて destに読み戻されているはずです。*/

} } alt_flash_close_dev(fd); } else { printf(“Can’t open flash device\n”); }return 0;

}

Page 27: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–172004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

ブロックの消去または破壊

一般に、フラッシュ・メモリは複数のブロックに分割されます。ブロックにデータを書き込む前に alt_write_flash() で、ブロックの内容を消去しなければならないことがあります。この場合、ブロックの既存の内容は保存されません。ブロック境界をまたいで書き込みを行う場合も、この動作によって予期しないデータ破壊(消去)が発生することがあります。現在のフラッシュ・メモリの内容を保存する場合は、より高精度なフラッシュ関数を使用します。4–18ページの「高精度フラッシュ・アクセス」を参照してください。

表 4–3は、シンプルなフラッシュ・アクセス関数を使用した書き込みによって、予期しないデータ破壊がどのようにして発生するかを示します。表 4–3は、2つの 4Kバイト・ブロックで構成される 8Kバイトのフラッシュ・メモリの例を示します。最初に、すべて 0xAAからなる 5 Kバイトを、フラッシュ・メモリのアドレス 0x0000に書き込み、次にすべて0xBBからなる2 Kバイトをアドレス0x1400に書き込みます。最初の書き込みが成功すると(時刻 t(2))、フラッシュ・メモリには 0xAAが 5 Kバイト格納され、それ以外は空(つまり、0xFF)になります。次に、2回目の書き込みが開始されますが、2 番目のブロックに書き込む前に、このブロックが消去されます。この時点(t(3))で、フラッシュ・メモリには、0xAAが 4 Kバイト、0xFFが 4 Kバイト格納されています。2回目の書き込みが終了すると(t(4))、アドレス 0x1000にある 2 Kバイトの0xFFが予期せず破壊されます。

表 4–3.フラッシュへの書き込みと予期しないデータ破壊発生の例

アドレス ブロック

時刻 t(0) 時刻 t(1) 時刻 t(2) 時刻 t(3) 時刻 t(4)

1回目の書き込み前

1回目の書き込み 2回目の書き込み

ブロックの消去後

データ 1の書き込み後

ブロックの消去後

データ 2の書き込み後

0x0000 1 ?? FF AA AA AA

0x0400 1 ?? FF AA AA AA

0x0800 1 ?? FF AA AA AA

0x0C00 1 ?? FF AA AA AA

0x1000 2 ?? FF AA FF FF (1)

0x1400 2 ?? FF FF FF BB

0x1800 2 ?? FF FF FF BB

0x1C00 2 ?? FF FF FF FF

表 4–3の注:(1) 2回目の書き込みのための消去中に、予期せずクリアされて FFに変化した。

Page 28: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–18 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

フラッシュ・デバイスの使用

高精度フラッシュ・アクセス

その他にも、フラッシュへの書き込みを最高レベルの精度で完全に制御する 3つの関数

alt_get_flash_info()alt_erase_flash_block()alt_write_flash_block()

があります。

フラッシュ・メモリの性質上、あるブロック内の 1アドレスだけを消去することはできません。一度にブロック全体を消去(つまり、すべて 1に設定)する必要があります。フラッシュ・メモリへの書き込みでは、ビットが 1から 0に変化するだけで、どのビットでも 0から 1に変更するには、そのビットが含まれるブロック全体を消去する必要があります。したがって、ブロック内の特定の位置のみ変更し、周囲の内容が変化しないようにするには、ブロック全体の内容をバッファに読み出し、バッファ内で値を変更し、フラッシュ・ブロックを消去して、最後にブロック・サイズのバッファ全体をフラッシュ・メモリに書き戻すことが必要です。高精度フラッシュ・アクセス関数を利用すれば、このプロセスをフラッシュ・ブロック・レベルで実行できます。

alt_get_flash_info()は、消去領域の数、各領域内の消去ブロック数、および各消去ブロックのサイズを取得します。プロトタイプは以下のとおりです。

int alt_get_flash_info( alt_flash_fd* fd, flash_region** info, int* number_of_regions)

呼び出しが成功した場合、関数が返された時点で、number_of_regionsが示すアドレスには、フラッシュ・メモリ内の消去領域の数が格納されており、infoは 1番目の flash_regionで記述されるアドレスを示しています。

flash_region 構造体は sys/alt_flash_types.h で定義され、そのtypedefは以下のとおりです。

typedef struct flash_region{ int offset;/* フラッシュの開始位置からこの領域までのオフセット */ int region_size;/* この消去領域のサイズ */ int number_of_blocks;/* この領域のブロック数 */ int block_size;/* この消去領域内の各ブロックのサイズ */}flash_region;

Page 29: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–192004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

alt_get_flash_info()を呼び出して情報を取得すると、フラッシュのブロックを個別に消去またはプログラムできます。

alt_erase_flash()は、フラッシュ・メモリ内の単一のブロックを消去します。プロトタイプは以下のとおりです。

int alt_erase_flash_block( alt_flash_fd* fd, int offset,

int length)

フラッシュ・メモリは、ハンドル fd で識別されます。ブロックは、フラッシュ・メモリの先頭からの offsetバイトとして認識され、ブロック・サイズは lengthに渡されます。

alt_write_flash_block()は、フラッシュ・メモリ内の 1ブロックに書き込みを実行します。プロトタイプは以下のとおりです。

int alt_write_flash_block( alt_flash_fd* fd, int block_offset, int data_offset, const void *data, int length)

この関数は、ハンドル fdで識別されるフラッシュ・メモリに書き込みを実行します。フラッシュの先頭から block_offsetバイトの位置にあるブロックに書き込みます。この関数は、dataで示された位置からlengthバイトのデータを、フラッシュ・デバイスの先頭から data_offset バイトの位置に書き込みます。

これらのプログラムおよび消去関数では、アドレス・チェックは実行されず、また書き込み操作の範囲が隣のブロックに及ぶかどうかも検証されません。プログラムまたは消去するブロックについて、適切な情報を渡すことが必要です。

以下のコードは、高精度フラッシュ・アクセス関数の使用法を示します。

例:高精度フラッシュ・アクセス API関数の使用

#include <string.h>#include "sys/alt_flash.h"#define BUF_SIZE 100

int main (void){ flash_region* regions; alt_flash_fd* fd; int number_of_regions; int ret_code; char write_data[BUF_SIZE];

Page 30: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–20 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

DMAデバイスの使用

/* write_dataをすべて 0xaに設定 */ memset(write_data, 0xA, BUF_SIZE);

fd = alt_flash_open_dev(EXT_FLASH_NAME);

if (fd) { ret_code = alt_get_flash_info(fd,

&regions, &number_of_regions);

if (number_of_regions && (regions->offset == 0)) { /* 1番目のブロックを消去 */ ret_code = alt_erase_flash_block(fd,

regions->offset, regions->block_size); if (ret_code) {

/* * write_dataから BUF_SIZEバイト、つまり 100バイトを* フラッシュの 1番目のブロックに書き込みます*/

ret_code = alt_write_flash_block( fd, regions->offset,

regions->offset+0x100, write_data,

BUF_SIZE); } } }return 0;

}

DMAデバイスの使用

HALは、DMA(Direct Memory Access)デバイスに対応するデバイス抽象化モデルを提供します。これらのモデルは、データ・ソースからディスティネーションへのバルク・データ転送を実行するペリフェラルです。イーサネット接続など、メモリやその他のデバイスをソースおよびディスティネーションにすることができます。

HAL DMAデバイス・モデルにおいて、DMA転送は、2つのカテゴリ、つまり送信と受信のいずれかに分類されます。したがって、HALは送信チャネルと受信チャネルを実装するために、2 つのデバイス・ドライバを提供しています。送信チャネルは、ソース・バッファにデータを受け取り、それをディスティネーション・デバイスに送信します。受信チャネルは、デバイスからデータを受信し、ディスティネーション・バッファに格納します。基本ハードウェアの実装状態に応じて、ソフトウェアでは、これら 2つのエンドポイントの一方のみにアクセスすることもできます。

Page 31: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–212004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

図 4-2 に、DMA 転送の 3 つの基本形式を示します。メモリ間でデータをコピーする場合、受信 DMAチャネルと送信 DMAチャネルを同時に使用します。

図 4-2. DMA転送の 3つの基本形式

DMAデバイスにアクセスするための API関数は、sys/alt_dma.hで定義されています。

これらの関数の使用法の詳細については、10–1 ページの「HAL APIリファレンス」を参照してください。

DMA デバイスは、物理メモリの内容を操作するため、データの読み取りおよび書き込みを行う際には、キャッシュの相互作用を考慮する必要があります。7–1ページの「キャッシュ・メモリ」を参照してください。

DMA送信チャネルDMA送信要求は、DMA送信デバイスのハンドルを使用して、キューに格納されます。ハンドルは関数 alt_dma_txchan_open()を使用して取得します。この関数は、system.hで定義されているように、1つの引数(使用するデバイスの名前)のみ受け取ります。

1.ペリフェラルからのデータの受信

DMARecieveChannel

ペリフェラル メモリ

2. ペリフェラルへのデータの送信

DMA受信

チャネル

ペリフェラル

DMA送信

チャネル

DMA受信

チャネル

DMA送信

チャネル

3.メモリ間でのデータの転送

メモリ

メモリメモリ

Page 32: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–22 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

DMAデバイスの使用

以下のコードは、DMA送信デバイス dma_0のハンドルを取得する方法を示します。

例:DMAデバイスのファイル・ハンドルの取得

#include <stddef.h>#include “sys/alt_dma.h”

int main (void){ alt_dma_txchan tx;

tx = alt_dma_txchan_open (“/dev/dma_0”); if (tx == NULL) { /* エラー */ } else { /* 成功 */ } return 0;}

このハンドルを使用すると、alt_dma_txchan_send() によって送信要求を送信できます。プロトタイプは以下のとおりです。

typedef void (alt_txchan_done)(void* handle);

int alt_dma_txchan_send (alt_dma_txchan dma, const void* from, alt_u32 length, alt_txchan_done* done, void* handle);

alt_dma_txchan_send()を呼び出すと、チャネルdmaに送信要求が送信され、lengthバイトのデータがアドレス fromから送信されます。この関数は、すべての DMA転送が完了する前に呼び出し元に復帰します。戻り値は、要求が正常にキューに格納されたかどうかを示します。負の戻り値は、要求が失敗したことを示します。転送が完了すると、通知を行うために引数 handleを渡して、ユーザ提供の関数 doneが呼び出されます。

DMA送信チャネルを操作するために、さらに 2つの関数alt_dma_txchan_space()、alt_dma_txchan_ioctl()が提供されています。alt_dma_txchan_space()関数は、デバイスのキューに格納できる追加送信要求数を返します。alt_dma_txchan_ioctl()関数は、送信デバイスのデバイス固有操作を実行します。

Page 33: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–232004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

DMA受信チャネルDMA 受信チャネルは、DMA 送信チャネルと同様の方式で動作します。DMA受信チャネルのハンドルは、alt_dma_rxchan_open()関数を使用して取得できます。ハンドルを取得すると、alt_dma_rxchan_prepare()関数を使用して、受信要求を送信できます。alt_dma_rxchan_prepare()のプロトタイプは以下のとおりです。

typedef void (alt_rxchan_done)(void* handle, void* data);

int alt_dma_rxchan_prepare (alt_dma_rxchan dma, void* data, alt_u32 length, alt_rxchan_done* done, void* handle);

この関数を呼び出すと、受信要求がチャネル dma に送信され、最大でlegthバイトのデータがアドレスdataに置かれます。この関数は、DMA転送が完了する前に呼び出し元に復帰します。戻り値は、要求が正常にキューに格納されたかどうかを示します。負の戻り値は、要求が失敗したことを示します。転送が完了すると、通知を行うための引数 handle、およびデータを受け取るためのポインタを渡して、ユーザが提供した関数 doneが呼び出されます。

DMA受信チャネルを操作するために、さらに 2つの関数alt_dma_rxchan_depth()、alt_dma_rxchan_ioctl()が用意されています。

alt_dma_rxchan_depth()関数は、デバイスのキューに格納できる最大受信要求数を返します。alt_dma_rxchan_ioctl()関数は、受信デバイスのデバイス固有操作を実行します。

以下のコードは、DMA受信要求を送信し、転送が完了するまで main()で待機するアプリケーション例を示します。

例:受信チャネルでの DMA転送

#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include “sys/alt_dma.h”#include “alt_types.h”

/* 転送の完了を示すために使用するフラグ */volatile int dma_complete = 0;

/* 転送が完了したときに呼び出される関数 */void dma_done (void* handle, void* data)

Page 34: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–24 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

DMAデバイスの使用

{ dma_complete = 1;}

int main (void){ alt_u8 buffer[1024]; alt_dma_rxchan rx;

/* デバイスのハンドルを取得 */ if ((rx = alt_dma_rxchan_open (“/dev/dma_0”)) == NULL) { printf (“Error:failed to open device\n”); exit (1); } else { /* 受信要求を送信 */ if (alt_dma_rxchan_prepare (rx, buffer, 1024, dma_done, NULL)

< 0) { printf (“Error:failed to post receive request\n”); exit (1); } /* 転送が完了するまで待機 */ while (!dma_complete); printf (“Transaction complete\n”); alt_dma_rxchan_close (rx); } return 0;}

メモリ間 DMA転送メモリ・バッファの間でデータをコピーするには、受信 DMAドライバと送信 DMAドライバの両方が必要です。以下のコードは、受信要求に続いて送信要求をキューに格納して、メモリ間 DMA転送を実現するプロセスを示します。

例:メモリ間でのデータのコピー

#include <stdio.h>#include <stdlib.h>

#include "sys/alt_dma.h"#include "system.h"

static volatile int rx_done = 0; /* * データ受信の完了を示す通知を取得する * コールバック関数 */

Page 35: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–252004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

static void done (void* handle, void* data){ rx_done++;}

/* * */ int main (int argc, char* argv[], char* envp[]){ int rc;

alt_dma_txchan txchan; alt_dma_rxchan rxchan;

void* tx_data = (void*) 0x901000; /* 送信するデータを示すポインタ */ void* rx_buffer = (void*) 0x902000; /* rxバッファを示すポインタ */

/* 転送チャネルを作成 */ if ((txchan = alt_dma_txchan_open("/dev/dma_0")) == NULL) { printf ("Failed to open transmit channel\n"); exit (1); } /* 受信チャネルを作成 */ if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL) { printf ("Failed to open receive channel\n"); exit (1); } /* 送信要求を送信 */ if ((rc = alt_dma_txchan_send (txchan,

tx_data, 128, NULL, NULL)) < 0)

{ printf ("Failed to post transmit request, reason = %i\n", rc); exit (1); } /* 受信要求を送信 */ if ((rc = alt_dma_rxchan_prepare (rxchan,

rx_buffer, 128, done, NULL)) < 0)

{

Page 36: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–26 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

コード・フットプリントの削減

printf ("Failed to post read request, reason = %i\n", rc); exit (1); }

/* 転送が完了するまで待機 */ while (!rx_done);

printf ("Transfer successful!\n");

return 0;}

コード・フットプリントの削減

コードを格納するメモリ・デバイスにはコストがかかるため、コード・サイズは常にシステム開発者の悩みです。コード・サイズのコントロールと削減は、このコストを管理する上で重要です。

HAL環境は、一般にユーザが要求する機能のみが全体的なコード・フットプリントに関与するように設計されています。ユーザの Nios II ハードウェア・システムに、プログラムで使用するだけのペリフェラルしかない場合、HALはそのハードウェアを制御するのに必要なドライバしか持つ必要はありません。

以下のセクションでは、コード・サイズを絶対最小サイズに削減する必要がある場合に検討すべきオプションについて説明します。

コンパイラ最適化の有効化

nios2-elf-gcc コンパイラに -O3 compiler 最適化レベルを使用します。すると、コードはサイズと速度の両方が最大限に最適化されてコンパイルされます。これは、システム・ライブラリとアプリケーション・プロジェクトの両方に対して行う必要があります。

スモール・フットプリント・デバイス・ドライバの使用

いくつかのデバイスでは、フル機能の「高速」型、および軽量の「スモール」型の 2つの改良型ドライバが用意されています。これら 2つの改良型によって、どの機能が利用できるかは、デバイスによって異なります。デフォルトで、HALシステム・ライブラリは常に高速型ドライバを使用します。Nios II IDEでHALシステム・ライブラリのUse Small FootprintDrivers オプションをオンにすると、スモール・フットプリント・ドライバを選択できます。HALシステム・ライブラリを構築するときには、プリプロセッサ・オプション –DALT_USE_SMALL_DRIVERSが利用できます。

Page 37: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–272004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

表 4–4に、スモール・フットプリント・ドライバを提供するアルテラ製Nios II ペリフェラルを示します。また、その他のペリフェラルもスモール・フットプリント・オプションに影響されることがあります。スモール・フットプリント・ドライバの動作に関する詳細は、各ペリフェラルのデータシートを参照してください。

ファイル・ディスクリプタ・プールの削減

キャラクタ・モード・デバイスおよびファイルにアクセスするファイル・ディスクリプタは、利用可能なファイル・ディスクリプタのプールから割り当てられます。このプールのサイズは、コンパイル時の定数ALT_MAX_FDによって定義され、Nios II IDEのシステム・ライブラリ・プロパティとして管理できます。デフォルトは 32です。例えば、プログラムで 10のみ必要であれば、ALT_MAX_FDの値を小さくすることによって、メモリ・フットプリントを削減できます。

/dev/nullの使用ブート時において、標準入力、標準出力、および標準エラーは、すべてnull デバイス、つまり /dev/null に送られます。これによって、ドライバの初期化中に printf()を呼び出しても何も実行されず、動作に影響を与えません。すべてのドライバがインストールされると、これらのストリームは、HALで構成されたチャネルにリダイレクトされます。このリダイレクトを実行するコードのフットプリントは小さなものですが、stdin、stdout、および stderrに対して nullを選択すれば、リダイレクトを完全に回避できます。このように選択するには、標準出力または標準エラーに対して送信されたすべてのデータを破棄し、プログラムで stdin を介した入力を受信しないことが前提となります。stdin、stdout、および stderrチャネルは、Nios II IDEではシステム・ライブラリ・プロパティとして制御できます。

表 4–4. P. スモール・フットプリント・ドライバを提供するアルテラのペリフェラル

ペリフェラル スモール・フットプリント動作

UART IRQ駆動ではなく、ポーリングによって動作します。

JTAG UART IRQ駆動ではなく、ポーリングによって動作します。

共通フラッシュ・インタフェース・コントローラ

ドライバは、スモール・フットプリント・モードでは除外されます。

LCDモジュール・コントローラ ドライバは、スモール・フットプリント・モードでは除外されます。

Page 38: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–28 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

コード・フットプリントの削減

ANSI Cではなく UNIXファイル I/Oの使用UNIX形式のファイル I/O関数を使用してデバイスやファイルにアクセスすると、アクセスごとにそれに付随するパフォーマンス・オーバヘッドが発生します。パフォーマンスを改善するために、ANSI C ファイルI/Oを使用することでバッファ使用のアクセスが可能になり、実行されるハードウェア I/O アクセスの総数が少なくなります。また、ANSI CAPI は柔軟性が高く、使いやすくなります。しかし、これらの利点は、コード・フットプリントを犠牲にして実現されています。UNIX 形式のI/O APIを直接使用することで、コード・フットプリントを削減することが可能です。4–5 ページの「UNIX 形式のインタフェース」を参照してください。

縮小版 Newlib Cライブラリの使用多くの場合、エンベデッド・システムには完全な ANSI C標準ライブラリは不要です。HAL は、一般にエンベデッド・システムでは不要なnewlibの機能を取り除くために、newlib ANSI C標準ライブラリの縮小版を提供します。縮小版の newlib 実装には、小さなコード・フットプリントが必要です。この newlib実装は、Nios II IDEではシステム・ライブラリ・プロパティとして制御できます。また、このオプションは、nios2-elf-gccの -msmallcコマンドライン・オプションでも制御できます。

縮小版の newlib Cライブラリがサポートする関数の詳細については、NiosII 開発キットと共にインストールされた newlib の資料を参照してください。(Windowsのスタート・メニューから)プログラム > Altera > Nios IIDevelopment Kit > Nios II Documentationの順にクリックします。

Page 39: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–292004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

表 4–5に、縮小版 newlib Cライブラリ実装の制限事項を要約します。

表 4–5.縮小版 newlib Cライブラリの制限事項

制限事項 影響する関数

printf()ルーチン・ファミリに対しては浮動小数点はサポートされません。右記の関数は実装されていますが、%fオプションと %gオプションはサポートされていません。

asprintf()fiprintf()fprintf()iprintf()printf()siprintf()snprintf()sprintf()vasprintf()vfiprintf()vfprintf()vprintf()vsnprintf()vsprintf()

scanf()ルーチン・ファミリはサポートされません。右記の関数は、サポートされていません。

fscanf()scanf()sscanf()vfscanf()vscanf()vsscanf()

シークはサポートされていません。右記の関数は、サポートされていません。 fseek()ftell()

FILE *のオープン /クローズはサポートされていません。既にオープンされたstdout、stderr、および stdinのみ利用できます。右記の関数は、サポートされていません。

fopen()fclose()fdopen()fcloseall()fileno()

FILE *ルーチン(つまり、すべての stdio.hルーチン)のバッファ機能はありません。

stdio.hで定義されたすべてのルーチン。

これらの関数は、サポートはされていますが、バッファ機能はありません。

setbuf()およびsetvbuf()はサポートされていません。

ロケールはサポートされていません。 setlocale()localeconv()

上記の関数がサポートされていないため、C++のサポートはありません。

Page 40: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–30 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

コード・フットプリントの削減

未使用デバイス・ドライバの除去

ハードウェア・デバイスがシステムに存在する場合、Nios II IDEは、そのデバイスがドライバを必要するものと想定し、それに応じて HAL システム・ライブラリを構成します。適切なドライバを見つけることができれば、HALはこのドライバのインスタンスを作成します。ユーザ・プログラムで実際にデバイスにアクセスしない場合、デバイス・ドライバの初期化にリソースが不必要に消費されることになります。

デバイスがハードウェアに含まれているが、ユーザ・プログラムを使用しない場合は、デバイスを完全に削除するオプションを検討する必要があります。これによって、コード・フットプリントと FPGAリソースがともに削減されます。ただし、デバイスが存在してもソフトウェアがドライバを必要としない、回避不能なケースもあります。

最も一般的な例は、フラッシュ・メモリです。この場合、ユーザ・プログラムはフラッシュ・メモリへの書き込みアクセスが必要ないことが多いため、フラッシュ・ドライバも不要です。このような場合、オプション –DALT_NO_CFI_FLASH をプリプロセッサに指定すれば、HAL がフラッシュ・ドライバをシステム・ライブラリに組み込まないようにすることができます。

独立した環境を使用して、デバイス・ドライバの初期化プロセスをより詳細に制御できます。4–31ページの「ブート・シーケンスおよびエントリ・ポイント」を参照してください。

非完全終了に対する _exit()の使用HALは、システム・シャットダウン時に exit()関数を呼び出して、プログラムからの終了を実現します。exit()は Cライブラリの内部 I/Oバッファをすべて消去し、atexit()に登録された関数を呼び出します。特に、exit()は main()から戻るときに呼び出されます。

一般に、エンベデッド・システムは終了することがないため、このコードは冗長となります。クリーンな終了の実現に伴うオーバヘッドを回避するために、ユーザ・プログラムでは、exit()関数の代わりに _exit()関数が使用できます。この関数ではソース・コードの変更は必要ありません。終了動作は、Nios II IDEでのシステム・ライブラリ・プロパティとして、またはプリプロセッサ・オプション -Dexit=_exit を指定することによって制御できます。

Page 41: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–312004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

命令エミュレーションの無効化

HALソフトウェア例外ハンドラは、プロセッサが乗算命令および除算命令をサポートしていない場合は、これらの命令をエミュレートできます。この機能は、システム・ライブラリ・プロジェクトの C プリプロセッサ・マクロ ALT_NO_INSTRUCTION_EMULATIONを定義すれば無効にできます。

使用中のコアがハードウェア乗算 / 除算をサポートしていれば、プロセッサがハードウェア乗算 /除算をサポートしていない場合でも、ほとんどのケースでこの機能を無効にすることができます。ハードウェア乗算 /除算命令をサポートしていないシステムに対して構築された、システム・ライブラリ・プロジェクトおよびアプリケーション・プロジェクトは、-mno-hw-mul オプションを指定してコンパイルおよびリンクされます。したがって、これらのプロジェクトの一部としてコンパイルされたコードに対しては、乗算命令のエミュレーションは不要です。除算命令エミュレーションは、–mhw-divオプションを指定してコードを明示的にコンパイルする場合のみ必要です。

ブート・シーケンスおよびエントリ・ポイント

これまでの説明では、プログラムのエントリ・ポイントを関数 main()と仮定していました。それに代わって利用できるエントリ・ポイントとして alt_main()があり、これを使用するとブート・シーケンスをより高度に制御できます。main()または alt_main()からのエントリの概念は、ホスト型アプリケーションと独立型アプリケーションの違いです。

ホスト型アプリケーションと独立型アプリケーション

ANSI C 規格では、ホスト型アプリケーションは、main() を呼び出して実行を開始するアプリケーションとして定義されています。main()の開始時に、ホスト型アプリケーションは、ランタイム環境およびすべてのシステム・サービスが初期化され、使用できる準備が整っていると仮定しています。HALシステム・ライブラリでも同様に仮定されます。事実、ホスト型環境では、システム内にどのデバイスが存在するか把握したり、各デバイスの初期化方法を考慮する必要がなく、HALがシステム全体を自動的に初期化するため、Nios II を初めて使用するプログラマにとって、ホスト型環境は HALの最大の利点の 1つです。

Page 42: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–32 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

ブート・シーケンスおよびエントリ・ポイント

ANSI C 規格は、自動初期化を回避する代替エントリ・ポイントも用意しており、Nios II プログラマが使用されているハードウェアを手動で初期化することを想定しています。alt_main()関数は独立型環境を提供し、ユーザはシステムの初期化を完全に制御できます。独立型環境では、プログラマはプログラムで使用されるシステム機能を手動で初期化する必要があります。例えば、独立型環境では、alt_main()が最初にキャラクタ・モード・デバイス・ドライバをインスタンス化し、stdout をデバイスにリダイレクトしない限り、printf()を呼び出しても正しく機能しません。

独立型環境を使用すると、ユーザは HAL の利点を利用できず、システムの初期化をすべて手動で実行しなければならないため、Nios II プログラムの記述は複雑になります。独立型環境を検討する主な目的が、コード・フットプリントの削減の場合は、4–26ページの「コード・フットプリントの削減」で説明した推奨事項を考慮してください。HAL システム・ライブラリのフットプリントを削減するには、独立型モードを使用するよりも、Nios IIIDEで利用できるオプションを使用する方が簡単です。

Nios II 開発キットには、独立型プログラムとホスト型プログラムの例が用意されています。

詳細については、Nios II IDEオンライン・ヘルプを参照してください。

HALベース・プログラムのブート・シーケンスHALは、以下のブート・シーケンスを実行するシステム初期化コードを提供します。

■ 命令キャッシュおよびデータ・キャッシュを消去する。■ スタック・ポインタをコンフィギュレーションする。■ グローバル・ポインタをコンフィギュレーションする。■ リンカが供給するシンボル __bss_startおよび __bss_endを使用して、BSS領域をゼロで初期化する。これらは、BSS領域の先頭および末尾を示すポインタです。

■ システム内にブート・ローダが存在しない場合に、.rwdata、.rodata、および/または例外セクションをRAMにコピーする(4–37ページの「ブート・モード」を参照)。

■ alt_main()を呼び出す。

Page 43: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–332004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

alt_main()関数を用意していない場合は、デフォルト実装が以下のステップを実行します。

■ ALT_OS_INIT() を呼び出して、オペレーティング・システム固有の必要な初期化を実行する。OS スケジューラがないシステムの場合、このマクロは無効です。

■ HAL がオペレーティング・システムで使用されている場合、HAL ファイル・システムへのアクセスを制御する alt_fd_list_lock セマフォ(semaphore)を初期化する。

■ 割り込みコントローラを初期化し、割り込みを可能にする。■ alt_sys_init() 関数を呼び出して、システム内のすべてのデバイス・ドライバとソフトウェア・コンポーネントを初期化する。NiosII IDE は、各 HAL システム・ライブラリに対応するファイルalt_sys_init.cを自動的に作成および管理します。

■ 適切なデバイスを使用するために、C 標準 I/O チャネル(stdin、stdout、および stderr)をリダイレクトする。

■ _do_ctors()関数を使用して、C++コンストラクタを呼び出す。■ システム・シャットダウン時に呼び出される C++ デストラクタを登録する。

■ main ()を呼び出す。■ exit()を呼び出し、main()の戻りコードをexit()の入力引数として渡す。

このデフォルト実装は、Nios II 開発キットのインストール・ディレクトリ内のファイル alt_main.cに記述されています。

ブート・シーケンスのカスタマイズ

Nios II IDE プロジェクトで alt_main() を定義するだけで、スタートアップ・シーケンスの独自の実装を提供できます。これにより、ブート・シーケンスを完全に制御し、HALサービスを選択することができます。ユーザのアプリケーションで alt_main()エントリ・ポイントが必要な場合、デフォルト実装を開始ポイントとしてコピーし、必要に応じてカスタマイズできます。

この関数は呼び出し元に復帰しません。alt_main()のプロトタイプは以下のとおりです。

void alt_main (void)

Page 44: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–34 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

メモリの使用

HAL構築環境の特徴の 1つは、すべてのソース・ファイルおよびインクルード・ファイルがサーチ・パスを使用して検索されることです。常にユーザのプロジェクトが最初にチェックされるため、デフォルトのデバイス・ドライバおよびシステム・コードをユーザ自身の実装に置き換えることができます。例えば、alt_sys_init.cの代わりにユーザ独自のファイルを供給する場合、そのファイルをユーザのシステム・プロジェクト・ディレクトリに置けばそれが可能です。ユーザが提供したファイルは、自動生成ファイルに優先して使用されます。

alt_sys_init()の詳細については、5–1ページの「HAL用デバイス・ドライバの開発」を参照してください。

メモリの使用 このセクションでは、HALがメモリを使用する方法と、HALがコード、データ、スタックなどをメモリ内で配置する方法について説明します。

メモリ・セクション

デフォルトでは、HALベースシステムは、Nios II IDEで作成および管理される自動生成されたリンカ・スクリプトを使用してリンクされます。このリンカ・スクリプトは、利用可能なメモリ・セクション内で、コードおよびデータのマッピングを制御します。自動生成されたリンカ・スクリプトは、システム内の各物理メモリ・デバイスに対するセクションを作成します。例えば、system.h ファイルで定義された on_chip_memory という名前のメモリ・コンポーネントが存在する場合は、.on_chip_memoryという名前のメモリ・セクションが存在します。

メモリ・デバイスに Nios II プロセッサのリセット・アドレスや例外アドレスが含まれるのは、特殊な場合です。メモリ・デバイスにこれらのアドレスのいずれかが含まれる場合、そのアドレス以下のすべてのメモリは、そのメモリ・デバイスに関連付けられたセクションから除外されます。32バイトのリセット・セクションはリセット・アドレスを開始位置として構築され、リセット・ハンドラ専用として使用するために予約されます。

このメモリ方式で作成できる使用不可領域は、マルチプロセッサ・システムの他のプロセスが使用できます。

Page 45: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–352004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

図 4-3 に、物理メモリをメモリ・セクションに分割する方法の一例を示します。あくまでも説明を目的として、この例では、リセット・アドレスおよび例外アドレスの配置によって使用不可となるメモリ領域を人為的に作成しています。デフォルトでは、アルテラのツールは、リセット・アドレスと例外アドレスをメモリにマップするため、アクセス不可のメモリは存在しません。デフォルトのメモリ・マップを使用するシステムでは、リセット・アドレスはデバイス・メモリまたはフラッシュ・メモリのオフセット 0x0 にあり、例外アドレスはシステム生成時に SOPCBuilderに指定されたメモリ内のオフセット 0x20にあります。

図 4-3. HALのメモリ・パーティション

メモリ・パーティションへのコードとデータの割り当て

このセクションでは、特定のメモリ・セクションでプログラム・コードとデータの配置を制御する方法について説明します。通常、Nios II 開発ツールは、合理的なデフォルトのパーティション作成方法を自動的に選択します。例えば、性能を向上させるための一般的な技法は、性能重視のコードとデータをアクセス・タイムが高速なデバイス RAM に配置します。また、デバッグ段階では RAM 内の位置からプロセッサをリセット(つまりブート)し、システムのリリース・バージョンではフラッシュ・メモリからブートすることも一般的です。このような場合は、どのコードがどのセクションに属するかを手動で指定する必要があります。

物理メモリ:on_chip_ram

0x0

セクション「.on_chip_ram」

物理メモリ:sdram

使用不可

セクション「.reset」

使用不可

セクション「.sdram」

0x0

リセット・アドレス

リセット・アドレス+0x10

例外アドレス

Page 46: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–36 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

メモリの使用

シンプルな配置オプション

リセット・ハンドラ・コードは常に、.reset パーティションに配置されます。例外ハンドラ・コードは常に、例外アドレスを含むセクション内の最初のコードになります。デフォルトでは、その他のコードおよびデータは、以下の 3つの出力セクションに分割されます。

■ .text-その他のすべてのコード■ .rodata-読み取り専用データ■ .rwdata-読み取りおよび書き込みデータ(ゼロに初期化されたデータを含む)

.text、.rodata、および .rwdataの配置は、Nios II IDEでシステム・ライブラリ・プロパティとして制御できます。

詳細については、Nios II IDEオンライン・ヘルプを参照してください。

高度な配置オプション

ユーザのプログラム・ソース・コード内で、特定のコードに対してターゲット・メモリ・セクションを指定できます。Cまたは C++でこの指定を行う場合は、section属性を使用できます。以下のコードは、.on_chip_memoryという名前のメモリ内の変数foo、および.sdramという名前のメモリ内の関数 bar()を配置する方法を示します。

例:特定のメモリ・セクションへの Cコードの手動による割り当て

/* セクション属性を使用する場合は、データの初期化が必要 */int foo __attribute__ ((section (".on_chip_memory"))) = 0;

void bar __attribute__ ((section (".sdram"))) (void){ foo++;}

アセンブリでは、この処理は .section 指示文を使用して実行します。例えば、次に示す行以降のすべてのコードは、on_chip_memoryという名前のメモリ・デバイスに配置されます。

.section .on_chip_memory

これらの機能の使用法の詳細については、GNU コンパイラおよびアセンブラの資料を参照してください。

Page 47: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 4–372004年 12月 Nios II ソフトウェア開発ハンドブック

HALを使用したプログラムの開発

ヒープおよびスタックの配置

ヒープとスタックは両方とも常に、.rwdataセクションと同じメモリ・パーティションに存在するように配置されます。スタックは、セクションの末尾から下方(下位アドレスへ)に拡張されます。ヒープは、.rwdata セクション内で最後に使用されたメモリから上方に拡張されます。

HALは、実行時にヒープおよびスタックに十分なスペースがあるかどうかはチェックしません。ユーザは自分のプログラムが、ヒープとスタックに利用できるメモリの制限内で動作することを保証する必要があります。

ブート・モード

リセット・ベクタを持つメモリ・デバイスがプロセッサのブート・デバイスになります。外部フラッシュまたはアルテラの EPCSシリアル・コンフィギュレーション・デバイス、あるいはオンチップ RAMをブート・デバイスにすることができます。ブート・デバイスの性質にかかわらず、すべての HAL ベースのシステムは、すべてのコードおよびデータ・セクションが最初の段階でブート・デバイス内に格納されるように構築されます。これらのセクションは、ブート時にシステム・ライブラリ・プロパティ・ページ上で指定された実行位置にコピーされます。

.textセクションがブート・デバイスに配置されていない場合、Nios IIIDE の Altera Flash Programmer は、_start を呼び出す前にすべてのコードおよびデータ・セクションをロードするブート・ローダを自動的にリセット・アドレスに配置します。EPCS デバイスからブートする場合、このローダの役割はハードウェアで提供されます。

ただし、.textセクションがブート・デバイス内に配置されている場合、システム内に個別のローダは存在しません。ローダを使用する代わりに、HAL 実行コマンド内の _reset エントリ・ポイントが直接呼び出されます。関数 _resetは、命令キャッシュを初期化した後に _startを呼び出します。そのため、フラッシュ・メモリから直接ブートおよび実行するアプリケーションの開発が可能です。

このモードで実行する場合、RAM へのロードが必要なセクションはすべて、HAL実行コマンドで行う必要があります。セクション .rwdata、.rodata、および例外セクションは、必要に応じて、alt_main()を呼び出す前に自動的にロードされます。この自動ロードは、関数alt_load()によって実行されます。

Page 48: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

4–38 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALシステム・ライブラリ・ファイルへのパス

HALシステム・ライブラリ・ファイルへのパス

通常は、HALシステム・ライブラリ・ファイルは絶対に編集しないでください。ただし、参考のために、ヘッダ・ファイルなどを参照することは可能です。

HALファイルの検出Nios II システム独自の性質により、HAL システム・ライブラリ・ファイルは、いくつかの個別ディレクトリに存在します。Nios II システムごとに異なるペリフェラルが含まれることがあるため、各システムのHALシステム・ライブラリも異なります。HAL関連ファイルは、以下の場所のいずれかにあります。

■ ほとんどの HAL システム・ライブラリ・ファイルは、<Nios II インストール・パス >/componentsディレクトリに格納されています。

■ HALの汎用デバイス・モデルを定義するヘッダ・ファイルは、<Nios IIインストール・パス >/components/altera_hal/HAL/inc/sysに格納されています。#include ディレクティブの場合、これらのファイルは、<Nios IIインストール・パス >/components/altera_hal/HAL/inc/に対して参照されます。例えば、DMA ドライバを取り込むには、#include sys/alt_dma/hを使用します。

■ system.h ファイルは、特定の HAL システム・ライブラリ・プロジェクト用のNios II IDEプロジェクト・ディレクトリに格納されています。

■ Newlib ANSI C ライブラリ・ヘッダ・ファイルは、<Nios II インストール・パス >/binに格納されています。

HAL関数の置き換えユーザが関数を独自に実装するには、Nios II IDEアプリケーション・プロジェクトにファイルをインクルードします。実行ファイルを構築するときに、Nios II IDEはユーザの関数を最初に検出し、HALバージョンの関数の代わりに使用します。

Page 49: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–12004年 12月 Preliminary

5. HAL用デバイス・ドライバの開発

はじめに エンベデッド・システムは、一般に独自のデバイス・ドライバを必要とするアプリケーション固有のハードウェア機能を備えています。この章では、デバイス・ドライバを開発する方法と、それらのドライバをHAL(Hardware Abstraction Layer)システム・ライブラリに統合する方法について説明します。

ハードウェアとの直接的な連携は、デバイス・ドライバ・コードに限定する必要があります。一般に、ユーザ・プログラム・コードの大部分ではハードウェアへの低レベルなアクセスを行うことはありません。ハードウェアへのアクセスには、可能な限り、高レベルHAL API(ApplicationProgramming Interface)関数を使用してください。それによって、コードの一貫性が向上し、ハードウェア・コンフィギュレーションが異なるその他のNios® II システムへの移植性も向上します。

新しいドライバを作成する場合、ドライバは以下の 2つレベルのいずれかで、HALフレームワークに統合することができます。

■ HAL APIへの統合■ ペリフェラル固有の API

HAL APIへの統合HAL APIへの統合は、キャラクタ・モード・デバイスまたは DMAデバイスなど、HAL汎用デバイス・モデル・クラスのいずれかに属するペリフェラルに適した方法です。HAL APIへの統合では、この章で説明するデバイス・アクセス関数を記述すると、ソフトウェアから標準HAL APIを介してデバイスにアクセスできるようになります。例えば、ASCIIキャラクタを表示する新しい LCD 画面デバイスを使用する場合、キャラクタ・モード・デバイス・ドライバを記述します。このドライバを使用すると、プログラムから使い慣れた printf() 関数を呼び出して、LCD画面にキャラクタを出力できます。

NII52005-1.1

myoshida
Text Box
この資料は、更新された最新の英語版が存在します。こちらの日本語版は参考用としてご利用下さい。 設計の際は、必ず最新の英語版で内容をご確認下さい。
Page 50: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–2 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

デバイス・ドライバ作成の開発フロー

ペリフェラル固有の APIペリフェラルが HAL 汎用デバイス・モデル・クラスのいずれにも属さない場合は、そのハードウェア実装専用のインタフェースを持つデバイス・ドライバを提供し、デバイスに対する APIを HAL APIから分離する必要があります。プログラムは、HAL APIではなくユーザが用意した関数を呼び出してハードウェアにアクセスします。

HAL APIへの統合では実装に労力を要しますが、デバイスを操作する上で、HALおよび C標準ライブラリ APIの利点が得られます。

HAL APIへの統合の詳細については、5–17ページの「HALへのデバイス・ドライバの統合」を参照してください。

この章の他のセクションは、HAL APIにドライバを統合する方法、およびペリフェラル固有のAPIを使用してドライバを作成する方法に関するものです。

C++はHALベースのプログラムでサポートされていますが、HALドライバは C++ では記述しません。ドライバ・コードは C またはアセンブラのみとし、移植性を考慮して Cを推奨します。

必要な知識

この章では、読者が HAL用の Cプログラミングに精通していることを前提としています。この章に入る前に、4–1ページの「HALを使用したプログラムの開発」の内容を確認してください。

デバイス・ドライバ作成の開発フロー

HAL用の新しいドライバを開発する手順は、デバイスの仕様によって大きく異なります。ただし、すべてのデバイス・クラスに以下の一般的な手順が適用されます。

1. レジスタについて記述するデバイス・ヘッダ・ファイルを作成します。このヘッダ・ファイルが、必要な唯一のインタフェースである場合もあります。

2. ドライバ機能を実装します。

3. main ()からテストします。

4. ドライバを HAL環境に統合する最終段階へ進みます。

5. デバイス・ドライバをHALフレームワークに統合します。

Page 51: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–32004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

SOPC Builderの概念

このセクションでは、ドライバ開発プロセスに関する理解を深めるために、アルテラの SOPC Builder ハードウェア・デザイン・ツールの概念について説明します。Nios II デバイス・ドライバを開発するのに、SOPCBuilderを使用する必要はありません。

system.hと SOPC Builderの関係system.h ヘッダ・ファイルは、Nios II システム・ハードウェアのすべてのソフトウェア記述を提供し、ドライバ開発の基本部分となるものです。ドライバは最下位レベルでハードウェアとやりとりを行うため、理解しやすいように system.h と Nios II プロセッサ・システム・ハードウェアを生成する SOPC Builder との関係を最初に説明しておきます。ハードウェア設計者は、SOPC Builderを使用して、Nios II プロセッサ・システムのアーキテクチャを指定し、必要なペリフェラルとメモリを統合します。したがって、各ペリフェラルの名前やコンフィギュレーションなど、system.h における定義は、SOPC Builder で選択したデザインを直接反映しています。

system.h ヘッダ・ファイルの詳細については、4–1 ページの「HAL を使用したプログラムの開発」を参照してください。

最適なハードウェア・コンフィギュレーションを目的とした SOPC Builderの使用system.h 内に最適でない定義を見つけた場合は、SOPC Builder で基本ハードウェアを変更することによって、system.h の内容を修正できます。デバイス・ドライバを記述して、不完全なハードウェアに対処する前に、SOPC Builderで簡単にハードウェアを改良できないか検討することが重要です。

コンポーネント、デバイス、およびペリフェラル

SOPC Builderで使用する「コンポーネント」という用語は、システムに含まれるハードウェア・モジュールを表します。Nios II ソフトウェア開発において、SOPC Builderコンポーネントとは、ペリフェラルやメモリなどのデバイスのことです。以降のセクションで、SOPC Builderに密接に関連する内容を説明する場合、「コンポーネント」は「デバイス」や「ペリフェラル」と置き換え可能な意味で使用します。

ハードウェアへのアクセス

ソフトウェアでは、デバイスへのメモリマップド・インタフェースを抽象化するマクロを介して、ハードウェアにアクセスします。このセクションでは、各デバイスのハードウェア・インタフェースを定義するマクロについて説明します。

Page 52: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–4 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

ハードウェアへのアクセス

すべての SOPC Builder コンポーネントは、デバイス・ハードウェアとソフトウェアを定義するディレクトリを提供します。例えば、Nios II 開発キットに含まれる各コンポーネントには、<Nios II インストール・パス >/componentsディレクトリに配置された専用のディレクトリがあります。多くのコンポーネントは、ハードウェア・インタフェースを定義するヘッダ・ファイルを提供します。ヘッダ・ファイルは、< コンポーネント名 >_regs.hの名前で、特定のコンポーネント用の incサブディレクトリに格納されています。例えば、アルテラが提供する JTAG UARTコンポーネントの場合、そのハードウェア・インタフェースは、ファイル <Nios IIインストール・パス >/components/altera_avalon_jtag_uart/inc/altera_avalon_jtag_uart_regs.h内で定義されています。

_regs.hヘッダ・ファイルは、以下のアクセスを定義します。

■ 動作をサポートするデバイス内で、各レジスタに対する読み取りマクロや書き込みマクロを提供するレジスタ・アクセス・マクロ。これらのマクロは、IORD_<コンポーネントの名前 >_<レジスタの名前 >、および IOWR_<コンポーネントの名前 >_<レジスタの名前 >です(7–1ページの「キャッシュ・メモリ」を参照)。

■ レジスタ内の個々のビット・フィールドへのアクセスを可能にするビット・フィールド・マスクとオフセット。これらのマクロの名前は、以下のとおりです。

● フィールドのビット・マスクの場合、<コンポーネントの名前>_<レジスタの名前 >_<フィールドの名前 >_MSK

● フィールド先頭のビット・オフセットの場合、< コンポーネントの名前 >_<レジスタの名前 >_<フィールドの名前 >_OFST

● ステータス・レジスタの PE フィールドへのアクセスの場合、ALTERA_AVALON_UART_STATUS_PE_MSKおよびALTERA_AVALON_UART_STATUS_PE_OFST

デバイスのレジスタにアクセスするには、_regs.hファイルに定義されたマクロのみを使用してください。デバイスの読み取りまたは書き込みを行うときに、プロセッサがデータ・キャッシュを使用しないようにするために、レジスタ・アクセス関数を使用する必要があります。また、この処理では、ソフトウェアが基本ハードウェアの変更による影響を受けやすくなるため、ハード・コード化された定数は絶対に使用しないでください。

まったく新しいハードウェア・デバイス用のドライバを記述する場合、_regs.hヘッダ・ファイルを作成する必要があります。

Page 53: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–52004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

キャッシュ管理およびデバイス・アクセスに関する影響の詳細は、7–1ページの「キャッシュ・メモリ」を参照してください。_regs.hファイルの詳細な例については、アルテラ提供の SOPC Builder コンポーネントのコンポーネント・ディレクトリを参照してください。

HALデバイス・クラス用ドライバの作成

HAL は、多数の汎用デバイス・モデル・クラスをサポートしています(3–1ページの「HALシステム・ライブラリの概要」を参照)。このセクションの説明に従ってデバイス・ドライバを作成して、既知のデバイス・クラスのいずれかに分類される特定のデバイスのインスタンスを HALに記述します。このセクションでは、HALがドライバ関数に均等にアクセスできるように、ドライバ関数のための統一されたインタフェースを定義します。

以下のセクションでは、以下のデバイスのクラスに対する APIを定義します。

■ キャラクタ・モード・デバイス■ ファイル・サブシステム■ DMAデバイス■ システム・クロックとして使用されるタイマ・デバイス■ タイムスタンプ・クロックとして使用されるタイマ・デバイス■ フラッシュ・メモリ・デバイス■ イーサネット・デバイス

以下のセクションでは、各デバイス・クラスに対してデバイス・ドライバを実装する方法と、それらのドライバを HAL ベース・システムで使用するための登録方法について説明します。

キャラクタ・モード・デバイス・ドライバ

このセクションでは、デバイス・インスタンスの作成方法とキャラクタ・デバイスの登録方法について説明します。

デバイス・インスタンスの作成

デバイスをキャラクタ・モード・デバイスとして使用できるようにするには、そのデバイスに alt_dev 構造体のインスタンスを提供する必要があります。alt_dev構造体は、以下のコードで定義されています。

typedef struct { alt_llist llist; /* 内部使用 */ const char* name; int (*open) (alt_fd* fd, const char* name, int flags, int mode); int (*close) (alt_fd* fd); int (*read) (alt_fd* fd, char* ptr, int len); int (*write) (alt_fd* fd, const char* ptr, int len);

Page 54: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–6 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

int (*lseek) (alt_fd* fd, int ptr, int dir); int (*fstat) (alt_fd* fd, struct stat* buf); int (*ioctl) (alt_fd* fd, int req, void* arg);} alt_dev;

この構造体は、基本的には関数ポインタの集合です。これらの関数は、HALファイル・システムへのユーザ・アクセスに応答して呼び出されます。例えば、このデバイスに対応するファイル名を指定して関数 open()を呼び出すと、結果としてこの構造体に割り当てられた open()関数が呼び出されます。

open()、close()、read()、write()、lseek()、fstat()、および ioctl() の詳細については、10–1 ページの「HAL API リファレンス」を参照してください。

これらの関数はいずれも、グローバル・エラー・ステータスの errnoを直接変更することはありません。ステータスを変更する代わりに、errno.hで定義された該当するエラー・コードの負の値を返します。

例えば、ioctl() 関数は、要求を処理できない場合には、errno をENOTTYに直接設定するのではなく、戻り値として–ENOTTYを返します。errnoは、これらの関数を呼び出すHALシステム・ルーチンが適切に設定します。

これらの関数の関数プロトタイプは、int 型ではなく alt_fd* 型の入力ファイル・ディスクリプタ引数を取るという点が、アプリケーション・レベルのプロトタイプとは異なります。

新しい alt_fd 構造体は、open() を呼び出したときに作成されます。この構造体のインスタンスは、関連するファイル・ディスクリプタに対して実行されたすべての関数呼び出しに、入力引数として渡されます。

alt_fd構造体は、以下のコードで定義されています。

typedef struct { alt_dev* dev; void* priv; int fd_flags;} alt_fd;

ここで、

■ devは、使用中のデバイスのデバイス構造体へのポインタです。■ fd_flagsは、open()に渡される flagsの値です。■ privは、HALシステム・コードで使用されない不定値です。

Page 55: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–72004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

■ privは、ドライバが内部使用に必要なファイル・ディスクリプタごとの情報を格納するために利用できます。

ドライバで、alt_dev構造体内のすべての関数を提供する必要はありません。関数ポインタが NULL に設定されている場合は、デフォルト動作が実行されます。表 5–1に、利用可能な関数それぞれのデフォルト動作を示します。

関数ポインタに加えて、alt_dev構造体にはさらに、llistと nameの2つのフィールドが含まれています。llistは内部で使用するためのもので、常に ALT_LLIST_ENTRY の値に設定する必要があります。nameは、HAL ファイル・システム内のデバイスの位置で、system.h で定義されたデバイスの名前です。

キャラクタ・デバイスの登録

alt_dev構造体のインスタンスを作成したら、これをHALに登録し、以下の関数を呼び出すことによって、システムでデバイスを利用できるようにする必要があります。

int alt_dev_reg (alt_dev* dev)

この関数は登録するデバイス構造体を唯一の入力引数として受け取ります。戻り値のゼロは正常に終了したことを示します。負の戻り値は、デバイスが登録できないことを示します。

表 5–1. alt_devで定義された関数のデフォルト動作

関数 デフォルト動作

open デバイスが事前に TIOCEXCL ioctl() 要求によってロックされていない限り、このデバイスに対して open()を呼び出すと成功します。

close ファイル・ディスクリプタが有効な場合、このデバイスに対して close()を呼び出すと、必ず成功します。

read このデバイスに対して read()を呼び出すと、必ず失敗します。

write このデバイスに対して write()を呼び出すと、必ず失敗します。

lseek このデバイスに対して lseek()を呼び出すと、必ず失敗します。

fstat デバイスは、自身をキャラクタ・モード・デバイスとして識別します。

ioctl デバイスを参照しなければ処理できない ioctl()は失敗します。

Page 56: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–8 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

デバイスがシステムに登録されると、HAL APIおよび ANSI C標準ライブラリを使用してデバイスにアクセスできます (4–1 ページの「HAL を使用したプログラムの開発」を参照 )。デバイスのノード名は、alt_dev構造体で指定されます。

ファイル・サブシステム・ドライバ

ファイル・サブシステム・デバイス・ドライバは、グローバル HALファイル・システム内の指定されたマウント・ポイントでのファイル・アクセスを処理します。

デバイス・インスタンスの作成

ファイル・システムの作成と登録は、キャラクタ・モード・デバイスの作成と登録とよく似ています。ファイル・システムを利用可能にするには、alt_dev構造体のインスタンスを作成します(5–5ページの「キャラクタ・モード・デバイス・ドライバ」を参照)。唯一の相違点は、デバイスの name フィールドがファイル・サブシステムのマウント・ポイントを表すことです。もちろん、キャラクタ・モード・デバイスの場合と同様に、read() や write() など、ファイル・サブシステムにアクセスするのに必要な関数も、ユーザが用意する必要があります。

fstat() を実装していない場合、デフォルトの動作によって、キャラクタ・モード・デバイスの値が返され、これはファイル・サブシステムに対して不正な動作となります。

ファイル・サブシステム・デバイスの登録

ファイル・サブシステムは、以下の関数を使用して登録できます。

int alt_fs_reg (alt_dev* dev)

この関数は登録するデバイス構造体を唯一の入力引数として受け取ります。負の戻り値は、ファイル・システムが登録できないことを示します。

ファイル・サブシステムが HAL ファイル・システムに登録されると、HAL APIおよび ANSI C標準ライブラリを使用して、このサブシステムにアクセスできます (4–1ページの「HALを使用したプログラムの開発」を参照 )。ファイル・サブシステムのマウント・ポイントは、alt_dev構造体で指定された nameです。

Page 57: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–92004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

タイマ・デバイス・ドライバ

このセクションでは、システム・クロックとタイムスタンプ・ドライバについて説明します。

システム・クロック・ドライバ

システム・クロック・デバイス・モデルを使用するには、周期的な「チック」を生成するドライバが必要です(4–1ページの「HALを使用したプログラムの開発」を参照)。1つのシステムには 1つのシステム・クロック・ドライバしか存在できません。そのため、システム・クロック・ドライバは、周期的な割り込みを生成するタイマ・ペリフェラルに対する割り込みサービス・ルーチン(ISR)として実装します。このドライバは、以下の関数を周期的に呼び出す必要があります。

void alt_tick (void)

alt_tick()は割り込み処理中に呼び出されます。

システム・クロック・ドライバを登録するには、以下の関数を呼び出します。

int alt_sysclk_init (alt_u32 nticks)

入力引数 nticksは、1秒あたりのシステム・クロック・チック数です。この値はシステム・クロック・ドライバによって決まります。この関数の戻り値は、成功時にはゼロ、それ以外はゼロではない値です。

割り込みサービス・ルーチンの記述に関する詳細は、6–1 ページの「例外処理」を参照してください。

タイムスタンプ・ドライバ

タイムスタンプ・ドライバは、alt_timestamp_start()、alt_timestamp()、および alt_timestamp_freq()の 3つのタイムスタンプ関数の実装を提供します。システムには、1 つのタイムスタンプ・ドライバしか存在できません。

これらの関数の使用法に関する詳細は、4–1ページの「HALを使用したプログラムの開発」および 10–1ページの「HAL APIリファレンス」の章を参照してください。

Page 58: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–10 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

フラッシュ・デバイス・ドライバ

このセクションでは、フラッシュ・ドライバの作成方法とフラッシュ・デバイスの登録方法について説明します。

フラッシュ・ドライバの作成

フラッシュ・デバイス・ドライバは、sys/alt_flash_dev.h で定義されたalt_flash_dev構造体のインスタンスを持つ必要があります。この構造体は以下のコードで表されます。

struct alt_flash_dev{ alt_llist llist; // 内部使用のみ const char* name; alt_flash_open open; alt_flash_close close; alt_flash_write write; alt_flash_read read; alt_flash_get_flash_info get_info; alt_flash_erase_block erase_block; alt_flash_write_block write_block; void* base_addr; int length; int number_of_regions; flash_region region_info[ALT_MAX_NUMBER_OF_FLASH_REGIONS]; };

最初のパラメータ llist は内部で使用するためのもので、常にALT_LLIST_ENTRY の値に設定する必要があります。name は、HALファイル・システム内のデバイスの位置で、system.hで定義されたデバイスの名前です。

open から write_block までの 8つのフィールドは、以下の関数へのユーザ API呼び出しの支援機能を実装する関数ポインタです。

■ alt_flash_open_dev()■ alt_flash_close_dev()■ alt_flash_write()■ alt_write_flash()■ alt_read_flash()■ alt_get_flash_info()■ alt_erase_flash_block()■ alt_write_flash_block()

Page 59: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–112004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

ここで、

■ base_addrパラメータは、フラッシュ・メモリのベース・アドレスです。■ lengthは、フラッシュのバイト・サイズです。■ number_of_regionsは、フラッシュ内の消去領域の数です。■ region_infoには、フラッシュ・デバイス内のブロックの位置とサイズに関する情報が含まれています。

flash_region 構造体の形式に関する詳細は、4–14 ページの「フラッシュ・デバイスの使用」を参照してください。

共通フラッシュ・インタフェース(CFI)準拠のデバイスなど、フラッシュ・デバイスには、領域数とそれらのコンフィギュレーションを実行時に読み出せるものもあります。実行時に読み出せない場合、これらの2つのフィールドはコンパイル時に定義しなければなりません。

フラッシュ・デバイスの登録

alt_flash_dev構造体のインスタンスを作成したら、以下の関数を呼び出してデバイスを HAL システムで利用できるようにする必要があります。

int alt_flash_device_register( alt_flash_fd* fd)

この関数は、登録するデバイス構造体を唯一の入力引数として受け取ります。戻り値のゼロは正常に終了したことを示します。負の戻り値は、デバイスが登録できなかったことを示します。

DMAデバイス・ドライバHALは、DMA転送を受信チャネルと送信チャネルの 2つのエンドポイント・デバイスでの制御対象としてモデル化します。このセクションでは、DMA チャネルの各タイプに対するドライバについて個々に説明します。

HAL DMA デバイス・モデルの詳細な説明については、4–20 ページの「DMAデバイスの使用」を参照してください。

DMAデバイス・ドライバ・インタフェースは、sys/alt_dma_dev.hで定義されます。

Page 60: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–12 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

DMA送信チャネル

DMA 送信チャネルは、以下の alt_dma_txchan 構造体のインスタンスを作成することによって構築されます。

typedef struct alt_dma_txchan_dev_s alt_dma_txchan_dev; struct alt_dma_txchan_dev_s { alt_llist llist; const char* name; int (*space) (alt_dma_txchan dma); int (*send) (alt_dma_txchan dma,

const void* from, alt_u32 len, alt_txchan_done* done, void* handle);

int (*ioctl) (alt_dma_txchan dma, int req, void* arg); };

表 5–2に、利用可能なフィールドとそれらの機能を示します。

space関数および send関数の両方を定義する必要があります。ioctlフィールドが null に設定されている場合、このデバイスに対してalt_dma_txchan_ioctl()を呼び出すと、–ENOTTYが返されます。

alt_dma_txchan 構造体のインスタンスを作成したら、以下の関数を呼び出して、デバイスを HAL システムに登録して利用可能にする必要があります。

int alt_dma_txchan_reg (alt_dma_txchan_dev* dev)

入力引数 devは、登録するデバイスです。戻り値は成功時にはゼロになり、デバイスが登録できない場合は負の値になります。

表 5–2. alt_dma_txchan構造体のフィールド

フィールド 機能

llist このフィールドは内部で使用するためのもので、常に ALT_LLIST_ENTRYの値に設定する必要があります。

name alt_dma_txchan_open()の呼び出しでこのチャネルを示す名前。nameは、system.hで定義されるデバイスの名前です。

space デバイスのキューに格納できる追加送信要求数を返す関数へのポインタ。入力引数は、alt_dma_txchan_dev構造体へのポインタです。

send ユーザ API関数 alt_dma_txchan_send()を呼び出した結果として呼び出される関数へのポインタ。この関数は、DMA デバイスに送信要求を送信します。alt_txchan_send() に渡されるパラメータは、send()に直接渡されます。パラメータおよび戻り値の説明は、10–20ページの「alt_dma_txchan_send()」を参照してください。

ioctl この関数はデバイス固有のI/O制御を実行します。デバイスがサポートできる一般的なオプションのリストは、sys/alt_dma_dev.hを参照してください。

Page 61: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–132004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

DMA受信チャネル

DMA 受信チャネルは、以下の alt_dma_rxchan 構造体のインスタンスを作成すれば構築されます。

typedef alt_dma_rxchan_dev_s alt_dma_rxchan;struct alt_dma_rxchan_dev_s { alt_llist list; const char* name; alt_u32 depth; int (*prepare) (alt_dma_rxchan dma, void* data, alt_u32 len, alt_rxchan_done* done, void* handle); int (*ioctl) (alt_dma_rxchan dma, int req, void* arg);};

表 5–3に、利用可能なフィールドとそれらの機能を示します。

prepare()関数を定義する必要があります。ioctl フィールドが null に設定されている場合、このデバイスに対して alt_dma_rxchan_ioctl()を呼び出すと、–ENOTTYが返されます。

表 5–3. alt_dma_rxchan構造体のフィールド

フィールド 機能

llist この機能は内部で使用するためのもので、常に ALT_LLIST_ENTRYの値に設定する必要があります。

name alt_dma_rxchan_open()の呼び出しで、このチャネルを示す名前。nameは、system.hで定義されるデバイスの名前です。

depth どの時点でも未処理状態にすることができる受信要求の総数。

prepare ユーザ API関数 alt_dma_rxchan_prepare()を呼び出した結果として呼び出される関数へのポインタ。この関数は DMAデバイスに受信要求を送信します。alt_dma_rxchan_prepare()に渡されたパラメータは、prepare()に直接渡されます。パラメータおよび戻り値の説明は、10–14ページの「alt_dma_rxchan_prepare()」を参照してください。

ioctl この関数は、デバイス固有の I/O 制御を実行します。デバイスがサポートする一般的なオプションのリストは、sys/alt_dma_dev.hを参照してください。

Page 62: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–14 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

alt_dma_rxchan 構造体のインスタンスを作成したら、以下の関数を呼び出してデバイスを HAL システムに登録して利用可能にする必要があります。

int alt_dma_rxchan_reg (alt_dma_rxchan_dev* dev)

入力引数 devは、登録するデバイスです。戻り値は成功時にはゼロになり、デバイスが登録できない場合は負の値になります。

イーサネット・デバイス・ドライバ

イーサネット・デバイス対応の HAL 汎用デバイス・モデルを利用すると、MicroC/OS-II オペレーティング・システム上で動作する軽量 IP(lwIP)TCP/IPスタックへのアクセスが可能になります。このセクションで定義するドライバ関数を供給することによって、新しいイーサネット・デバイスをサポートできます。

新しいイーサネット・デバイス用のデバイス・ドライバの作成を検討する前に、lwIPのアルテラ・ポートとその使用法の基本を理解しておく必要があります(9–1ページの「イーサネットと Lightweight IP」を参照)。

新しいイーサネット・デバイス・ドライバを作成する最も簡単な方法は、SMSC lan91c111デバイスに対するアルテラの実装から始めて、これをユーザのイーサネット・メディア・アクセス・コントローラ(MAC)に適合するよう修正することです。このセクションでは、ユーザがこの方法を利用するものと仮定しています。すなわち、lwIP スタック実装の詳細を学習するのではなく、動作確認済みの例を修正するだけでドライバを作成できます。したがって、このセクションでは、lwIP スタックのアルテラのポートを内部実装する上での最小限の内容について説明します。

lwIP実装の詳細については、www.sics.se/~adam/lwip/doc/lwip.pdfを参照してください。

lan91c111ドライバのソース・コードは、srcディレクトリおよび incディレクトリ内の<Nios IIインストール・パス>/components/altera_avalon_lan91c111/UCOSII/に、Nios II 開発キットとともに提供されています。イーサネット・デバイス・ドライバ・インタフェースは、<lwIPコンポーネント・パス >/UCOSII/inc/alt_lwip_dev.hで定義されています。

Page 63: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–152004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

以下のセクションでは、新しいイーサネット・デバイス用のドライバを提供する方法について説明します。

alt_lwip_dev_listのインスタンスの提供

以下のコードは、各デバイス・ドライバで提供する必要があるalt_lwip_dev_list構造体のインスタンスを示します。

typedef struct { alt_llist llist; /* 内部使用 */ alt_lwip_dev dev;} alt_lwip_dev_list;

struct alt_lwip_dev{ /* netifポインタは構造体の最初の要素であることが必要 */ struct netif* netif; const char* name; err_t (*init_routine)(struct netif*); void (*rx_routine)();};

nameパラメータは、system.hで定義されるデバイスの名前です。

lwIPシステム・コードは netif構造体を内部で使用して、デバイス・ドライバへのインタフェースを定義します。netif 構造体は、<lwIP コンポーネントのパス >/UCOSII/src/downloads/lwip-0.7.2/src/include/lwipの netif.hで定義されています。特に、netif構造体には、以下の内容が含まれます。

■ インタフェースのMACアドレス用のフィールド■ インタフェースの IPアドレス用のフィールド■ MACデバイスを初期化する低レベル関数への関数ポインタ■ パケットを送信する低レベル関数へのポインタ■ パケットを受信する低レベル関数への関数ポインタ

init_routine()の提供

alt_lwip_dev 構造体の init_routine は、netif 構造体の設定とハードウェアの初期化を行う関数へのポインタです。この関数は、ターゲットのイーサネット・デバイス用に提供する必要があります。この関数のプロトタイプは以下のとおりです。

err_t init_routine(struct netif* netif)

Page 64: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–16 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALデバイス・クラス用ドライバの作成

init_routine()は、ルーチン get_mac_addr()およびget_ip_addr()を呼び出すことによって、MACアドレスおよび IPアドレスに対する netifフィールドに入力します。これらの関数は、9–1ページの「イーサネットと Lightweight IP」で定義されています。さらに、init_routine() では、必要な低レベル・レジスタ・アクセスを実行して、ハードウェアをコンフィギュレーションする必要があります。

output()と linkoutput()の提供

また、init_routine()関数では、output()および link_output()の2つの送信関数へのポインタに対するnetifフィールドにも入力する必要があります。

link_output()は、イーサネット・ハードウェア上でパケットを送信します。link_output()関数のプロトタイプは以下のとおりです。

link_output(struct netif *netif, struct pbuf *p)

link_output()は、イーサネット・インタフェース上で IPパケットを送信します。IPアドレスに関連付けられるMACアドレスに対して ARP要求が発行され、次に link_output()を呼び出してパケットを送信します。link_output()関数のプロトタイプは、以下のとおりです。

output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)

rx_routine()の提供

alt_lwip_dev 構造体の rx_routine は、TCP/IP スタックへの着信パケットを受信するために呼び出されるルーチンへの関数ポインタです。

新しいパケットが到着すると、割り込み要求(IRQ)が生成されます。関連付けられた割り込みサービス・ルーチン(ISR)がこの割り込みをクリアし、rx_mboxという名前のメッセージ・キューにメッセージを送信します。このメッセージ・ボックスは、ファイル <lwIPコンポーネントのパス >/UCOSII/src/alt_lwip_dev.cで定義されています。

rx_threadは、rx_mbox内で新しいメッセージを検出すると、rx_routine()を呼び出します。rx_routine()によって、ハードウェアからパケットが受信され、TCP/IPスタックに渡されます。

Page 65: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–172004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

この関数のプロトタイプは以下のとおりです。

void rx_func()

HALへのデバイス・ドライバの統合

このセクションでは、HALの機能を活用して、システム初期化中にデバイス・ドライバを自動的にインスタンス化および登録する方法について説明します。いずれかのHAL汎用デバイス・モデルに対してデバイス・ドライバを作成した場合でも、ペリフェラル専用のデバイス・ドライバを作成した場合でも、このサービスを活用できます。HALが提供する自動化機能の主な利点は、HALディレクトリ構造の適切な場所にファイルを配置するプロセスです。

HALデバイスのディレクトリ構造各ペリフェラルは、特定の SOPC Builder コンポーネント・ディレクトリに提供されたファイルで定義されています(5–3ページの「ハードウェアへのアクセス」を参照)。このセクションでは、アルテラの JTAG UARTコンポーネントの例を使用して、ファイルの位置を示します。図 5-1に、JTAG UART コンポーネント・ディレクトリのディレクトリ構造を示します。このディレクトリは、<Nios IIインストール・パス >/componentsディレクトリ内に配置されています。

図 5-1. HALペリフェラルのディレクトリ構造

HAL用デバイス・ドライバ・ファイルこのセクションでは、必要なファイルを提供して、デバイス・ドライバをHALに統合する方法について説明します。

altera_avalon_jtag_uart

HALHAL

HAL

inc

src

inc

Page 66: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–18 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALへのデバイス・ドライバの統合

デバイスの HALヘッダ・ファイルと alt_sys_init.c

HALの中心となるのは、自動生成されたソース・ファイルのalt_sys_init.cです。alt_sys_init.c には、システム内のすべてのサポート対象デバイスのデバイス・ドライバを初期化するために、HAL が使用するソース・コードが含まれています。特に、このファイルでは alt_sys_init()関数が定義されています。この関数は、main()の前に呼び出されて、すべてのデバイスを初期化し、プログラムからそれらのデバイスを利用できるようにします。

以下のコードは、alt_sys_init.cファイルから一部分を抜粋したものです。

例:ドライバの初期化を実行する alt_sys_init.cファイルの一部分

#include "system.h"#include "sys/alt_sys_init.h"

/* * デバイス・ヘッダ */#include "altera_avalon_timer.h"#include "altera_avalon_uart.h"

/* * デバイス・ストレージの割り当て */ALTERA_AVALON_UART_INSTANCE( UART1, uart1 );ALTERA_AVALON_TIMER_INSTANCE( SYSCLK, sysclk );

/* * デバイスの初期化 */void alt_sys_init( void ){ ALTERA_AVALON_UART_INIT( UART1, uart1 ); ALTERA_AVALON_TIMER_INIT( SYSCLK, sysclk );}

新しいソフトウェア・プロジェクトを作成すると、Nios II 統合開発環境(IDE)は、SOPC Builder システムの固有のハードウェア内容に適合するように、alt_sys_init.cの内容を自動的に生成します。Nios II IDEは、ジェネレータ・ユーティリティ gtf-generate を呼び出して、alt_sys_init.cを作成します。

gtf-generate は、明示的に呼び出す必要はありません。HALの低レベル動作での gtf-generate について述べているため、ここでは参考として説明しています。

Page 67: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–192004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

プロセッサから認識可能な各デバイスに対して、ジェネレータ・ユーティリティは、デバイスのHAL/incディレクトリ内で関連するヘッダ・ファイルを検索します。ヘッダ・ファイルの名前は、SOPC Builderコンポーネント名によって異なります。例えば、アルテラの JATG UARTコンポーネントの場合、ジェネレータはファイル altera_avalon_jtag_uart/HAL/inc/altera_avalon_jtag_uart.hを検出します。ジェネレータ・ユーティリティは、該当するヘッダ・ファイルを検出すると、alt_sys_init.cにコードを挿入して、以下の動作を実行します。

■ デバイスのヘッダ・ファイルをインクルードします。5–18ページの「例:ドライバの初期化を実行する alt_sys_init.cファイルの一部分」の /* デバイス・ヘッダ */を参照してください。

■ マクロ <デバイスの名前 >_INSTANCEを呼び出して、デバイスにストレージを割り当てます。5–18 ページの「例:ドライバの初期化を実行する alt_sys_init.cファイルの一部分」の /* デバイス・ストレージの割り当て */のセクションを参照してください。

■ alt_sys_init()関数内でマクロ<デバイスの名前>_INITを呼び出して、デバイスを初期化します。5–18ページの「例:ドライバの初期化を実行する alt_sys_init.cファイルの一部分」の /* デバイスの初期化 */のセクションを参照してください。

これらの *_INSTANCE マクロおよび *_INIT マクロは、関連付けられたデバイス・ヘッダ・ファイルで定義する必要があります。例えば、altera_avalon_jtag_uart.hでは、マクロALTERA_AVALON_JTAG_UART_INSTANCEとALTERA_AVALON_JGAT_UART_INITを定義する必要があります。*_INSTANCEマクロは、ドライバが必要とする静的メモリ割り当てをデバイスごとに実行します。*_INIT マクロは、デバイスのランタイム初期化を実行します。どちらのマクロも 2 つの入力引数を受け取ります。最初の引数は大文字で表したデバイス・インスタンスの名前、2 番目の引数は小文字で表したデバイス名です。これは、システム生成時に SOPCBuilderのコンポーネントに与えられた名前です。これらの入力パラメータを使用して、system.hファイルからデバイス固有のコンフィギュレーション情報を抽出できます。

詳細な例は、アルテラ提供のデバイス・ドライバを参照してください。

プロジェクトの再構築時間を短縮するには、ペリフェラル・ヘッダ・ファイルに system.h を直接指定しないようにします(alt_sys_init.cで既に指定されています)。

Page 68: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–20 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

HALへのデバイス・ドライバの統合

SOPC Builderコンポーネント用のデバイス・ドライバを公開するには、コンポーネントのディレクトリ内にファイルHAL/inc/<component_name>.hを提供します。このファイルは、上記のようにマクロ <COMPONENT_NAME>_INSTANCEおよび<COMPONENT_NAME>_INIT を定義するために必要です。このようにデバイスに対応したインフラストラクチャを準備すれば、HALシステム・ライブラリは、main() を呼び出す前に、デバイス・ドライバを自動的にインスタンス化して登録します。

デバイス・ドライバのソース・コード

一般に、デバイス・ドライバは、ヘッダでは完全に定義できません(5–18ページの「デバイスのHALヘッダ・ファイルと alt_sys_init.c」を参照)。ほとんどの場合、コンポーネントは、システム・ライブラリに組み込まれるその他のソース・コードも提供する必要があります。

必要なソース・コードは、HAL/srcディレクトリに配置しなければなりません。さらに、makefileの一部分の component.mkを取り込む必要があります。component.mkファイルは、システム・ライブラリに含まれるソース・ファイルをリストします。ファイル名をスペースで区切ると、複数のファイルをリストできます。以下のコードは、アルテラの JTAGUARTデバイスに対するmakefileの例を示します。

例:component.mk makefileの例

C_LIB_SRCS += altera_avalon_uart.c ASM_LIB_SRCS +=INCLUDE_PATH +=

Page 69: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–212004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

Nios II IDEは、システム・ライブラリ・プロジェクトおよびアプリケーション・プロジェクトをコンパイルするときに、component.mkファイルをトップ・レベルのmakefileに自動的に取り込みます。component.mkは、利用できる make 変数を変更できますが、これは C_LIB_SRCS、ASM_LIB_SRCSおよび INCLUDE_PATHに限定されます。表 5–4にこれらの変数を示します。

component.mkによって、その他のmake規則とマクロを必要に応じて追加できますが、マクロ名は相互運用性を確保するために、ネーム空間規則に準拠する必要があります(5–22ページの「ネーム空間の割り当て」を参照)。

要約

要約すると、HALフレームワークにデバイス・ドライバを統合するには、以下の処理を実行することが必要です。

■ *_INSTANCE マクロおよび *_INIT マクロを定義するインクルード・ファイルを作成し、デバイスのHAL/incディレクトリに配置します。

■ デバイスを操作するソース・コード・ファイルを作成し、そのファイルをデバイスの HAL/srcディレクトリに配置します。

■ makefileの一部分、component.mkを記述し、HAL/srcディレクトリに配置します。

表 5–4. component.mkで定義されるmake変数

make変数 意味

C_LIB_SRCS システム・ライブラリに組み込まれる Cソース・ファイルのリスト。

ASM_LIB_SRCS システム・ライブラリに組み込まれるアセンブラ・ソース・ファイルのリスト(これらはCプリプロセッサで前処理されます)。

INCLUDE_PATH インクルード検索パスに追加するディレクトリのリスト。ディレクトリ<component>/HAL/inc は自動的に追加されるため、コンポーネントで明示的に定義する必要はありません。

Page 70: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–22 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

ドライバ・フットプリントの削減

ドライバ・フットプリントの削減

HAL では、ALT_USE_SMALL_DRIVERS という名前の C プリプロセッサ・マクロが定義されています。このマクロをドライバ・ソース・コード内で使用すると、最小のコード・フットプリントを必要とするシステムに対応した、代替動作が実現できます。Nios II IDEのオプションを利用すれば、機能が限定されたデバイス・ドライバを有効にすることができます。ALT_USE_SMALL_DRIVERS が定義されていない場合、ドライバ・ソース・コードはドライバのフル機能バージョンを実装します。マクロが定義されている場合、ソース・コードは機能を限定したドライバを提供します。例えば、あるドライバはデフォルトでは割り込み駆動式の動作を実装できますが、ALT_USE_SMALL_DRIVERS が定義されていれば、ポーリング式(より軽量と予想される)動作を実装できます。

デバイス・ドライバを作成する際に、ALT_USE_SMALL_DRIVERS の値を無視するように選択すれば、マクロの定義にかかわらず、同じバージョンのドライバが使用されます。

ネーム空間の割り当て

SOPC Builder システムでデバイスによって定義されるシンボルの名前が重複するのを回避するために、すべてのグローバル・シンボルに定義済みプリフィックスを付加する必要があります。グローバル・シンボルには、グローバル変数と関数名があります。デバイス・ドライバの場合、プリフィックスは SOPC Builder コンポーネントの名前の後に下線を付加したものです。このネーミングでは文字列が長くなるため、これに代わる短縮形式も利用できます。この短縮形式ではベンダ名が基本となり、例えばalt_は、アルテラが供給するコンポーネントに対するプリフィックスです。すべてのコンポーネントの相互運用性は、コンポーネントを供給するベンダがテストすることが求められます。

例えば、altera_avalon_jtag_uartコンポーネントの場合、以下の関数名は有効です。

■ altera_avalon_jtag_uart_init()■ alt_jtag_uart_init()

以下の名前は無効です。

■ avalon_jtag_uart_init()■ jtag_uart_init()

ソース・ファイルは検索パスを使用して検索されるため、これらのネーム空間制限事項はデバイス・ドライバのソース・ファイルとヘッダ・ファイルにも適用されます。

Page 71: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

Altera Corporation 5–232004年 12月 Nios II ソフトウェア開発ハンドブック

HAL用デバイス・ドライバの開発

デフォルト・デバイス・ドライバの置き換え

すべての SOPC Builderコンポーネントは、HALデバイス・ドライバを提供することを選択できます(5–17 ページの「HAL へのデバイス・ドライバの統合」を参照)。ただし、コンポーネントに用意されたドライバがアプリケーションに適さない場合は、Nios II IDEのシステム・ライブラリ・プロジェクト・ディレクトリに別のドライバを供給して、デフォルトのドライバを置き換えることができます。

Nios II IDEは検索パスを使用して、すべてのインクルード・ファイルとソース・ファイルを検索します。この場合、システム・ライブラリ・プロジェクト・ディレクトリが常に最初に検索されます。例えば、コンポーネントがヘッダ・ファイル alt_my_component.h を提供し、システム・ラ イ ブ ラ リ・プ ロ ジ ェ ク ト・デ ィ レ ク ト リ に も フ ァ イ ルalt_my_component.h が含まれている場合、コンパイル時にシステム・ライブラリ・プロジェクト・ディレクトリに提供されるバージョンが使用されます。これと同じメカニズムによって、Cソース・ファイルとアセンブラ・ソース・ファイルを置き換えることが可能です。

Page 72: セクション II. HAL システム・ ライブラリ · ソフトウェア開発ハンドブック. hal. システム・ライブラリの概要. 図. 3-1. hal. ベースのシステムのレイヤ

5–24 Altera CorporationNios II ソフトウェア開発ハンドブック 2004年 12月

デフォルト・デバイス・ドライバの置き換え