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)