You might want to use the emulator to develop programs on your own, not just run already existing operating system kernels such as NetBSD. To get started, I recommend that you do two things:
The Hello World demo program is included in the GXemul source code distribution, in the demos/hello/ subdirectory. The README files in the demo directories have several examples of how the demo programs can be built.
Once you have compiled the Hello World program into a binary, hello_mips, start it like this:
gxemul -E testmips hello_mips
Then you can experiment using the commands further up on this page.
If you start the emulator in the paused state, or if you press CTRL-C during normal execution, you will end up with a GXemul> prompt.
Hopefully this is enough to get you inspired. :-)
The emulator has several modes where it doesn't emulate any real machine. It can either run in "bare" mode, where no devices are included by default (just the CPU), or in a "test" mode where some simple devices are emulated. This can be used when developing e.g. operating systems, as a complement to targeting real machines.
The name of the test machine modes are testmips, testarm, etc. Run gxemul -H for an up-to-date list.
Here are some examples of guest OSes that use or (have used) the test machine modes:
HelenOS:
Old versions of HelenOS can run in GXemul's
testarm and testmips machine modes.
ftp http://www.helenos.org/releases/HelenOS-0.5.0-arm32-GXemul.boot gxemul -X -E testarm HelenOS-0.5.0-arm32-GXemul.boot ftp http://www.helenos.org/releases/HelenOS-0.5.0-mips32-GXemul.boot gxemul -X -E testmips HelenOS-0.5.0-mips32-GXemul.boot
The test machines (testmips, testarm, etc) have the following experimental devices:
ram:
The first 256 MB of RAM.
|
|
|||||||||||||||||||||||||||||||
cons:
A simple console device, for writing characters to the controlling terminal and receiving keypresses. Source code: src/devices/dev_cons.c Include file: dev_cons.h
|
|
|||||||||||||||||||||||||||||||
mp:
This device controls the behaviour of CPUs in an emulated multi-processor system. Source code: src/devices/dev_mp.c Include file: dev_mp.h
|
|
|||||||||||||||||||||||||||||||
fb:
A simple linear framebuffer, for graphics output. Initial resolution is 640 x 480 pixels, with 3 bytes per pixel (red, green, blue, 8 bits each). Source code: src/devices/dev_fb.c Include file: dev_fb.h
|
|
|||||||||||||||||||||||||||||||
disk:
Disk controller, which can read from and write to emulated IDE disks. It does not use interrupts; read and write operations finish instantaneously. Source code: src/devices/dev_disk.c Include file: dev_disk.h
|
|
|||||||||||||||||||||||||||||||
ether:
A simple ethernet controller, enough to send and receive packets on a simulated network. Source code: src/devices/dev_ether.c Include file: dev_ether.h
|
|
|||||||||||||||||||||||||||||||
rtc:
A Real-Time Clock, used to retrieve the current time and to cause periodic interrupts. Source code: src/devices/dev_rtc.c Include file: dev_rtc.h
|
|
|||||||||||||||||||||||||||||||
irqc:
An Interrupt Controller. (Note: Not used for the MIPS test machine.) Source code: src/devices/dev_irqc.c Include file: dev_irqc.h
|
|
(*) Note: If the emulated architecture has the capability to write 64-bit words atomically, then writing to offset 0x0000 of the disk device should be enough to set the offset. For 32-bit architectures, the lowest 32 bits of the disk offset should first be written to the register at offset 0x0000, and the top 32 bits should then be written to the register at offset 0x0008.
The include files for the test machine devices are found in src/include/testmachine/.
While these devices may resemble real-world hardware, they are intentionally made simpler to use. (An exception is the framebuffer; some machines actually have simple linear framebuffers like this.)
If the physical address is 0x10000000, then for MIPS that means that it can be accessed at virtual address 0xffffffffb0000000. (Using virtual address 0xffffffff90000000 may work in the emulator, but should be avoided, since devices should in general be accessed in a non-cached manner.)
When using the ARM or PPC test machines, the addresses are 0x10000000, 0x11000000 etc., so no need to add any virtual displacement.
The mp, disk, and ether devices are agnostic when it comes to word-length. For example, when reading offset 0x0000 of the mp device, you may use any kind of read (an 8-bit read will work just as well as a 64-bit read, although the value will be truncated to 8 bits in the first case). You can not, however, read one byte from 0x0000 and one from 0x0001, and combine the result. The read from 0x0001 will be invalid.
The cons device should be accessed using 8-bit reads and writes. Doing a getchar() (ie reading from offset 0x00) returns 0 if no character was available. Whenever a character is available, the cons device' interrupt is asserted. When there are no more available characters, the interrupt is deasserted. (Remember that the interrupt has to be unmasked to be able to actually cause an interrupt.)
IPIs (inter-processor interrupts) are controlled by the mp device. Whenever an IPI is "sent" from a source to one or more target CPUs, the interrupt is asserted on the target CPUs, and the IPI number is added last in the IPI queue for each of the target CPUs. It is then up to those CPUs to individually read from offset 0x00c0, to figure out what kind of IPI it was.
Interrupt mappings are as follows:
testmips (as native MIPS interrupts) | ||||||||||||||||||
|
testarm and others (via the irqc device) | |||||||||||||||
|