10 |
|
|
11 |
<!-- |
<!-- |
12 |
|
|
13 |
$Id: experiments.html,v 1.96 2006/02/18 13:15:20 debug Exp $ |
$Id: experiments.html,v 1.105 2006/12/30 13:30:50 debug Exp $ |
14 |
|
|
15 |
Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
16 |
|
|
17 |
Redistribution and use in source and binary forms, with or without |
Redistribution and use in source and binary forms, with or without |
18 |
modification, are permitted provided that the following conditions are met: |
modification, are permitted provided that the following conditions are met: |
65 |
|
|
66 |
<p> |
<p> |
67 |
<ul> |
<ul> |
68 |
<li>Build and install a cross-compiler for MIPS. |
<li>Build and install a cross-compiler for your chosen target. |
69 |
<li>Compile this hello world program, and run it in the emulator. |
GCC is usually a good compiler choice, because it is portable |
70 |
|
and in wide-spread use. (Other compilers should work too.) |
71 |
|
|
72 |
|
<p> |
73 |
|
<li>Compile the Hello World demo program for your chosen target, and run |
74 |
|
it in the emulator. |
75 |
</ul> |
</ul> |
76 |
|
|
77 |
<p> |
<p>The Hello World demo program is included in the GXemul source |
78 |
<table border="0"><tr><td width="40"> </td><td> |
code distribution, in the <a href="../demos/hello/"><tt>demos/hello/</tt></a> |
79 |
<pre> |
subdirectory. The README files in the demo directories have several |
80 |
<font color=#f00000>/* Hello world for GXemul */ |
examples of how the demo programs can be built. |
|
|
|
|
/* Note: The cast to a signed int causes the address to be sign-extended |
|
|
correctly to 0xffffffffb00000xx when compiled in 64-bit mode */ |
|
|
</font><font color=#a0a0a0>#define PUTCHAR_ADDRESS ((signed int)0xb0000000) |
|
|
#define HALT_ADDRESS ((signed int)0xb0000010) |
|
|
|
|
|
</font><font color=#c000c0>void </font><font color=#000000><a name="printchar">printchar</a>(</font><font color=#c000c0>char </font><font color=#000000>ch) |
|
|
{ |
|
|
*((</font><font color=#c000c0>volatile unsigned char </font><font color=#000000>*) PUTCHAR_ADDRESS) = ch; |
|
|
} |
|
|
|
|
|
</font><font color=#c000c0>void </font><font color=#000000><a name="halt">halt</a>(</font><font color=#c000c0>void</font><font color=#000000>) |
|
|
{ |
|
|
*((</font><font color=#c000c0>volatile unsigned char </font><font color=#000000>*) HALT_ADDRESS) = 0; |
|
|
} |
|
|
|
|
|
</font><font color=#c000c0>void </font><font color=#000000><a name="printstr">printstr</a>(</font><font color=#c000c0>char </font><font color=#000000>*s) |
|
|
{ |
|
|
</font><font color=#c000c0>while </font><font color=#000000>(*s) |
|
|
printchar(*s++); |
|
|
} |
|
|
|
|
|
</font><font color=#c000c0>void </font><font color=#000000>f(</font><font color=#c000c0>void</font><font color=#000000>) |
|
|
{ |
|
|
printstr(</font><font color=#00c000>"Hello world\n"</font><font color=#000000>); |
|
|
halt(); |
|
|
} |
|
|
</font></pre> |
|
|
</td></tr></table> |
|
|
|
|
|
<p>(This hello world program is available here as well: |
|
|
<a href="hello_mips.c"><tt>hello_mips.c</tt></a>) |
|
|
|
|
|
<p>I recommend that you build a GCC cross compiler for the |
|
|
<b>mips64-unknown-elf</b> target, and install it. Other compilers could |
|
|
work too, but GCC is good because of its portability. Then try to compile |
|
|
and link the hello world program: |
|
|
<pre> |
|
|
$ <b>mips64-unknown-elf-gcc -O2 hello_mips.c -mips4 -mabi=64 -c</b> |
|
|
$ <b>mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f hello_mips.o -o hello_mips --oformat=elf64-bigmips</b> |
|
|
$ <b>file hello_mips</b> |
|
|
hello_mips: ELF 64-bit MSB mips-4 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped |
|
|
$ <b>gxemul -q -E testmips hello_mips</b> |
|
|
Hello world |
|
|
|
|
|
$ <b>mips64-unknown-elf-gcc -O2 hello_mips.c -c</b> |
|
|
$ <b>mips64-unknown-elf-ld -Ttext 0x80030000 -e f hello_mips.o -o hello_mips</b> |
|
|
$ <b>file hello_mips</b> |
|
|
hello_mips: ELF 32-bit MSB mips-3 executable, MIPS R3000_BE, version 1 (SYSV), statically linked, not stripped |
|
|
$ <b>gxemul -q -E testmips hello_mips</b> |
|
|
Hello world |
|
|
</pre> |
|
|
|
|
|
<p> |
|
|
As you can see above, a GCC configured for mips64-unknown-elf can produce |
|
|
both 64-bit and 32-bit binaries. If you don't want to run the entire |
|
|
Hello World program, but want to single-step through the execution to |
|
|
learn more about how MIPS programs run, then add -V to the command line: |
|
81 |
|
|
82 |
<p> |
<p>Hopefully this is enough to get you inspired. :-) |
|
<pre> |
|
|
$ <b>gxemul -V -E testmips hello_mips</b> |
|
|
.. |
|
|
GXemul> <b>r</b> |
|
|
cpu0: pc = a800000000030078 <f> |
|
|
cpu0: hi = 0000000000000000 lo = 0000000000000000 |
|
|
cpu0: zr = 0000000000000000 at = 0000000000000000 |
|
|
cpu0: v0 = 0000000000000000 v1 = 0000000000000000 |
|
|
.. |
|
|
cpu0: gp = a8000000000780c0 sp = ffffffffa0007f00 |
|
|
cpu0: fp = 0000000000000000 ra = 0000000000000000 |
|
|
GXemul> <b>s 15</b> |
|
|
<f> |
|
|
a800000000030078: 67bdfff0 daddiu sp,sp,-16 |
|
|
a80000000003007c: 3c04a800 lui a0,0xa800 |
|
|
a800000000030080: 3c010003 lui at,0x3 |
|
|
a800000000030084: 64840000 daddiu a0,a0,0 |
|
|
a800000000030088: 642100b8 daddiu at,at,184 |
|
|
a80000000003008c: 0004203c dsll32 a0,a0,0 |
|
|
a800000000030090: 0081202d daddu a0,a0,at |
|
|
a800000000030094: ffbf0000 sd ra,0(sp) [0xffffffffa0007ef0, data=0x0000000000000000] |
|
|
a800000000030098: 0c00c00a jal 0xa800000000030028 <printstr> |
|
|
a80000000003009c: 00000000 (d) nop |
|
|
<printstr("Hello world\n",0,0,0,..)> |
|
|
<printstr> |
|
|
a800000000030028: 67bdfff0 daddiu sp,sp,-16 |
|
|
a80000000003002c: ffb00000 sd s0,0(sp) [0xffffffffa0007ee0, data=0x0000000000000000] |
|
|
a800000000030030: ffbf0008 sd ra,8(sp) [0xffffffffa0007ee8, data=0xa8000000000300a0] |
|
|
a800000000030034: 90820000 lbu v0,0(a0) [0xa8000000000300b8 = $LC0, data=0x48] |
|
|
a800000000030038: 00021600 sll v0,v0,24 |
|
|
GXemul> <b>print v0</b> |
|
|
v0 = 0x0000000048000000 |
|
|
GXemul> <b>_</b> |
|
|
</pre> |
|
|
|
|
|
<p>The syntax of the single-step debugger shouldn't be too hard to grasp. |
|
|
Type "<tt>s</tt>" to single-step one instruction. For some commands (e.g. |
|
|
the single-step command), just pressing enter on a blank line will cause |
|
|
the last command to be repeated. Type "<tt>quit</tt>" to quit. |
|
|
|
|
|
<p> |
|
|
Hopefully this is enough to get you inspired. :-) |
|
83 |
|
|
84 |
|
|
85 |
|
|
108 |
characters to the controlling terminal |
characters to the controlling terminal |
109 |
and receiving keypresses. |
and receiving keypresses. |
110 |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_cons.c</tt></font> |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_cons.c</tt></font> |
111 |
|
<p>Include file: <font color="#0000f0"><tt>dev_cons.h</tt></font> |
112 |
<br>Default physical address:  <font color="#0000f0">0x10000000</font> |
<br>Default physical address:  <font color="#0000f0">0x10000000</font> |
113 |
</td> |
</td> |
114 |
<td align="left" valign="top" width="25"> </td> |
<td align="left" valign="top" width="25"> </td> |
144 |
<p>This device controls the behaviour of CPUs in an emulated |
<p>This device controls the behaviour of CPUs in an emulated |
145 |
multi-processor system. |
multi-processor system. |
146 |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_mp.c</tt></font> |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_mp.c</tt></font> |
147 |
|
<p>Include file: <font color="#0000f0"><tt>dev_mp.h</tt></font> |
148 |
<br>Default physical address:  <font color="#0000f0">0x11000000</font> |
<br>Default physical address:  <font color="#0000f0">0x11000000</font> |
149 |
</td> |
</td> |
150 |
<td></td> |
<td></td> |
178 |
<tr> |
<tr> |
179 |
<td align="left" valign="top"><tt>0x0040</tt></td> |
<td align="left" valign="top"><tt>0x0040</tt></td> |
180 |
<td align="left" valign="top">Write: <b><tt>pause_addr(addr)</tt></b>. |
<td align="left" valign="top">Write: <b><tt>pause_addr(addr)</tt></b>. |
181 |
Sets the pause address. (TODO: This is not |
Sets the pause address. (NOTE: This is not |
182 |
used anymore?)</td> |
used anymore.)</td> |
183 |
</tr> |
</tr> |
184 |
<tr> |
<tr> |
185 |
<td align="left" valign="top"><tt>0x0050</tt></td> |
<td align="left" valign="top"><tt>0x0050</tt></td> |
186 |
<td align="left" valign="top">Write: <b><tt>pause_cpu(i)</tt></b>. |
<td align="left" valign="top">Write: <b><tt>pause_cpu(i)</tt></b>. |
187 |
Stops all CPUs <i>except</i> CPU i.</td> |
Pauses all CPUs <i>except</i> CPU i.</td> |
188 |
</tr> |
</tr> |
189 |
<tr> |
<tr> |
190 |
<td align="left" valign="top"><tt>0x0060</tt></td> |
<td align="left" valign="top"><tt>0x0060</tt></td> |
191 |
<td align="left" valign="top">Write: <b><tt>unpause_cpu(i)</tt></b>. |
<td align="left" valign="top">Write: <b><tt>unpause_cpu(i)</tt></b>. |
192 |
Unpauses all CPUs <i>except</i> CPU i.</td> |
Unpauses CPU i.</td> |
193 |
</tr> |
</tr> |
194 |
<tr> |
<tr> |
195 |
<td align="left" valign="top"><tt>0x0070</tt></td> |
<td align="left" valign="top"><tt>0x0070</tt></td> |
220 |
the specified one.</td> |
the specified one.</td> |
221 |
</tr> |
</tr> |
222 |
<tr> |
<tr> |
223 |
<td align="left" valign="top">0x00c0</tt></td> |
<td align="left" valign="top"><tt>0x00c0</tt></td> |
224 |
<td align="left" valign="top">Read: <b><tt>ipi_read()</tt></b>. |
<td align="left" valign="top">Read: <b><tt>ipi_read()</tt></b>. |
225 |
Returns the next pending IPI. 0 is returned if there is no |
Returns the next pending IPI. 0 is returned if there is no |
226 |
pending IPI (so 0 shouldn't be used for valid IPIs). |
pending IPI (so 0 shouldn't be used for valid IPIs). |
229 |
Clears the IPI queue, discarding any pending IPIs.</td> |
Clears the IPI queue, discarding any pending IPIs.</td> |
230 |
</tr> |
</tr> |
231 |
<tr> |
<tr> |
232 |
<td align="left" valign="top">0x00d0</tt></td> |
<td align="left" valign="top"><tt>0x00d0</tt></td> |
233 |
<td align="left" valign="top">Read: <b><tt>ncycles()</tt></b>. |
<td align="left" valign="top">Read: <b><tt>ncycles()</tt></b>. |
234 |
Returns approximately the number of cycles executed. |
Returns approximately the number of cycles executed. |
235 |
Note: this value is not updated for every instruction, |
Note: this value is not updated for every instruction, |
249 |
<p>A simple linear framebuffer, for graphics output. |
<p>A simple linear framebuffer, for graphics output. |
250 |
640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each). |
640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each). |
251 |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_fb.c</tt></font> |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_fb.c</tt></font> |
252 |
|
<p>Include file: <font color="#0000f0"><tt>dev_fb.h</tt></font> |
253 |
<br>Default physical address:  <font color="#0000f0">0x12000000</font> |
<br>Default physical address:  <font color="#0000f0">0x12000000</font> |
254 |
</td> |
</td> |
255 |
<td></td> |
<td></td> |
276 |
<td align="left" valign="top"> |
<td align="left" valign="top"> |
277 |
<a name="expdevices_disk"><b><tt>disk</tt>:</b></a> |
<a name="expdevices_disk"><b><tt>disk</tt>:</b></a> |
278 |
<p>Disk controller, which can read from and write |
<p>Disk controller, which can read from and write |
279 |
to disk images. It does not use interrupts; read and |
to emulated IDE disks. It does not use interrupts; read and |
280 |
write operations finish instantaneously. |
write operations finish instantaneously. |
281 |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_disk.c</tt></font> |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_disk.c</tt></font> |
282 |
|
<p>Include file: <font color="#0000f0"><tt>dev_disk.h</tt></font> |
283 |
<br>Default physical address:  <font color="#0000f0">0x13000000</font> |
<br>Default physical address:  <font color="#0000f0">0x13000000</font> |
284 |
</td> |
</td> |
285 |
<td></td> |
<td></td> |
296 |
</tr> |
</tr> |
297 |
<tr> |
<tr> |
298 |
<td align="left" valign="top"><tt>0x0010</tt></td> |
<td align="left" valign="top"><tt>0x0010</tt></td> |
299 |
<td align="left" valign="top">Write: Select the SCSI ID to be used in the next |
<td align="left" valign="top">Write: Select the IDE ID to be used in the next |
300 |
read/write operation.</td> |
read/write operation.</td> |
301 |
</tr> |
</tr> |
302 |
<tr> |
<tr> |
328 |
<p>A simple ethernet controller, enough to send |
<p>A simple ethernet controller, enough to send |
329 |
and receive packets on a simulated network. |
and receive packets on a simulated network. |
330 |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_ether.c</tt></font> |
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_ether.c</tt></font> |
331 |
|
<p>Include file: <font color="#0000f0"><tt>dev_ether.h</tt></font> |
332 |
<br>Default physical address:  <font color="#0000f0">0x14000000</font> |
<br>Default physical address:  <font color="#0000f0">0x14000000</font> |
333 |
</td> |
</td> |
334 |
<td></td> |
<td></td> |
367 |
</td> |
</td> |
368 |
</tr> |
</tr> |
369 |
|
|
370 |
|
<tr height="15"> |
371 |
|
<td height="15"> </td> |
372 |
|
</tr> |
373 |
|
|
374 |
|
<tr> |
375 |
|
<td align="left" valign="top"> |
376 |
|
<a name="expdevices_rtc"><b><tt>rtc</tt>:</b></a> |
377 |
|
<p>A Real-Time Clock, used to retrieve the current time |
378 |
|
and to cause periodic interrupts. |
379 |
|
<p>Source code: <font color="#0000f0"><tt>src/devices/dev_rtc.c</tt></font> |
380 |
|
<p>Include file: <font color="#0000f0"><tt>dev_rtc.h</tt></font> |
381 |
|
<br>Default physical address:  <font color="#0000f0">0x15000000</font> |
382 |
|
</td> |
383 |
|
<td></td> |
384 |
|
<td align="left" valign="top"> |
385 |
|
<table border="0"> |
386 |
|
<tr> |
387 |
|
<td align="left" valign="top"><i><u>Offset:</u></i> </td> |
388 |
|
<td align="left" valign="top"><i><u>Effect:</u></i></td> |
389 |
|
</tr> |
390 |
|
<tr> |
391 |
|
<td align="left" valign="top"><tt>0x0000</tt></td> |
392 |
|
<td align="left" valign="top">Read or Write: Trigger a clock update (a gettimeofday() on the host).</td> |
393 |
|
</tr> |
394 |
|
<tr> |
395 |
|
<td align="left" valign="top"><tt>0x0010</tt></td> |
396 |
|
<td align="left" valign="top">Read: Seconds since 1st January 1970</td> |
397 |
|
</tr> |
398 |
|
<tr> |
399 |
|
<td align="left" valign="top"><tt>0x0020</tt></td> |
400 |
|
<td align="left" valign="top">Read: Microseconds</td> |
401 |
|
</tr> |
402 |
|
<tr> |
403 |
|
<td align="left" valign="top"><tt>0x0100</tt></td> |
404 |
|
<td align="left" valign="top">Read: Get the current |
405 |
|
timer interrupt frequency.<br>Write: Set the timer |
406 |
|
interrupt frequency. (Writing 0 disables the timer.)</td> |
407 |
|
</tr> |
408 |
|
<tr> |
409 |
|
<td align="left" valign="top"><tt>0x0110</tt></td> |
410 |
|
<td align="left" valign="top">Read or Write: Acknowledge |
411 |
|
one timer interrupt. (Note that if multiple interrupts |
412 |
|
are pending, only one is acknowledged.)</td> |
413 |
|
</tr> |
414 |
|
</table> |
415 |
|
</td> |
416 |
|
</tr> |
417 |
|
|
418 |
</table></center> |
</table></center> |
419 |
|
|
420 |
<p> |
<p> |
428 |
<tt>0xffffffff90000000</tt> too, but devices should usually be accessed in |
<tt>0xffffffff90000000</tt> too, but devices should usually be accessed in |
429 |
a non-cached manner.) |
a non-cached manner.) |
430 |
|
|
431 |
<p> (When using the PPC test machine (<tt>testppc</tt>), the addresses are |
<p>When using the Alpha, ARM, or PPC test machines, the addresses are |
432 |
<tt>0x10000000</tt>, <tt>0x11000000</tt> etc., so no need to add any |
<tt>0x10000000</tt>, <tt>0x11000000</tt> etc., so no need to add any |
433 |
virtual displacement.) |
virtual displacement. |
434 |
|
|
435 |
<p>The <b><tt>mp</tt></b>, <b><tt>disk</tt></b>, and <b><tt>ether</tt></b> |
<p>The <tt>mp</tt>, <tt>disk</tt>, and <tt>ether</tt> devices are agnostic |
436 |
devices are agnostic when it comes to word-length. For example, when |
when it comes to word-length. For example, when reading offset |
437 |
reading offset <tt>0x0000</tt> of the <b><tt>mp</tt></b> |
<tt>0x0000</tt> of the <tt>mp</tt> device, you may use any kind of read |
438 |
device, you may use any kind of read (an 8-bit read will work just as well |
(an 8-bit read will work just as well as a 64-bit read, although the value |
439 |
as a 64-bit read, although the value will be truncated to 8 bits in the |
will be truncated to 8 bits in the first case). You can <i>not</i>, |
440 |
first case). You can <i>not</i>, however, read one byte from <tt>0x0000</tt> |
however, read one byte from <tt>0x0000</tt> and one from <tt>0x0001</tt>, |
441 |
and one from <tt>0x0001</tt>, and combine the result. The read from |
and combine the result. The read from <tt>0x0001</tt> will be invalid. |
|
<tt>0x0001</tt> will be invalid. |
|
442 |
|
|
443 |
<p>The <b><tt>cons</tt></b> device should be accessed using 8-bit reads |
<p>The <tt>cons</tt> device should be accessed using 8-bit reads |
444 |
and writes. Doing a getchar() (ie reading from offset <tt>0x00</tt>) |
and writes. Doing a getchar() (ie reading from offset <tt>0x00</tt>) |
445 |
returns <tt>0</tt> if no character was available. |
returns <tt>0</tt> if no character was available. Whenever a character is |
446 |
|
available, the <tt>cons</tt> device' interrupt is asserted. When there are |
447 |
|
no more available characters, the interrupt is deasserted. (Remember that |
448 |
|
the interrupt has to be unmasked to be able to actually cause an |
449 |
|
interrupt.) |
450 |
|
|
451 |
|
<p>IPIs (inter-processor interrupts) are controlled by the <tt>mp</tt> |
452 |
|
device. Whenever an IPI is "sent" from a source to one or more target |
453 |
|
CPUs, the interrupt is asserted on the target CPUs, and the IPI number is |
454 |
|
added last in the IPI queue for each of the target CPUs. It is then up to |
455 |
|
those CPUs to individually read from offset <tt>0x00c0</tt>, to figure out |
456 |
|
what kind of IPI it was. |
457 |
|
|
|
<p>On MIPS, the <b><tt>cons</tt></b> device is hardwired to interrupt 2 |
|
|
(the lowest hardware interrupt). Whenever a character is available, the |
|
|
interrupt is asserted. When there are no more available characters, the |
|
|
interrupt is deasserted. (Remember that the interrupt has to be enabled in |
|
|
the status register of the system coprocessor.) |
|
|
|
|
|
<p>The <b><tt>ether</tt></b> device is hardwired to interrupt 3. |
|
|
|
|
|
<p>The IPIs controlled by the <b><tt>mp</tt></b> device are hardwired to |
|
|
interrupt 6. Whenever an IPI is "sent", interrupt 6 is asserted on the |
|
|
target CPU(s), and the IPI number is added last in the IPI queue for that |
|
|
CPU. It is then up to that CPU to read from offset <tt>0x00c0</tt>, to |
|
|
figure out what kind of IPI it was. |
|
|
|
|
|
<p>A simple tutorial on how to use the <tt>disk</tt> device, if not clear |
|
|
from the description above, can be found here: <a |
|
|
href="test_disk.c"><tt>test_disk.c</tt></a> |
|
458 |
|
|
459 |
|
|
460 |
|
<p>Interrupt mappings are as follows: |
461 |
|
|
462 |
|
<p><center> |
463 |
|
<table border="1"> |
464 |
|
<tr><td align="center"> |
465 |
|
<b><tt>testmips</tt></b> |
466 |
|
</td></tr> |
467 |
|
<tr><td> |
468 |
|
<table border="0"> |
469 |
|
<tr><td align="center">IRQ:</td><td> </td> |
470 |
|
<td>Used for:</td></tr> |
471 |
|
<tr><td align="center">7</td><td></td> |
472 |
|
<td>MIPS count/compare interrupt</td></tr> |
473 |
|
<tr><td align="center">6</td><td></td> |
474 |
|
<td><tt>mp</tt> (inter-processor interrupts)</td></tr> |
475 |
|
<tr><td align="center">4</td><td></td> |
476 |
|
<td><tt>rtc</tt></td></tr> |
477 |
|
<tr><td align="center">3</td><td></td> |
478 |
|
<td><tt>ether</tt></td></tr> |
479 |
|
<tr><td align="center">2</td><td></td> |
480 |
|
<td><tt>cons</tt></td></tr> |
481 |
|
</table> |
482 |
|
</td></tr> |
483 |
|
</table> |
484 |
|
</center> |
485 |
|
|
486 |
|
<p>Other machines: TODO |
487 |
|
|
488 |
|
|
489 |
|
<p><br> |
490 |
|
|
491 |
|
|
492 |
|
|
493 |
</p> |
</p> |