u64.htm
18.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
<HTML>
<HEAD>
<TITLE>無題</TITLE>
<META NAME="GENERATOR" CONTENT="Internet Assistant for Microsoft Word 2.0j">
</HEAD>
<BODY>
<P>
<B><FONT SIZE=4>u64(3P)<BR>
</FONT></B>
<P>
<B>関数名</B>
<P>
u64
<P>
→ /dev/u64(NINTENDO64開発ボードのデバイスドライバー)について。
<BR>
<P>
<B>説明</B>
<P>
NINTENDO64開発ボードはIndyのダブルワイドgioバスに接続するソフト開発用ボードです。R4300のゲームカートリッジメモリ空間としてRAMが16MB実装されています。このエリアはホストのIndyからもアクセスすることが出来ます。Indyからアクセスする際には、一度にマッピング出来るのは16MB中1MBだけで、このマッピングエリアはvia(4bitのページコントロール用レジスタ)で指定します。ボード上のR4300とホストのIndyからこのRAMへ同時にアクセスすることは出来ません。ボード上の16MB"ramrom"領域へのアクセス管理機構がデュアルポーティングに対応していないからです。
<BR>
<P>
ホストのIndyと開発ボード間の通信には、gio割り込みレジスタか、分割されたRDB割り込みレジスタを使用します。初期のリリースではgio割り込みを使用していましたが、2.0F以降はすべてRDB割り込みを使用する方式に移行しました。RDB割り込みはVer.1の開発ボードでは使用出来ません。Ver.2以降の開発ボードだけがRDBポートを使用出来ます。ですから今後はVer.1のボードはサポートされません。
<BR>
<P>
gio割り込みは、開発システムではカートリッジ割り込みにマップされています。カートリッジ割り込みは64DDのような周辺機器で使用するように設計されていますので、今後はボード・ホスト間の通信にはこの割り込みを絶対に使用しないで下さい。
<BR>
<P>
RDBポートではデュアルポート割り込みレジスタが使用出来ます。RDBポートは2つのポートだと考えることが出来ます。おのおのが32bit幅で、一方はIndyからボードへの通信用、もう一方はボードからIndyへの通信用のポートです。Indyからボードにメッセージを送りたい時にはRDBポートに書き込みます。そうするとボード上で割り込みが発生します。ボートがRDBポートのデータを読み込むと、Indy上で割り込みが発生します。このデュアルポートはハンドシェークを行うには非常に便利なシステムで、RDBポートに書き込む前に既に送信したデータが読まれたかどうかを確かめることも出来ます。このシステムはボードがRDBポートにデータを書き込んだ時も同じように動作します。その場合は、データが書き込まれるとIndy上で割り込みが発生し、Indyがデータを読み込むとボード上で割り込みが発生します。このように、RDBポートは2つの独立したポートとして動作しますので、ボード・Indy間の双方向同時通信が可能になります。
<BR>
<P>
u64デバイスドライバーにより、read, write, ioctlコマンドが使用出来るようになります。これらのコマンドはシステムのリセット、ramrom領域の読み込みと書き込み、Indyとゲームアプリケーションとの様々な通信に使用します。
<BR>
<P>
以下は、ボードのレジスタとその機能についての詳細です。<BR>
<P>
<B>Product ID Register<BR>
</B>
<P>
<B>GIO address 0x1f400000 (R), no development system address
<BR>
</B>
<P>
この32bitレジスタは、Indyのカーネルがブート時にボードを認識するために使用します。bit31〜30はgio割り込み(後述)の識別用に予約されています。bit30〜8はOです。bit7は1で、bit6〜0は0x15にセットされています。IndyのカーネルはGIOハードの認識のため、このアドレスの上位bitをマスクしているので、下位7bitだけがブート時の認識で参照されます。(すべてのGIO拡張カードは、認識用の固有のbitパターンをこのアドレス0x1f400000に持っています)。<BR>
<P>
上位2bitは、デバイスドライバがRDBポートを他のRDB割り込み発生源と区別するためにRDBポート識別用として予約されています。<BR>
<P>
Bit30(0x40000000)をセットしておくと、ボードがRDBレジスタからの読み込みを終わったことを、Indy上での割り込みの際に示します。
<BR>
<P>
Bit31(0x80000000)をセットしておくと、ボードがRDBレジスタへの書き込みを終わったことを、Indy上での割り込みの際に示します。
<BR>
<P>
もしgio割り込みが発生し、どちらかのbitがセットされていたら、ボードからスタンダードGIOレジスタ(後述)に対して割り込み要求があったことを示します。
<BR>
<P>
<B>Reset Control Register<BR>
</B>
<P>
<B>GIO address 0x1f400400 (W), no development system address
<BR>
</B>
<P>
このレジスタに書き込むことによってボード上でリセット、またはnmi(non-maskable
interrupt)を発生させることが出来ます。bit2がNMI、bit1がリセットの制御に割り当てられています。リセットはbitがセットされると有効になり、bitがクリアされると解除されます。NMIはbitをセットすると用意され、クリアすると発生します。
<BR>
<P>
<B>DRAM Page Control Register<BR>
</B>
<P>
<B>GIO address 0x1f400600 (R/W), no development system address</B>
<P>
bit23〜20の4bitによって、16MBの内のどの1MB分をマップするかを選択します。選択された1MBはGIOアドレスの0x1f500000〜0x1f5ffffeにマップされます。IndyはGIOバスのアドレス空間を一度に2MB分だけしかマップ出来ません。そして、その最初の1MB分をこのレジスタでマップしています。ですから16MBのramrom領域の中で、一度にマップ出来るのは1MBのみなのです。
<BR>
<P>
<B>Cartridge Interrupt Register<BR>
</B>
<P>
<B>GIO address 0x1f400800 (R/W), development system R4300 address
0x18000800 (R)</B>
<P>
カートリッジ割り込みレジスタはR4300のINT1割り込みを発生させます。R4300は、ホストがこのレジスタのbit5〜0の6bit分に書き込んだ値を読んで、割り込み時になにをするかを決めます。R4300がこのレジスタを読むと、割り込みがクリアされます。注意:この割り込みは今後使用しないで下さい。
<BR>
<P>
<B>GIO Interrupt Register<BR>
</B>
<P>
<B>GIO address 0x1f400c00 (R), development system R4300 address
0x18000000 (R/W)</B>
<P>
R4300がこのGIO割り込みレジスタのbit5〜0の6bit分に値を書き込むと、Indy上でGIO割り込みが発生します。Indyがこの値を読むと割り込みはクリアされます。注意:この割り込みは今後使用しないで下さい。
<BR>
<P>
<B>GIO Sync Register<BR>
</B>
<P>
<B>GIO address 0x1f400e00 (R), development system R4300 address
0x18000400 (R/W)</B>
<P>
ホストのIndyは、R4300がこのGIO Syncレジスタのbit5〜0の6bit分に書き込んだ値を読むことになります。このレジスタは値を書き込んでもIndy上に割り込みを発生させません。ですから、2つのプロセッサ間でのポーリング機構をインプリメントする必要があります。GIO割り込みレジスタ(前項参照)とGIO
Syncレジスタはどちらか一方に値が書き込まれるともう一方にも同じ値にが書き込まれます。
<BR>
<BR>
<P>
<B>RDB Registers<BR>
</B>
<P>
<B>GIO address 0x1f480000 (W), development system R4300 address
0xc0000000 (R)</B>
<P>
<B>GIO address 0x1f480000 (R), development system R4300 address
0xc0000000 (W)</B>
<P>
この2つの32bit幅のレジスタは、一方はIndyからR4300への通信用に、もう一方はR4300からIndyへの通信用に用意されています。ですから、両方のプロセッサが同時に書き込みを行ってもデータは消失しません。一方のプロセッサで読み込み、書き込みがおこると、そのサイクルタイプ(読み込みか書き込みか)を示す割り込みがもう一方プロセッサに送られます。
<BR>
<P>
Indyの割り込み処理ルーチンは、R4300がRDBレジスタの読み込み・書き込みのどちらを行うかを判断するためにProduct
IDレジスタを参照します。Product IDレジスタのbit30がセットされていれば読み込み、bit31がセットされていれば書き込みとなります。
<BR>
<P>
R4300は、IndyがRDBレジスタの読み込み・書き込みを行うと、それぞれ別の割り込みを受け取ります。INT3
(CAUSE_IP6)の場合は読み込み、INT4 (CAUSE_IP7)の場合は書き込みとなります。
<BR>
<P>
Indy、r4300それぞれの割り込み処理ルーチンは、"write interrupt"を受け取った場合、RDBレジスタから読み込める最大量のデータを読み込んで、処理を終了します(一度データが読まれると書き込みサイクルはIndyのアプリケーションまたはNINTENDO64のスレッドによって初期化されます)。
<BR>
<P>
これらのレジスタ(と後述の割り込みレジスタ)はIndy側ではgioアドレス空間の上位ポートにマップされており、R4300側では拡張SysAD(System
Address and Data)デバイスアドレス空間にマップされています。<BR>
<P>
<B>RDB Write Interrupt<BR>
</B>
<P>
<B>GIO address 0x1f480008 (W), R4300 address 0xc0000008 (W)</B>
<P>
どちらか一方のプロセッサがRDBレジスタに対して書き込みを終了すると、"write割り込み"が他方のプロセッサに対して発生します。割り込みが発生したプロセッサでは、割り込み処理ルーチンがこのRDB
Write割り込みレジスタに0x0を書き込むことによって割り込みをクリアします。データを読み込むことによって、もう一方のプロセッサに割り込みが発生する点と、RDB
Write割り込みレジスタに書き込むことによっては、割り込み処理ルーチンが動いているプロセッサの割り込みがかかった状態をクリアするだけという点に注意して下さい。
<BR>
<P>
<B>RDB Read Interrupt<BR>
</B>
<P>
<B>GIO address 0x1f48000c (W), R4300 address 0xc000000c (W)</B>
<P>
どちらか一方のプロセッサがRDBレジスタからの読み込みを終了すると、"read割り込み"が他方のプロセッサに発生します。割り込みが発生したプロセッサでは、割り込み処理ルーチンがこのRDB
Read割り込みレジスタに0x0を書き込むことによって割り込みをクリアします。
<BR>
<BR>
<P>
<B>Device Driver Entry Points<BR>
</B>
<P>
Device Driver Entry Pointには、ユーザレベルプログラムがデバイスアクセスのために(例えばopen()のような)システムコールを実行した時に、/dev/u64デバイスドライバが何をしなければならないかが定義されています。ユーザがデバイスをファイルとして扱えるように、open,
read, write, closeといった標準のファイル操作をDriver Entry Pointで用意してあります。
<BR>
<P>
さらに標準のEntry Pointsに加えて、chpoll関数もインプリメントしてありますので、select(),
poll()を既にopneしたファイル記述子からの入出力が接続中かをテストするのに使用出来ます。
<BR>
<P>
デバイスドライバ内部には、カーネルが使用するために用意されたいくつかの関数のEntry
Pointがあります。これはユーザからは見えません。edtinit()はボードのブートタイムを検出し、ボードが検出されたら初期化とデバイスドライバ用のメモリリソースを確保します。ドライバのGIO割り込み処理ルーチンであるu64_giointr()のアドレスが、edtinit()によってカーネルの割り込み処理ルーチンのテーブルに登録されます。後述の標準のシステムコールについてはmanで使い方を見ることが出来ます。
<BR>
<P>
RDB上で異なるタイプのデータを効率よく送受信するために、デバイスドライバは様々なマイナーデバイスを使用できるようにします。メジャーデバイスである/dev/u64に加え、現在のところ以下のマイナーデバイスが使用可能です:
<BR>
<P>
/dev/u64_print, /dev/u64_logging, /dev/u64_data, /dev/u64_debug,
/dev/u64_fault, /dev/u64_kdebug, /dev/u64_profile<BR>
<BR>
<P>
<B>int open(int open (const char *path, int oflag, ... /* mode_t
mode */))<BR>
</B>
<P>
ユーザはopen()をコールして、/devディレクトリにあるu64デバイスファイルの1つをopneします。/dev/u64はボードのリセットとramromへのアクセスに使用します。/dev/u64_printはgloadのプリントサーバで使用します。/dev/u64_loggingはgloadでlogデータのflushをするために使用します。/dev/u64_dataはhostioライブラリのルーチン(例えばuhReadGame,
uhWriteGame)で使用します。/dev/u64_debugはGVDデバッガで使用します。/dev/u64_faultはgloadでfaultデータをモニタするのに使用します。/dev/u64_kdebugはSGIの内部ツールであるkdebugで使用され、外部の開発ツールではサポートされません。/dev/u64_profileはgperfでデータのprofilingをモニタするのに使用します。
<BR>
<P>
open()は固有のファイル記述子を返します。返されたファイル記述子は、すべてのサブシーケンスシステムコールでパラメータとしてデバイスドライバに渡されなければなりません。/dev/u64は複数個open出来ますが、マイナーデバイスは1クライアントからは1回しかopen出来ない点に注意して下さい。
<BR>
<BR>
<P>
<B>int close(int fildes)<BR>
</B>
<P>
close()はデバイスの使用を終了するためにコールします。ドライバリソースは使用されていたクライアントから開放され、そのクライアントのために接続中だったすべてのセマフォも開放されます。
<BR>
<BR>
<P>
<B>u64_giointr():<BR>
</B>
<P>
この内部ルーチンは、開発ボードからIndyに送信されたイベントデータをキューにためていきます。u64_giointr()は、GIO割り込みまたはRDB割り込みが検出されると起動します。このルーチンは、最初にProduct
IDレジスタをチェックし、どんな割り込みが発生したかを判断します。
<BR>
<P>
割り込みが、R4300がIndyのRDBレジスタに値が書いたことにより発生したものならば、その割り込みをクリアするために0x0がIndyのRDB
Write割り込みレジスタに書き込まれます。そして、ドライバはRDBレジスタから1word読み込んでキューに入れ、後でユーザレベルプロセスのリードシステムコールによりviaが変更された際に、その1wordを復帰させます。
<BR>
<P>
割り込みが、R4300がR4300のRDBレジスタから読み込んだことにより発生したものならば、IndyはIndyのRDB
Read割り込みレジスタに0x0を書き込んで、割り込みをクリアします。ドライバは(必要があれば)次の1wordをIndyのRDBレジスタに書き込むめるように内部状態を調整します。
<BR>
<P>
これ以外の場合は、割り込みはGIO割り込みレジスタによるものですが、GIO割り込みレジスタは使用されていないはずなので、エラーとみなされてデバイスドライバはエラーメッセージをコンソールに表示します。
<BR>
<P>
クライアントのキューにイベントが入ると、割り込み処理ルーチンはクライアントのためにpollwakeupをコールします(これにより、ユーザアプリケーションは、ブロックされたselect()またはpoll()のシステムコールからを復帰します)。また、まだ接続中のデータが呼び出せない状態でユーザレベルプログラムがread()をコールしたためにブロックされたセマフォも開放します。
<BR>
<BR>
<P>
<B>int read(int fildes, void *buf, unsigned nbyte)<BR>
</B>
<P>
read()システムコールは、最初に、渡されたファイル記述子が適正かどうか調べます。もし、マイナーデバイスが、正しいマイナーデバイスからデータを読み出そうとしていることを示せば、u64_giointr()によって管理されている適切なキューからデータを復帰させます。もし読み出せるデータが無い場合は、readコールはブロックされデータを待ちます。もし読み出せるデータがあってもreadコールによる要求より少なければ、readコールはデータをユーザバッファにコピーして正常に読み出せたデータのバイト数を返します。それ以上のデータを受け取るためには、ユーザアプリケーションはもう一度read()をコールしなければなりません。
<BR>
<BR>
<P>
<B>int write(int fildes, const void *buf, unsigned nbyte)</B>
<P>
write()システムコールはユーザレベルアプリケーションでIndyからR4300のRDBレジスタへの書き込みをするためのものです。デバイスドライバはユーザレベルアプリケーションから受け取った値をキューにためておいて、1回に1wordずつRDBポートに書き込みます。カーネルは最初にwrite()システムコールによってデータキューを作成し、それが一杯になるまで開発ボードからの"read"割り込み毎にRDBポートを通してデータを32bitずつ送信します。
<BR>
<BR>
<P>
<B>int ioctl(int filedes, int request, ...)<BR>
</B>
<P>
ioctl()システムコールは標準のEntry Pointでは使用出来ないカスタムコマンドを、ドライバで使用出来るようにします。/dev/u64ドライバのioctlコマンドには、ボードのリセットコマンドとRAMROMエリアへのアクセスコマンドがあります。filedesパラメータにはファイル記述子として常に"/dev/u64"を入れます。マイナーデバイスではioctlコールはサポートされていないことに注意して下さい。2番目のパラメータはioctlのどの機能を使用するかを指定します。3番目のパラメータは要求する機能により決まります。以下、使用できるコマンドとその使用方法です。
<BR>
<BR>
<P>
<B>U64_RESET:<BR>
</B>
<P>
3番目のパラメータを1にすると、リセットコントロールレジスタのプロセッサリセットbitがセットされます。0にすると、プロセッサリセットbitはクリアされR4300はramromからbootされます。
<BR>
<BR>
<P>
<B>U64_WRITE:<BR>
</B>
<P>
3番目のパラメータには次の構造体(u64gio.hで定義されている)へのポインタをセットします。
<BR>
<PRE>
<FONT SIZE=4> typedef struct u64_write_arg {
void *buffer; /* pointer to user's buffer of data */
long ramrom_addr; /* address in ramrom to be written */
int nbytes; /* number of bytes to write */
} u64_write_arg_t;<BR>
</FONT>
</PRE>
<P>
カーネルは、ユーザバッファからカーネルデータ構造体へデータをコピーし、そこからデータをramrom領域へコピーします。ioctl()はボード側がramromへアクセスを行っていない時だけ実行されるべきものです。具体的に言えば、ゲームが実行されている間は、このU64_WRITEコマンドはコールしてはいけないということです。本来このコマンドは、gloadとその他のツールがリセットプロセス中にromイメージをロードするために用意されたものです。
<BR>
<BR>
<P>
<B>U64_READ:<BR>
</B>
<P>
3番目のパラメータには次の構造体(u64gio.hで定義されている)へのポインタをセットします。:
<BR>
<PRE>
<FONT SIZE=4> typedef struct u64_read_arg {
void *buffer; /* pointer to user's buffer of data */
long ramrom_addr; /* address in ramrom to be read */
int nbytes; /* number of bytes to read */
} u64_read_arg_t;<BR>
</FONT>
</PRE>
<P>
カーネルは、ramromエリアの指定された場所のデータを専用のカーネルデータ構造体にコピーし、そこからデータをユーザバッファにコピーします。ioctl()はボート側がramromへアクセスを行っていない時だけ実行されるべきものです。具体的に言えば、ゲームが実行されている間は、このU64_READコマンドはコールしてはいけないということです。本来このコマンドは、gloadとその他のツールがリセットプロセス中にromイメージをベリファイするために用意されたものです。
<BR>
<BR>
<P>
<B>U64_SAFE_WRITE:<BR>
</B>
<P>
3番目のパラメータには次の構造体(u64gio.hで定義されている)へのポインタをセットします。:
<BR>
<PRE>
<FONT SIZE=4> typedef struct u64_write_arg { /* (same as used for U64_WRITE) */
void *buffer; /* pointer to user's buffer of data */
long ramrom_addr; /* address in ramrom to be written */
int nbytes; /* number of bytes to write */
} u64_write_arg_t;<BR>
</FONT>
</PRE>
<P>
U64_SAFE_WRITEコマンドがコールされると、デバイスドライバは、ゲーム側でramron領域をコントロールしているシステムスレッドと同期を取ります。ramromへのアクセスが許可されると、カーネルはwrite構造体で指定されたramromアドレスへデータをコピーします。書き込みが終了すると、カーネルは、ramromのコントロールを開放するために、ゲーム側のシステムスレッドに信号を送ります。このコマンドは、ボード側でゲームアプリケーションが実行されている時だけ使用出来ます。
<BR>
<P>
このU64_SAFE_WRITEコマンドはホスト側のライブラリである<A HREF="../uh/uhWriteRamrom.htm">uhWriteRamrom</A>関数で使用されています。
<BR>
<P>
<B>U64_SAFE_READ:<BR>
</B>
<P>
3番目のパラメータには次の構造体(u64gio.hで定義されている)へのポインタをセットします。:
<BR>
<BR>
<PRE>
<FONT SIZE=4> typedef struct u64_read_arg { /* Same as used for U64_READ */
void *buffer; /* pointer to user's buffer of data */
long ramrom_addr; /* address in ramrom to be read */
int nbytes; /* number of bytes to read */
} u64_read_arg_t;<BR>
</FONT>
</PRE>
<P>
U64_SAFE_READコマンドは、U64_SAFE_WRITEとデータの送信方向が逆になっただけで、機能的には同じものです(ramromエリアから読み出しで、書き込みではないということです)。U64_SAFE_WRITEと同様に、カーネルはデータを読み出す前に、ramromエリアにアクセスするために、ゲーム側のシステムスレッドと同期を取ります。このコマンドは、ボード側でゲームアプリケーションが実行されている時だけ使用出来ます。
<BR>
<P>
このU64_SAFE_READコマンドはホスト側のライブラリである<A HREF="../uh/uhReadRamrom.htm">uhReadRamrom</A>関数で使用されています。
<BR>
<P>
<B>参照<BR>
</B>
<P>
<A HREF="../uh/uhOpenGame.htm">uhOpenGame</A>(3P), <A HREF="../uh/uhReadGame.htm">uhReadGame</A>(3P),
<P>
<A NAME="OLE_LINK1"></A><A HREF="../uh/uhWriteGame.htm" >uhWriteGame</A>(3P),
<A HREF="../tool/gload.htm" >gload</A>(1P)
<P>
<A HREF="../uh/uhReadRamrom.htm">uhReadRamrom</A>(3P),<A HREF="../uh/uhWriteRamrom.htm">uhWriteRamrom</A>(3P),
<A HREF="../os/osOpenHost.htm">osOpenHost</A>(3P),
<P>
<A HREF="../os/osReadHost.htm">osReadHost</A>(3P), <A HREF="../os/osWriteHost.htm">osWriteHost</A>(3P),
<P>
<A HREF="../os/osSetEventMesg.htm">osSetEventMesg</A>(3P), <A HREF="../os/osStartThread.htm">osStartThread</A>(3P),
<A HREF="../os/osStopThread.htm">osStopThread</A>(3P),
<P>
open(2),close(2), read(2), write(2), ioctl(2), select(2), poll(2)
<BR>
</BODY>
</HTML>