u64.3p
18.9 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
401
402
403
404
405
406
407
408
.TH u64 3P local "Silicon Graphics, Inc."
.SH NAME
.upperok
u64 \- Introduction to the \f3/dev/u64\f1 device driver interface for the
Nintendo 64 (formerly known as Ultra 64) development board.
.SH DESCRIPTION
The Nintendo 64 development board is a double wide gio-bus peripheral card
designed for the Indy class of Silicon Graphics computers. A 16MB ram is
provided in the cartridge memory address space of the R4300 processor, and may
be accessed by the Indy host. Only a single megabyte of this RAM can be mapped
at a time by the Indy host, and this megabyte is chosen from the 16MB available
via a 4 bit page control register. Simultaneous R4300/Indy host memory accesses
are not supported, as the memory arbiter for the development board's 16MB of
"ramrom" does not support dual porting.
.P
Communication between the Indy host and the development board can occur using
either a gio-interrupt register, or a seperate RDB interrupt register. Early
releases of the software used the gio-interrupt, but starting with release 2.0F
all communication was moved to the RDB interrupt. The RDB interrupt hardware
is not available on hardware 1 boards. Only hardware 2 and later boards include
the RDB port. For this reason, hardware 1 boards are now considered obsolete, and
only hardware 2 boards are supported.
.P
The gio-interrupt is mapped to the cartridge interrupt on the development system.
Because the cartridge interrupt has been designated to be used by peripherials,
such as the bulky media device, it is critical that this interrupt not be used
any longer by host to development communication.
.P
The RDB port provides a dual ported interrupt register. The RDB port can be
thought of as two ports, each 32 bits wide, one for Indy to development
system communication, and the other for development system to Indy communication.
When the Indy wishes to send a message to the development system it can write
to the RDB port, and this will generate an interrupt on the development system.
When the development system reads the data on the RDB port, this generates an
interrupt on the Indy. This dual interrupt system provides a useful handshaking
system, that can insure data is read before more data is written to the RDB port.
The system is the same when the development system writes data to the RDB port.
This generates an interrupt on the Indy, and when the Indy reads the data from the
RDB port, this generates an interrupt on the development system. As mentioned above,
the RDB port acts as two independent ports. Thus both Indy to development system
communication and development system to Indy communication can occur simultaneously.
.P
The u64 device driver provides support for read, write and ioctl commands. These
commands are used to reset the system, read and write to the ramrom, and perform
various Indy and game system communications.
.P
A description of the board's registers and their intended purpose follows:
.SH Product ID Register
\f3
GIO address 0x1f400000 (R), no development system address
\f1
.P
This 32 bit register is used by the Indy kernel as it boots to uniquely
identify the Nintendo 64 development board; bits <31..30> are reserved for
gio interrupt identification (as described below); bits <30..8> are zero;
bit <7> is one, and bits <6..0> are set to 0x15. Only the bottom 7 bits
are significant for the boot probe, as the Indy kernel masks off all other
bits when doing the probe for GIO hardware at this standard address (all GIO
peripheral cards must identify themselves with a unique bit pattern at the
base address 0x1f400000).
.P
Two upper bits have been reserved for use by the RDB port to allow the
device driver to distinguish between the different RDB interrupt sources.
.P
Bit <30> (0x40000000), when set, indicates to the Indy interrupt that the
development system has read from the \f3RDB Register\f1.
.P
Bit <31> (0x80000000), when set, indicates to the Indy interrupt that the
development system has written to the \f3RDB Register\f1.
.P
If a gio interrupt occurs and neither of these bits are set, it must have been
due to a write by the development system to the standard \f3GIO Interrupt Register\f1,
described below.
.SH Reset Control Register
\f3
GIO address 0x1f400400 (W), no development system address
\f1
.P
Writes to this register can trigger a reset or an nmi (non-maskable
interrupt) on the development system. The reset is active when the pertinent
bit is set, and released when the same bit is cleared. NMI is armed when its
bit is set, and triggered when its bit is cleared. Bit <2> = NMI, bit <1> =
Processor reset.
.SH DRAM Page Control Register
\f3
GIO address 0x1f400600 (R/W), no development system address
\f1
.P
Four bits at <23..20> select a single megabyte from the 16 MB available, and
map it into the GIO address range of 0x1f500000..0x1f5ffffe. The Indy can only
map two megabytes of GIO bus space at a time, and the first megabyte is used
to map in these registers; thus there is only a megabyte available for mapping
in the 16 megabytes of ramrom memory.
.SH Cartridge Interrupt Register
\f3
GIO address 0x1f400800 (R/W), development system R4300 address 0x18000800 (R)
\f1
.P
The cartridge interrupt register will generate an INT1 interrupt on the R4300
processor. The host may write 6 bits of data to this register, in bits <5..0>;
the R4300 may read these bits to determine what to do with the interrupt.
The interrupt is cleared when the R4300 reads from this register. Note: This
interrupt should no longer be used.
.SH GIO Interrupt Register
\f3
GIO address 0x1f400c00 (R), development system R4300 address 0x18000000 (R/W)
\f1
.P
The R4300 may write a 6 bit value to bits <5..0>; the act of writing this
register will cause a GIO interrupt to occur on the Indy host side. Upon
receiving this interrupt, the Indy host reads the gio interrupt register to
clear the interrupt. Note: This interrupt should no longer be used.
.SH GIO Sync Register
\f3
GIO address 0x1f400e00 (R), development system R4300 address 0x18000400 (R/W)
\f1
.P
The R4300 may write a 6 bit value to bits <5..0>; the host may read this value.
No interrupt to the Indy host is generated by the write cycle, so that a
polling scheme may be implemented between the two processors. The 6 bit value
in either the \f3GIO Interrupt\f1 or \f3GIO Sync\f1 registers corresponds to
the most recently written value to either register.
.SH RDB Registers
\f3
GIO address 0x1f480000 (W), development system R4300 address 0xc0000000 (R)
.br
GIO address 0x1f480000 (R), development system R4300 address 0xc0000000 (W)
\f1
.P
There are two 32 bit registers; one is provided for Indy to R4300
communication, and another for R4300 to Indy communication. Thus, both
processors may start write cycles at the same time and no data will be lost.
Upon initiating a read or write cycle, an interrupt which denotes the cycle
type (read or write) is sent to the other processor.
.P
The Indy's interrupt service routine must read the \f3Product ID Register\f1
to determine whether the R4300 performed a read or write cycle from a
\f3RDB Register\f1; Bit 30 of the \f3Product ID Register\f1 will be set when
the R4300 has read from its \f3RDB Register\f1, and Bit 31 will be
set when the R4300 has written to its \f3RDB Register\f1.
.P
The R4300 receives separate interrupts whenever the Indy has read or written
from/to a \f3RDB Register\f1. INT3 (CAUSE_IP6) is set when the Indy has read
from its \f3RDB Register\f1; INT4 (CAUSE_IP7) is set when the Indy
has written to its \f3RDB Register\f1.
.P
The interrupt service routine for either the Indy or R4300 should (in the
event of a "write interrupt") read from its \f3RDB Register\f1 before
returning, to maximize data throughput (once the data has been read, another
write cycle may be initiated by an Indy application or Nintendo64 thread).
.P
These registers (and the interrupt registers described below) are mapped into
the upper portion of the first megabyte of the gio address space on the Indy
side, and are mapped into the external SysAD (System Address and Data) device
address space on the R4300 side.
.SH RDB Write Interrupt
\f3
GIO address 0x1f480008 (W), R4300 address 0xc0000008 (W)
\f1
.P
Whenever either processor has completed a write to its \f3RDB Register\f1,
a "write interrupt" is generated to the other processor. The interrupt service
routine for this processor clears the interrupt by writing a 0x0 to its write
interrupt register. Note that it is the the act of reading the data that
generates the interrupt on the opposing processor, and that writing to the
\f3RDB Write Interrupt Register\f1 only clears the interrupt condition on the
processor running the interrupt routine.
.P
.SH RDB Read Interrupt
\f3
GIO address 0x1f48000c (W), R4300 address 0xc000000c (W)
\f1
.P
Whenever either processor has completed a read from its \f3RDB Register\f1,
a "read interrupt" is generated to the other processor. The interrupt service
routine for this processor clears the interrupt by writing a 0x0 to its read
interrupt register.
.SH Device Driver Entry Points
.P
A set of driver entry points define what the \f3/dev/u64\f1 device driver must
do when a user-level program executes a system call (such as \f3open()\f1) that
accesses the device. Because the user treats the device as a file, we have
provided driver entry points for the standard file operations such as \f3open,
read, write, \f1and\f3 close\f1.
.P
In addition to these standard entry points, we have implemented the
\f3chpoll\f1 function so that users can use \f3select()\f1 or \f3poll()\f1 to
test for pending input or output from the opened file descriptors.
.P
There are several functions internal to the device driver which the user never
sees, but are standard entry points for kernel functionality. \f3edtinit()\f1
provides a boot time probe of the board, and will initialize the board and
allocate memory resources for the device driver if a board is found. The
address for the driver's GIO interrupt service routine \f3u64_giointr()\f1 is
entered into the kernel's table of interrupt service routines by
\f3edtinit()\f1. Each of the standard system calls below have man pages
available on the system.
.P
In order to multiplex different types of data over the RDB efficiently, the
device driver makes extensive use of device minors. In addition to the major
device, \f3/dev/u64\f1, the following device minors are currently available:
\f3/dev/u64_print\f1, \f3/dev/u64_logging\f1, \f3/dev/u64_data\f1,
\f3/dev/u64_debug\f1, \f3/dev/u64_fault\f1, \f3/dev/u64_kdebug\f1,
\f3/dev/u64_profile\f1.
.bp
.P
\f3int open(int open (const char *path, int oflag, ... /* mode_t mode */))\f1
.P
The user calls \f3open()\f1 with one of the u64 device files found
in the \f3/dev\f1 directory. \f3/dev/u64\f1 is used for resetting the development
system and accessing the ramrom. \f3/dev/u64_print\f1 is used by the print server
in gload.
\f3/dev/u64_logging\f1 is used by gload to handle the flushing of log data.
\f3/dev/u64_data\f1 is used by the hostio library routines, such as \f3uhReadGame\f1
and \f3uhWriteGame\f1.
\f3/dev/u64_debug\f1 is used by the debugger GVD.
\f3/dev/u64_fault\f1 is used by gload to monitor for fault data.
\f3/dev/u64_kdebug\f1 is used by the internal SGI tool kdebug and is not supported
as an external development tool.
\f3/dev/u64_profile\f1 is used by gperf to monitor for profiling data.
.P
\f3open()\f1 returns a unique file descriptor which must be passed in as a
parameter for all subsequent system calls to the device driver. Note that
\f3/dev/u64\f1 can be opened multiple times, but that the minor devices can
only be opened by one client at a time.
.P
\f3int close(int fildes)\f1
.P
The user process invokes the \f3close()\f1 system call when it is finished with
its usage of the device; driver resources are freed up for this client, and
any pending semaphores held on behalf of this client are released.
.P
\f3u64_giointr():\f1
.P
This internal routine queues event data transmitted from the development board
to the host Indy. Whenever a GIO or RDB interrupt is detected, \f3u64_giointr()\f1
gets invoked. It first checks the \f3Product ID Register\f1 to determine what
type of interrupt was generated.
.P
If the interrupt was due to a write to the Indy's \f3RDB Register\f1
by the R4300, a 0x0 is written to the Indy's \f3RDB Write Interrupt
Register\f1 to clear the interrupt, and the driver reads a word from the
\f3RDB Register\f1 and queues it for later retrieval by a user-level process via the
\f3read\f1 system call.
.P
If the interrupt source was due to a read from the R4300's \f3RDB Register\f1
by the R4300, the Indy clears the read interrupt by writing 0x0 to
its \f3RDB Read Interrupt Register\f1. The driver then adjusts its
internal state such that another word can be written to the Indy's \f3RDB
Register\f1 (if necessary).
.P
Otherwise, the interrupt source must be the \f3GIO Interrupt Register\f1.
Since the \f3GIO Interrupt Register\f1 is no longer used this is considered
an error and the device driver prints an error message to the console.
.P
If an event is queued for a client, the interrupt service routine calls
\f3pollwakeup\f1 on behalf of a client (this will cause a user-level
application to return from a blocked \f3select()\f1 or \f3poll()\f1 system
call). We also free up any blocked semaphores which may have been set by a
user-level program's attempt to \f3read()\f1 when no pending data was yet
available.
.P
\f3int read(int fildes, void *buf, unsigned nbyte)\f1
.P
The \f3read()\f1 system call first qualifies the incoming file descriptor
argument; if the minor device indicates that we are reading from a valid
minor, we retrieve data from the appropriate queue maintained by
\f3u64_giointr()\f1. If there is no data available, the read call will block
waiting for data. If there is data available, but not as much as requested by
the read, the read call will copy the data to the user's buffer and
return the number of valid bytes. In order to receive more data,
the user's application will have to make another call to read().
.P
.bp
.P
\f3int write(int fildes, const void *buf, unsigned nbyte)\f1
.P
The \f3write()\f1 system call is intended to support writes from the Indy to
the R4300 \f3RDB Register\f1 from the user level applications. The device driver
queues up values from the user-level application and writes these words one
at a time to the RDB port. The kernel will continue to send each 32 bit word
of data through the RDB port as each "read" interrupt is received from the
development board, until the queue of data initially created by the \f3write()\f1
system call is depleted.
.P
\f3int ioctl(int filedes, int request, ...)\f1
.P
The \f3ioctl()\f1 system call allows a driver to provide custom functions not
available from the standard entry points. The \f3/dev/u64\f1 driver's ioctl
commands allow the user to reset the development system, and to access the
RAMROM. The filedes argument should always be a file descriptor for the device,
\f3/dev/u64\f1. Note that minors do not support ioctl calls. The second argument
to the \f3ioctl()\f1 specifies what type of function is to be invoked, and
the type of the optional third argument varies depending upon the request made.
A list of the available commands and their intended purpose follows:
.P
\f3U64_RESET\f1:
.P
If the third argument is 1, the Processor reset bit of the
\f3Reset Control Register\f1 is set. If it is zero, the Processor reset bit is
cleared, and the R4300 attempts to boot itself from the contents of ramrom.
.P
\f3U64_WRITE\f1:
.P
The third parameter is a pointer to the following structure (defined in
\f3u64gio.h\f1):
.P
.nf
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;
.fi
.P
The kernel copies the data from the user's buffer into a kernel data
structure, then copies the data from there into ramrom. This ioctl() should
only be made when the development system will not attempt to access
the ramrom. In practice, this means, this ioctl should not be called when
the game is executing. This ioctl is primarily intended for gload and other
tools to use to load rom images during the reset process.
.P
\f3U64_READ\f1:
.P
The third parameter is a pointer to the following structure (defined in
\f3u64gio.h\f1):
.P
.nf
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;
.fi
.P
The kernel copies the data from the specified ramrom location into a
dedicated kernel data structure, then copies the data from there into the
user's buffer. This ioctl() should only be made when the development system
will not attempt to access the ramrom. In practice, this means, this ioctl should
not be called when the game is executing. This ioctl is primarily intended
for gload and other tools to use to verify the rom during the reset process.
.P
\f3U64_SAFE_WRITE\f1:
.P
The third parameter is a pointer to the following structure (defined in
\f3u64gio.h\f1):
.P
.nf
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;
.fi
.P
When this ioctl() is called, the device driver negotiates with the game's
system threads for control of the ramrom. Once access to the ramrom has
been granted, the kernel copies the data to the ramrom address specified
in the write structure. After writing is complete, the kernel signals the
game's system threads to release control of the ramrom. This ioctl() should
only be used when the development system is executing a game application.
.P
The \f3U64_SAFE_WRITE\f1 ioctl() is used by the library function \f3uhWriteRamrom\f1.
.P
\f3U64_SAFE_READ\f1:
.P
The third parameter is a pointer to the following structure (defined in
\f3u64gio.h\f1):
.P
.nf
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;
.fi
.P
This ioctl is the logical equivalent of \f3U64_SAFE_WRITE\f1, with the data
direction reversed (we are reading from ramrom memory, rather than writing to
it). Like \f3U64_SAFE_WRITE\f1, the kernel negotiates with the game's system
threads for access to the ramrom before attempting to read any data.This
ioctl() should only be used when the development system is executing a game
application.
.P
The \f3U64_SAFE_READ\f1 ioctl() is used by the library function \f3uhReadRamrom\f1.
.P
.SH "SEE ALSO"
.IR uhOpenGame (3P),
.IR uhReadGame (3P),
.IR uhWriteGame (3P),
.IR uhReadRamrom (3P),
.IR uhWriteRamrom (3P),
.IR osOpenHost (3P),
.IR osReadHost (3P),
.IR osWriteHost (3P),
.IR osSetEventMesg (3P),
.IR osStartThread (3P),
.IR osStopThread (3P),
.IR open (2),
.IR close (2),
.IR read (2),
.IR write (2),
.IR ioctl (2),
.IR select (2),
.IR poll (2)