/[gxemul]/upstream/0.3.8/doc/experiments.html
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.8/doc/experiments.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/html
File size: 19660 byte(s)
0.3.8
1 <html><head><title>Gavare's eXperimental Emulator:&nbsp;&nbsp;&nbsp;Experimenting with GXemul</title>
2 <meta name="robots" content="noarchive,nofollow,noindex"></head>
3 <body bgcolor="#f8f8f8" text="#000000" link="#4040f0" vlink="#404040" alink="#ff0000">
4 <table border=0 width=100% bgcolor="#d0d0d0"><tr>
5 <td width=100% align=center valign=center><table border=0 width=100%><tr>
6 <td align="left" valign=center bgcolor="#d0efff"><font color="#6060e0" size="6">
7 <b>Gavare's eXperimental Emulator:</b></font><br>
8 <font color="#000000" size="6"><b>Experimenting with GXemul</b>
9 </font></td></tr></table></td></tr></table><p>
10
11 <!--
12
13 $Id: experiments.html,v 1.96 2006/02/18 13:15:20 debug Exp $
14
15 Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are met:
19
20 1. Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22 2. Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25 3. The name of the author may not be used to endorse or promote products
26 derived from this software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 SUCH DAMAGE.
39
40 -->
41
42 <a href="./">Back to the index</a>
43
44 <p><br>
45 <h2>Experimenting with GXemul</h2>
46
47 <p>
48 <ul>
49 <li><a href="#hello">Hello world</a>
50 <li><a href="#expdevices">Experimental devices</a>
51 </ul>
52
53
54
55
56
57
58 <p><br>
59 <a name="hello"></a>
60 <h3>Hello world:</h3>
61
62 You might want to use the emulator to develop programs on your own,
63 not just run precompiled kernels such as NetBSD. To get started, I recommend
64 that you do two things:
65
66 <p>
67 <ul>
68 <li>Build and install a cross-compiler for MIPS.
69 <li>Compile this hello world program, and run it in the emulator.
70 </ul>
71
72 <p>
73 <table border="0"><tr><td width="40">&nbsp;</td><td>
74 <pre>
75 <font color=#f00000>/* Hello world for GXemul */
76
77 /* Note: The cast to a signed int causes the address to be sign-extended
78 correctly to 0xffffffffb00000xx when compiled in 64-bit mode */
79 </font><font color=#a0a0a0>#define PUTCHAR_ADDRESS ((signed int)0xb0000000)
80 #define HALT_ADDRESS ((signed int)0xb0000010)
81
82 </font><font color=#c000c0>void </font><font color=#000000><a name="printchar">printchar</a>(</font><font color=#c000c0>char </font><font color=#000000>ch)
83 {
84 *((</font><font color=#c000c0>volatile unsigned char </font><font color=#000000>*) PUTCHAR_ADDRESS) = ch;
85 }
86
87 </font><font color=#c000c0>void </font><font color=#000000><a name="halt">halt</a>(</font><font color=#c000c0>void</font><font color=#000000>)
88 {
89 *((</font><font color=#c000c0>volatile unsigned char </font><font color=#000000>*) HALT_ADDRESS) = 0;
90 }
91
92 </font><font color=#c000c0>void </font><font color=#000000><a name="printstr">printstr</a>(</font><font color=#c000c0>char </font><font color=#000000>*s)
93 {
94 </font><font color=#c000c0>while </font><font color=#000000>(*s)
95 printchar(*s++);
96 }
97
98 </font><font color=#c000c0>void </font><font color=#000000>f(</font><font color=#c000c0>void</font><font color=#000000>)
99 {
100 printstr(</font><font color=#00c000>"Hello world\n"</font><font color=#000000>);
101 halt();
102 }
103 </font></pre>
104 </td></tr></table>
105
106 <p>(This hello world program is available here as well:
107 <a href="hello_mips.c"><tt>hello_mips.c</tt></a>)
108
109 <p>I recommend that you build a GCC cross compiler for the
110 <b>mips64-unknown-elf</b> target, and install it. Other compilers could
111 work too, but GCC is good because of its portability. Then try to compile
112 and link the hello world program:
113 <pre>
114 $ <b>mips64-unknown-elf-gcc -O2 hello_mips.c -mips4 -mabi=64 -c</b>
115 $ <b>mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f hello_mips.o -o hello_mips --oformat=elf64-bigmips</b>
116 $ <b>file hello_mips</b>
117 hello_mips: ELF 64-bit MSB mips-4 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped
118 $ <b>gxemul -q -E testmips hello_mips</b>
119 Hello world
120
121 $ <b>mips64-unknown-elf-gcc -O2 hello_mips.c -c</b>
122 $ <b>mips64-unknown-elf-ld -Ttext 0x80030000 -e f hello_mips.o -o hello_mips</b>
123 $ <b>file hello_mips</b>
124 hello_mips: ELF 32-bit MSB mips-3 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped
125 $ <b>gxemul -q -E testmips hello_mips</b>
126 Hello world
127 </pre>
128
129 <p>
130 As you can see above, a GCC configured for mips64-unknown-elf can produce
131 both 64-bit and 32-bit binaries. If you don't want to run the entire
132 Hello World program, but want to single-step through the execution to
133 learn more about how MIPS programs run, then add -V to the command line:
134
135 <p>
136 <pre>
137 $ <b>gxemul -V -E testmips hello_mips</b>
138 ..
139 GXemul&gt; <b>r</b>
140 cpu0: pc = a800000000030078 <f>
141 cpu0: hi = 0000000000000000 lo = 0000000000000000
142 cpu0: zr = 0000000000000000 at = 0000000000000000
143 cpu0: v0 = 0000000000000000 v1 = 0000000000000000
144 ..
145 cpu0: gp = a8000000000780c0 sp = ffffffffa0007f00
146 cpu0: fp = 0000000000000000 ra = 0000000000000000
147 GXemul&gt; <b>s 15</b>
148 &lt;f&gt;
149 a800000000030078: 67bdfff0 daddiu sp,sp,-16
150 a80000000003007c: 3c04a800 lui a0,0xa800
151 a800000000030080: 3c010003 lui at,0x3
152 a800000000030084: 64840000 daddiu a0,a0,0
153 a800000000030088: 642100b8 daddiu at,at,184
154 a80000000003008c: 0004203c dsll32 a0,a0,0
155 a800000000030090: 0081202d daddu a0,a0,at
156 a800000000030094: ffbf0000 sd ra,0(sp) [0xffffffffa0007ef0, data=0x0000000000000000]
157 a800000000030098: 0c00c00a jal 0xa800000000030028 &lt;printstr&gt;
158 a80000000003009c: 00000000 (d) nop
159 &lt;printstr("Hello world\n",0,0,0,..)&gt;
160 &lt;printstr&gt;
161 a800000000030028: 67bdfff0 daddiu sp,sp,-16
162 a80000000003002c: ffb00000 sd s0,0(sp) [0xffffffffa0007ee0, data=0x0000000000000000]
163 a800000000030030: ffbf0008 sd ra,8(sp) [0xffffffffa0007ee8, data=0xa8000000000300a0]
164 a800000000030034: 90820000 lbu v0,0(a0) [0xa8000000000300b8 = $LC0, data=0x48]
165 a800000000030038: 00021600 sll v0,v0,24
166 GXemul&gt; <b>print v0</b>
167 v0 = 0x0000000048000000
168 GXemul&gt; <b>_</b>
169 </pre>
170
171 <p>The syntax of the single-step debugger shouldn't be too hard to grasp.
172 Type "<tt>s</tt>" to single-step one instruction. For some commands (e.g.
173 the single-step command), just pressing enter on a blank line will cause
174 the last command to be repeated. Type "<tt>quit</tt>" to quit.
175
176 <p>
177 Hopefully this is enough to get you inspired. :-)
178
179
180
181
182
183
184 <p><br>
185 <a name="expdevices"></a>
186 <h3>Experimental devices:</h3>
187
188 The emulator has several modes where it doesn't emulate any real machine.
189 It can either run in "bare" mode, where no devices are included by default
190 (just the CPU), or in a "test" mode where some simple devices are
191 emulated.
192
193 <p>The test machines (<tt>testmips</tt>, <tt>testppc</tt>, etc) have the
194 following experimental devices:
195
196 <p>
197 <center><table border="0" width="80%">
198
199 <tr>
200 <td align="left" valign="top" width="200">
201 <a name="expdevices_cons"><b><tt>cons</tt>:</b></a>
202 <p>A simple console device, for writing
203 characters to the controlling terminal
204 and receiving keypresses.
205 <p>Source code:&nbsp;&nbsp;<font color="#0000f0"><tt>src/devices/dev_cons.c</tt></font>
206 <br>Default physical address:&nbsp&nbsp;<font color="#0000f0">0x10000000</font>
207 </td>
208 <td align="left" valign="top" width="25">&nbsp;</td>
209 <td align="left" valign="top">
210 <table border="0">
211 <tr>
212 <td align="left" valign="top"><i><u>Offset:</u></i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
213 <td align="left" valign="top"><i><u>Effect:</u></i></td>
214 </tr>
215 <tr>
216 <td align="left" valign="top"><tt>0x00</tt></td>
217 <td align="left" valign="top">
218 Read: <b><tt>getchar()</tt></b> (non-blocking; returns
219 <tt>0</tt> if no char was available)<br>
220 Write: <b><tt>putchar(ch)</tt></b></td>
221 </tr>
222 <tr>
223 <td align="left" valign="top"><tt>0x10</tt></td>
224 <td align="left" valign="top">Read or write: <b><tt>halt()</tt></b><br>
225 (Useful for exiting the emulator.)</td>
226 </tr>
227 </table>
228 </td>
229 </tr>
230
231 <tr height="15">
232 <td height="15">&nbsp;</td>
233 </tr>
234
235 <tr>
236 <td align="left" valign="top">
237 <a name="expdevices_mp"><b><tt>mp</tt>:</b></a>
238 <p>This device controls the behaviour of CPUs in an emulated
239 multi-processor system.
240 <p>Source code:&nbsp;&nbsp;<font color="#0000f0"><tt>src/devices/dev_mp.c</tt></font>
241 <br>Default physical address:&nbsp&nbsp;<font color="#0000f0">0x11000000</font>
242 </td>
243 <td></td>
244 <td align="left" valign="top">
245 <table border="0">
246 <tr>
247 <td align="left" valign="top"><i><u>Offset:</u></i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
248 <td align="left" valign="top"><i><u>Effect:</u></i></td>
249 </tr>
250 <tr>
251 <td align="left" valign="top"><tt>0x0000</tt></td>
252 <td align="left" valign="top">Read: <b><tt>whoami()</tt></b>.
253 Returns the id of the CPU doing the read.</td>
254 </tr>
255 <tr>
256 <td align="left" valign="top"><tt>0x0010</tt></td>
257 <td align="left" valign="top">Read: <b><tt>ncpus()</tt></b>.
258 Returns the number of CPUs in the system.</td>
259 </tr>
260 <tr>
261 <td align="left" valign="top"><tt>0x0020</tt></td>
262 <td align="left" valign="top">Write: <b><tt>startupcpu(i)</tt></b>.
263 Starts CPU i. It begins execution at the address
264 set by a write to startupaddr (see below).</td>
265 </tr>
266 <tr>
267 <td align="left" valign="top"><tt>0x0030</tt></td>
268 <td align="left" valign="top">Write: <b><tt>startupaddr(addr)</tt></b>.
269 Sets the starting address for CPUs.</td>
270 </tr>
271 <tr>
272 <td align="left" valign="top"><tt>0x0040</tt></td>
273 <td align="left" valign="top">Write: <b><tt>pause_addr(addr)</tt></b>.
274 Sets the pause address. (TODO: This is not
275 used anymore?)</td>
276 </tr>
277 <tr>
278 <td align="left" valign="top"><tt>0x0050</tt></td>
279 <td align="left" valign="top">Write: <b><tt>pause_cpu(i)</tt></b>.
280 Stops all CPUs <i>except</i> CPU i.</td>
281 </tr>
282 <tr>
283 <td align="left" valign="top"><tt>0x0060</tt></td>
284 <td align="left" valign="top">Write: <b><tt>unpause_cpu(i)</tt></b>.
285 Unpauses all CPUs <i>except</i> CPU i.</td>
286 </tr>
287 <tr>
288 <td align="left" valign="top"><tt>0x0070</tt></td>
289 <td align="left" valign="top">Write: <b><tt>startupstack(addr)</tt></b>.
290 Sets the startup stack address. (CPUs started with
291 startupcpu() above will have their stack pointer
292 set to this value.)</td>
293 </tr>
294 <tr>
295 <td align="left" valign="top"><tt>0x0080</tt></td>
296 <td align="left" valign="top">Read: <b><tt>hardware_random()</tt></b>.
297 This produces a "random" number.</td>
298 </tr>
299 <tr>
300 <td align="left" valign="top"><tt>0x0090</tt></td>
301 <td align="left" valign="top">Read: <b><tt>memory()</tt></b>.
302 Returns the number of bytes of RAM in the system.</td>
303 </tr>
304 <tr>
305 <td align="left" valign="top"><tt>0x00a0</tt></td>
306 <td align="left" valign="top">Write: <b><tt>ipi_one((nr &lt;&lt; 16) + cpuid)</tt></b>.
307 Sends IPI <tt>nr</tt> to a specific CPU.</td>
308 </tr>
309 <tr>
310 <td align="left" valign="top"><tt>0x00b0</tt></td>
311 <td align="left" valign="top">Write: <b><tt>ipi_many((nr &lt;&lt; 16) + cpuid)</tt></b>.
312 Sends IPI <tt>nr</tt> to all CPUs <i>except</i>
313 the specified one.</td>
314 </tr>
315 <tr>
316 <td align="left" valign="top">0x00c0</tt></td>
317 <td align="left" valign="top">Read: <b><tt>ipi_read()</tt></b>.
318 Returns the next pending IPI. 0 is returned if there is no
319 pending IPI (so 0 shouldn't be used for valid IPIs).
320 Hardware int 6 is deasserted when the IPI queue is empty.
321 <br>Write: <b><tt>ipi_flush()</tt></b>.
322 Clears the IPI queue, discarding any pending IPIs.</td>
323 </tr>
324 <tr>
325 <td align="left" valign="top">0x00d0</tt></td>
326 <td align="left" valign="top">Read: <b><tt>ncycles()</tt></b>.
327 Returns approximately the number of cycles executed.
328 Note: this value is not updated for every instruction,
329 so it cannot be used for small measurements.</td>
330 </tr>
331 </table>
332 </td>
333 </tr>
334
335 <tr height="15">
336 <td height="15">&nbsp;</td>
337 </tr>
338
339 <tr>
340 <td align="left" valign="top">
341 <a name="expdevices_fb"><b><tt>fb</tt>:</b></a>
342 <p>A simple linear framebuffer, for graphics output.
343 640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each).
344 <p>Source code:&nbsp;&nbsp;<font color="#0000f0"><tt>src/devices/dev_fb.c</tt></font>
345 <br>Default physical address:&nbsp&nbsp;<font color="#0000f0">0x12000000</font>
346 </td>
347 <td></td>
348 <td align="left" valign="top">
349 <table border="0">
350 <tr>
351 <td align="left" valign="top"><i><u>Offset:</u></i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
352 <td align="left" valign="top"><i><u>Effect:</u></i></td>
353 </tr>
354 <tr>
355 <td align="left" valign="top"><tt>0x00000-</tt><br><tt>0xe0fff</tt></td>
356 <td align="left" valign="top">Read: read pixel values.
357 <br>Write: write pixel values.</td>
358 </tr>
359 </table>
360 </td>
361 </tr>
362
363 <tr height="15">
364 <td height="15">&nbsp;</td>
365 </tr>
366
367 <tr>
368 <td align="left" valign="top">
369 <a name="expdevices_disk"><b><tt>disk</tt>:</b></a>
370 <p>Disk controller, which can read from and write
371 to disk images. It does not use interrupts; read and
372 write operations finish instantaneously.
373 <p>Source code:&nbsp;&nbsp;<font color="#0000f0"><tt>src/devices/dev_disk.c</tt></font>
374 <br>Default physical address:&nbsp&nbsp;<font color="#0000f0">0x13000000</font>
375 </td>
376 <td></td>
377 <td align="left" valign="top">
378 <table border="0">
379 <tr>
380 <td align="left" valign="top"><i><u>Offset:</u></i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
381 <td align="left" valign="top"><i><u>Effect:</u></i></td>
382 </tr>
383 <tr>
384 <td align="left" valign="top"><tt>0x0000</tt></td>
385 <td align="left" valign="top">Write: Set the offset (in bytes) from the beginning
386 of the disk image. This offset will be used for the next read/write operation.</td>
387 </tr>
388 <tr>
389 <td align="left" valign="top"><tt>0x0010</tt></td>
390 <td align="left" valign="top">Write: Select the SCSI ID to be used in the next
391 read/write operation.</td>
392 </tr>
393 <tr>
394 <td align="left" valign="top"><tt>0x0020</tt></td>
395 <td align="left" valign="top">Write: Start a read or write operation.
396 (Writing <tt>0</tt> means a Read operation, a <tt>1</tt> means a
397 Write operation.)</td>
398 </tr>
399 <tr>
400 <td align="left" valign="top"><tt>0x0030</tt></td>
401 <td align="left" valign="top">Read: Get status of the last operation.
402 (Status 0 means failure, non-zero means success.)</td>
403 </tr>
404 <tr>
405 <td align="left" valign="top"><tt>0x4000-</tt><br><tt>0x41ff</tt>&nbsp;&nbsp;&nbsp;</td>
406 <td align="left" valign="top">Read/Write: 512 bytes data buffer.</td>
407 </tr>
408 </table>
409 </td>
410 </tr>
411
412 <tr height="15">
413 <td height="15">&nbsp;</td>
414 </tr>
415
416 <tr>
417 <td align="left" valign="top">
418 <a name="expdevices_ether"><b><tt>ether</tt>:</b></a>
419 <p>A simple ethernet controller, enough to send
420 and receive packets on a simulated network.
421 <p>Source code:&nbsp;&nbsp;<font color="#0000f0"><tt>src/devices/dev_ether.c</tt></font>
422 <br>Default physical address:&nbsp&nbsp;<font color="#0000f0">0x14000000</font>
423 </td>
424 <td></td>
425 <td align="left" valign="top">
426 <table border="0">
427 <tr>
428 <td align="left" valign="top"><i><u>Offset:</u></i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
429 <td align="left" valign="top"><i><u>Effect:</u></i></td>
430 </tr>
431 <tr>
432 <td align="left" valign="top"><tt>0x0000-</tt><br><tt>0x3fff</tt></td>
433 <td align="left" valign="top">Read/write buffer for the packet to be sent/received.</td>
434 </tr>
435 <tr>
436 <td align="left" valign="top"><tt>0x4000</tt></td>
437 <td align="left" valign="top">Read: status word, one or more of these:
438 <br><tt>0x01</tt>&nbsp;=&nbsp;something was received (because of
439 the last command)
440 <br><tt>0x02</tt>&nbsp;=&nbsp;more packets are available
441 <br><i>NOTE:</i> Whenever the status word is non-zero,
442 an interrupt is asserted. Reading the status word
443 clears it, and deasserts the interrupt.</td>
444 </tr>
445 <tr>
446 <td align="left" valign="top"><tt>0x4010</tt></td>
447 <td align="left" valign="top">Read: get the Length of the received packet
448 <br>Write: set the Length of the next packet to transmit</td>
449 </tr>
450 <tr>
451 <td align="left" valign="top"><tt>0x4020</tt></td>
452 <td align="left" valign="top">Write: command:
453 <br><tt>0x00:</tt>&nbsp;receive a packet
454 <br><tt>0x01:</tt>&nbsp;send a packet</td>
455 </tr>
456 </table>
457 </td>
458 </tr>
459
460 </table></center>
461
462 <p>
463 While these devices may resemble real-world hardware, they are
464 intentionally made simpler to use. (An exception is the framebuffer;
465 some machines actually have simple linear framebuffers like this.)
466
467 <p>If the physical address is <tt>0x10000000</tt>, then for MIPS that
468 means that it can be accessed at virtual address
469 <tt>0xffffffffb0000000</tt>. (Actually it can be accessed at
470 <tt>0xffffffff90000000</tt> too, but devices should usually be accessed in
471 a non-cached manner.)
472
473 <p> (When using the PPC test machine (<tt>testppc</tt>), the addresses are
474 <tt>0x10000000</tt>, <tt>0x11000000</tt> etc., so no need to add any
475 virtual displacement.)
476
477 <p>The <b><tt>mp</tt></b>, <b><tt>disk</tt></b>, and <b><tt>ether</tt></b>
478 devices are agnostic when it comes to word-length. For example, when
479 reading offset <tt>0x0000</tt> of the <b><tt>mp</tt></b>
480 device, you may use any kind of read (an 8-bit read will work just as well
481 as a 64-bit read, although the value will be truncated to 8 bits in the
482 first case). You can <i>not</i>, however, read one byte from <tt>0x0000</tt>
483 and one from <tt>0x0001</tt>, and combine the result. The read from
484 <tt>0x0001</tt> will be invalid.
485
486 <p>The <b><tt>cons</tt></b> device should be accessed using 8-bit reads
487 and writes. Doing a getchar() (ie reading from offset <tt>0x00</tt>)
488 returns <tt>0</tt> if no character was available.
489
490 <p>On MIPS, the <b><tt>cons</tt></b> device is hardwired to interrupt 2
491 (the lowest hardware interrupt). Whenever a character is available, the
492 interrupt is asserted. When there are no more available characters, the
493 interrupt is deasserted. (Remember that the interrupt has to be enabled in
494 the status register of the system coprocessor.)
495
496 <p>The <b><tt>ether</tt></b> device is hardwired to interrupt 3.
497
498 <p>The IPIs controlled by the <b><tt>mp</tt></b> device are hardwired to
499 interrupt 6. Whenever an IPI is "sent", interrupt 6 is asserted on the
500 target CPU(s), and the IPI number is added last in the IPI queue for that
501 CPU. It is then up to that CPU to read from offset <tt>0x00c0</tt>, to
502 figure out what kind of IPI it was.
503
504 <p>A simple tutorial on how to use the <tt>disk</tt> device, if not clear
505 from the description above, can be found here: <a
506 href="test_disk.c"><tt>test_disk.c</tt></a>
507
508
509
510
511 </p>
512
513 </body>
514 </html>

  ViewVC Help
Powered by ViewVC 1.1.26