1 |
dpavlin |
12 |
<html><head><title>Gavare's eXperimental Emulator: Technical details</title> |
2 |
dpavlin |
8 |
<meta name="robots" content="noarchive,nofollow,noindex"></head> |
3 |
dpavlin |
4 |
<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 |
dpavlin |
44 |
<b>GXemul:</b></font> |
8 |
dpavlin |
4 |
<font color="#000000" size="6"><b>Technical details</b> |
9 |
|
|
</font></td></tr></table></td></tr></table><p> |
10 |
dpavlin |
2 |
|
11 |
|
|
<!-- |
12 |
|
|
|
13 |
dpavlin |
44 |
$Id: technical.html,v 1.77 2007/06/23 16:59:35 debug Exp $ |
14 |
dpavlin |
2 |
|
15 |
dpavlin |
34 |
Copyright (C) 2004-2007 Anders Gavare. All rights reserved. |
16 |
dpavlin |
2 |
|
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 |
|
|
|
43 |
dpavlin |
12 |
|
44 |
dpavlin |
2 |
<a href="./">Back to the index</a> |
45 |
|
|
|
46 |
|
|
<p><br> |
47 |
|
|
<h2>Technical details</h2> |
48 |
|
|
|
49 |
dpavlin |
10 |
<p>This page describes some of the internals of GXemul. |
50 |
dpavlin |
2 |
|
51 |
|
|
<p> |
52 |
|
|
<ul> |
53 |
dpavlin |
10 |
<li><a href="#speed">Speed and emulation modes</a> |
54 |
dpavlin |
2 |
<li><a href="#net">Networking</a> |
55 |
|
|
<li><a href="#devices">Emulation of hardware devices</a> |
56 |
|
|
</ul> |
57 |
|
|
|
58 |
|
|
|
59 |
|
|
|
60 |
|
|
|
61 |
|
|
|
62 |
|
|
|
63 |
|
|
<p><br> |
64 |
|
|
<a name="speed"></a> |
65 |
dpavlin |
10 |
<h3>Speed and emulation modes</h3> |
66 |
dpavlin |
2 |
|
67 |
dpavlin |
14 |
So, how fast is GXemul? There is no short answer to this. There is |
68 |
dpavlin |
10 |
especially no answer to the question <b>What is the slowdown factor?</b>, |
69 |
|
|
because the host architecture and emulated architecture can usually not be |
70 |
|
|
compared just like that. |
71 |
dpavlin |
2 |
|
72 |
dpavlin |
10 |
<p>Performance depends on several factors, including (but not limited to) |
73 |
dpavlin |
24 |
host architecture, target architecture, host clock speed, which compiler |
74 |
|
|
and compiler flags were used to build the emulator, what the workload is, |
75 |
|
|
what additional runtime flags are given to the emulator, and so on. |
76 |
dpavlin |
2 |
|
77 |
dpavlin |
24 |
<p>Devices are generally not timing-accurate: for example, if an emulated |
78 |
|
|
operating system tries to read a block from disk, from its point of view |
79 |
|
|
the read was instantaneous (no waiting). So 1 MIPS in an emulated OS might |
80 |
|
|
have taken more than one million instructions on a real machine. |
81 |
|
|
|
82 |
dpavlin |
10 |
<p>Also, if the emulator says it has executed 1 million instructions, and |
83 |
|
|
the CPU family in question was capable of scalar execution (i.e. one cycle |
84 |
|
|
per instruction), it might still have taken more than 1 million cycles on |
85 |
|
|
a real machine because of cache misses and similar micro-architectural |
86 |
|
|
penalties that are not simulated by GXemul. |
87 |
dpavlin |
2 |
|
88 |
dpavlin |
10 |
<p>Because of these issues, it is in my opinion best to measure |
89 |
|
|
performance as the actual (real-world) time it takes to perform a task |
90 |
dpavlin |
24 |
with the emulator, e.g.: |
91 |
dpavlin |
2 |
|
92 |
dpavlin |
24 |
<ul> |
93 |
|
|
<li>"How long does it take to install NetBSD onto a disk image?" |
94 |
|
|
<li>"How long does it take to compile XYZ inside NetBSD |
95 |
|
|
in the emulator?". |
96 |
|
|
</ul> |
97 |
|
|
|
98 |
dpavlin |
14 |
<p>So, how fast is it? :-) Answer: it varies. |
99 |
|
|
|
100 |
dpavlin |
2 |
|
101 |
|
|
|
102 |
|
|
|
103 |
|
|
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
<p><br> |
107 |
|
|
<a name="net"></a> |
108 |
|
|
<h3>Networking</h3> |
109 |
|
|
|
110 |
dpavlin |
42 |
<font color="#ff0000">NOTE/TODO: This section is very old.</font> |
111 |
dpavlin |
2 |
|
112 |
dpavlin |
10 |
<p>Running an entire operating system under emulation is very interesting |
113 |
|
|
in itself, but for several reasons, running a modern OS without access to |
114 |
|
|
TCP/IP networking is a bit akward. Hence, I feel the need to implement |
115 |
|
|
TCP/IP (networking) support in the emulator. |
116 |
|
|
|
117 |
dpavlin |
2 |
<p> |
118 |
|
|
As far as I have understood it, there seems to be two different ways to go: |
119 |
|
|
|
120 |
|
|
<ol> |
121 |
|
|
<li>Forward ethernet packets from the emulated ethernet controller to |
122 |
|
|
the host machine's ethernet controller, and capture incoming |
123 |
|
|
packets on the host's controller, giving them back to the |
124 |
|
|
emulated OS. Characteristics are: |
125 |
|
|
<ul> |
126 |
|
|
<li>Requires <i>direct</i> access to the host's NIC, which |
127 |
|
|
means on most platforms that the emulator cannot be |
128 |
|
|
run as a normal user! |
129 |
|
|
<li>Reduced portability, as not every host operating system |
130 |
|
|
uses the same programming interface for dealing with |
131 |
|
|
hardware ethernet controllers directly. |
132 |
|
|
<li>When run on a switched network, it might be problematic to |
133 |
|
|
connect from the emulated OS to the OS running on the |
134 |
|
|
host, as packets sent out on the host's NIC are not |
135 |
|
|
received by itself. (?) |
136 |
dpavlin |
6 |
<li>All specific networking protocols will be handled by the |
137 |
|
|
physical network. |
138 |
dpavlin |
2 |
</ul> |
139 |
|
|
<p> |
140 |
|
|
or |
141 |
|
|
<p> |
142 |
|
|
<li>Whenever the emulated ethernet controller wishes to send a packet, |
143 |
|
|
the emulator looks at the packet and creates a response. Packets |
144 |
|
|
that can have an immediate response never go outside the emulator, |
145 |
|
|
other packet types have to be converted into suitable other |
146 |
|
|
connection types (UDP, TCP, etc). Characteristics: |
147 |
|
|
<ul> |
148 |
|
|
<li>Each packet type sent out on the emulated NIC must be handled. |
149 |
|
|
This means that I have to do a lot of coding. |
150 |
|
|
(I like this, because it gives me an opportunity to |
151 |
|
|
learn about networking protocols.) |
152 |
|
|
<li>By not relying on access to the host's NIC directly, |
153 |
|
|
portability is maintained. (It would be sad if the networking |
154 |
|
|
portion of a portable emulator isn't as portable as the |
155 |
|
|
rest of the emulator.) |
156 |
|
|
<li>The emulator can be run as a normal user process, does |
157 |
|
|
not require root privilegies. |
158 |
|
|
<li>Connecting from the emulated OS to the host's OS should |
159 |
|
|
not be problematic. |
160 |
|
|
<li>The emulated OS will experience the network just as a single |
161 |
|
|
machine behind a NAT gateway/firewall would. The emulated |
162 |
|
|
OS is thus automatically protected from the outside world. |
163 |
|
|
</ul> |
164 |
|
|
</ol> |
165 |
|
|
|
166 |
dpavlin |
6 |
<p> |
167 |
|
|
Some emulators/simulators use the first approach, while others use the |
168 |
|
|
second. I think that SIMH and QEMU are examples of emulators using the |
169 |
|
|
first and second approach, respectively. |
170 |
dpavlin |
2 |
|
171 |
|
|
<p> |
172 |
|
|
Since I have choosen the second kind of implementation, I have to write |
173 |
|
|
support explicitly for any kind of network protocol that should be |
174 |
|
|
supported. As of 2004-07-09, the following has been implemented and seems |
175 |
|
|
to work under at least NetBSD/pmax and OpenBSD/pmax under DECstation 5000/200 |
176 |
|
|
emulation (-E dec -e 3max): |
177 |
|
|
|
178 |
|
|
<p> |
179 |
|
|
<ul> |
180 |
|
|
<li>ARP requests sent out from the emulated NIC are interpreted, |
181 |
|
|
and converted to ARP responses. (This is used by the emulated OS |
182 |
|
|
to find out the MAC address of the gateway.) |
183 |
|
|
<li>ICMP echo requests (that is the kind of packet produced by the |
184 |
dpavlin |
6 |
<b><tt>ping</tt></b> program) are interpreted and converted to ICMP echo |
185 |
dpavlin |
2 |
replies, <i>regardless of the IP address</i>. This means that |
186 |
|
|
running ping from within the emulated OS will <i>always</i> |
187 |
|
|
receive a response. The ping packets never leave the emulated |
188 |
|
|
environment. |
189 |
|
|
<li>UDP packets are interpreted and passed along to the outside world. |
190 |
|
|
If the emulator receives an UDP packet from the outside world, it |
191 |
|
|
is converted into an UDP packet for the emulated OS. (This is not |
192 |
|
|
implemented very well yet, but seems to be enough for nameserver |
193 |
|
|
lookups, tftp file transfers, and NFS mounts using UDP.) |
194 |
|
|
<li>TCP packets are interpreted one at a time, similar to how UDP |
195 |
|
|
packets are handled (but more state is kept for each connection). |
196 |
|
|
<font color="#ff0000">NOTE: Much of the TCP handling code is very |
197 |
|
|
ugly and hardcoded.</font> |
198 |
dpavlin |
6 |
<!-- |
199 |
dpavlin |
2 |
<li>RARP is not implemented yet. (I haven't needed it so far.) |
200 |
dpavlin |
6 |
--> |
201 |
dpavlin |
2 |
</ul> |
202 |
|
|
|
203 |
dpavlin |
6 |
<p> |
204 |
dpavlin |
2 |
The gateway machine, which is the only "other" machine that the emulated |
205 |
|
|
OS sees on its emulated network, works as a NAT-style firewall/gateway. It |
206 |
dpavlin |
6 |
usually has a fixed IPv4 address of <tt>10.0.0.254</tt>. An OS running in |
207 |
|
|
the emulator would usually have an address of the form <tt>10.x.x.x</tt>; |
208 |
|
|
a typical choice would be <tt>10.0.0.1</tt>. |
209 |
dpavlin |
2 |
|
210 |
|
|
<p> |
211 |
dpavlin |
6 |
Inside emulated NetBSD/pmax or OpenBSD/pmax, running the following |
212 |
|
|
commands should configure the emulated NIC: |
213 |
dpavlin |
2 |
<pre> |
214 |
|
|
# <b>ifconfig le0 10.0.0.1</b> |
215 |
|
|
# <b>route add default 10.0.0.254</b> |
216 |
|
|
add net default: gateway 10.0.0.254 |
217 |
|
|
</pre> |
218 |
|
|
|
219 |
dpavlin |
6 |
<p> |
220 |
dpavlin |
2 |
If you want nameserver lookups to work, you need a valid /etc/resolv.conf |
221 |
|
|
as well: |
222 |
|
|
<pre> |
223 |
|
|
# <b>echo nameserver 129.16.1.3 > /etc/resolv.conf</b> |
224 |
|
|
</pre> |
225 |
dpavlin |
6 |
(But replace <tt>129.16.1.3</tt> with the actual real-world IP address of |
226 |
|
|
your nearest nameserver.) |
227 |
|
|
|
228 |
dpavlin |
2 |
<p> |
229 |
|
|
Now, host lookups should work: |
230 |
|
|
<pre> |
231 |
|
|
# <b>host -a www.netbsd.org</b> |
232 |
|
|
Trying null domain |
233 |
|
|
rcode = 0 (Success), ancount=2 |
234 |
|
|
The following answer is not authoritative: |
235 |
|
|
The following answer is not verified as authentic by the server: |
236 |
|
|
www.netbsd.org 86400 IN AAAA 2001:4f8:4:7:290:27ff:feab:19a7 |
237 |
|
|
www.netbsd.org 86400 IN A 204.152.184.116 |
238 |
|
|
For authoritative answers, see: |
239 |
|
|
netbsd.org 83627 IN NS uucp-gw-2.pa.dec.com |
240 |
|
|
netbsd.org 83627 IN NS ns.netbsd.org |
241 |
|
|
netbsd.org 83627 IN NS adns1.berkeley.edu |
242 |
|
|
netbsd.org 83627 IN NS adns2.berkeley.edu |
243 |
|
|
netbsd.org 83627 IN NS uucp-gw-1.pa.dec.com |
244 |
|
|
Additional information: |
245 |
|
|
ns.netbsd.org 83627 IN A 204.152.184.164 |
246 |
|
|
uucp-gw-1.pa.dec.com 172799 IN A 204.123.2.18 |
247 |
|
|
uucp-gw-2.pa.dec.com 172799 IN A 204.123.2.19 |
248 |
|
|
</pre> |
249 |
|
|
|
250 |
dpavlin |
6 |
<p> |
251 |
|
|
At this point, UDP and TCP should (mostly) work. |
252 |
dpavlin |
2 |
|
253 |
dpavlin |
6 |
<p> |
254 |
|
|
Here is an example of how to configure a server machine and an emulated |
255 |
|
|
client machine for sharing files via NFS: |
256 |
dpavlin |
2 |
|
257 |
dpavlin |
6 |
<p> |
258 |
|
|
(This is very useful if you want to share entire directory trees |
259 |
|
|
between the emulated environment and another machine. These instruction |
260 |
|
|
will work for FreeBSD, if you are running something else, use your |
261 |
|
|
imagination to modify them.) |
262 |
dpavlin |
2 |
|
263 |
|
|
<p> |
264 |
|
|
<ul> |
265 |
|
|
<li>On the server, add a line to your /etc/exports file, exporting |
266 |
|
|
the files you wish to use in the emulator:<pre> |
267 |
|
|
<b>/tftpboot -mapall=nobody -ro 123.11.22.33</b> |
268 |
|
|
</pre> |
269 |
|
|
where 123.11.22.33 is the IP address of the machine running the |
270 |
|
|
emulator process, as seen from the outside world. |
271 |
|
|
<p> |
272 |
|
|
<li>Then start up the programs needed to serve NFS via UDP. Note the |
273 |
|
|
-n argument to mountd. This is needed to tell mountd to accept |
274 |
|
|
connections from unprivileged ports (because the emulator does |
275 |
|
|
not need to run as root).<pre> |
276 |
|
|
# <b>portmap</b> |
277 |
|
|
# <b>nfsd -u</b> <--- u for UDP |
278 |
|
|
# <b>mountd -n</b> |
279 |
|
|
</pre> |
280 |
|
|
<li>In the guest OS in the emulator, once you have ethernet and IPv4 |
281 |
|
|
configured so that you can use UDP, mounting the filesystem |
282 |
|
|
should now be possible: (this example is for NetBSD/pmax |
283 |
|
|
or OpenBSD/pmax)<pre> |
284 |
|
|
# <b>mount -o ro,-r=1024,-w=1024,-U,-3 my.server.com:/tftpboot /mnt</b> |
285 |
|
|
or |
286 |
|
|
# <b>mount my.server.com:/tftpboot /mnt</b> |
287 |
|
|
</pre> |
288 |
|
|
If you don't supply the read and write sizes, there is a risk |
289 |
|
|
that the default values are too large. The emulator currently |
290 |
|
|
does not handle fragmentation/defragmentation of <i>outgoing</i> |
291 |
|
|
packets, so going above the ethernet frame size (1518) is a very |
292 |
|
|
bad idea. Incoming packets (reading from nfs) should work, though, |
293 |
|
|
for example during an NFS install. |
294 |
|
|
</ul> |
295 |
|
|
|
296 |
|
|
The example above uses read-only mounts. That is enough for things like |
297 |
|
|
letting NetBSD/pmax or OpenBSD/pmax install via NFS, without the need for |
298 |
|
|
a CDROM ISO image. You can use a read-write mount if you wish to share |
299 |
|
|
files in both directions, but then you should be aware of the |
300 |
|
|
fragmentation issue mentioned above. |
301 |
|
|
|
302 |
|
|
|
303 |
|
|
|
304 |
|
|
|
305 |
|
|
|
306 |
dpavlin |
10 |
|
307 |
|
|
|
308 |
dpavlin |
2 |
<p><br> |
309 |
|
|
<a name="devices"></a> |
310 |
|
|
<h3>Emulation of hardware devices</h3> |
311 |
|
|
|
312 |
dpavlin |
42 |
Each file called <tt>dev_*.c</tt> in the |
313 |
|
|
<a href="../src/devices/"><tt>src/devices/</tt></a> directory is |
314 |
dpavlin |
20 |
responsible for one hardware device. These are used from |
315 |
dpavlin |
42 |
<a href="../src/machines/"><tt>src/machines</tt></a><tt>/machine_*.c</tt>, |
316 |
|
|
when initializing which hardware a particular machine model will be using, |
317 |
|
|
or when adding devices to a machine using the <tt>device()</tt> command in |
318 |
|
|
<a href="configfiles.html">configuration files</a>. |
319 |
dpavlin |
2 |
|
320 |
dpavlin |
10 |
<p>(I'll be using the name "<tt>foo</tt>" as the name of the device in all |
321 |
|
|
these examples. This is pseudo code, it might need some modification to |
322 |
dpavlin |
2 |
actually compile and run.) |
323 |
|
|
|
324 |
dpavlin |
10 |
<p>Each device should have the following: |
325 |
dpavlin |
2 |
|
326 |
|
|
<p> |
327 |
|
|
<ul> |
328 |
dpavlin |
10 |
<li>A <tt>devinit</tt> function in <tt>src/devices/dev_foo.c</tt>. It |
329 |
|
|
would typically look something like this: |
330 |
dpavlin |
2 |
<pre> |
331 |
dpavlin |
22 |
DEVINIT(foo) |
332 |
dpavlin |
2 |
{ |
333 |
dpavlin |
42 |
struct foo_data *d; |
334 |
dpavlin |
2 |
|
335 |
dpavlin |
42 |
CHECK_ALLOCATION(d = malloc(sizeof(struct foo_data))); |
336 |
dpavlin |
22 |
memset(d, 0, sizeof(struct foo_data)); |
337 |
dpavlin |
2 |
|
338 |
|
|
/* |
339 |
|
|
* Set up stuff here, for example fill d with useful |
340 |
dpavlin |
42 |
* data. devinit contains settings like address, irq path, |
341 |
dpavlin |
2 |
* and other things. |
342 |
|
|
* |
343 |
|
|
* ... |
344 |
|
|
*/ |
345 |
dpavlin |
42 |
|
346 |
|
|
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); |
347 |
dpavlin |
2 |
|
348 |
|
|
memory_device_register(devinit->machine->memory, devinit->name, |
349 |
|
|
devinit->addr, DEV_FOO_LENGTH, |
350 |
dpavlin |
20 |
dev_foo_access, (void *)d, DM_DEFAULT, NULL); |
351 |
dpavlin |
2 |
|
352 |
|
|
/* This should only be here if the device |
353 |
|
|
has a tick function: */ |
354 |
|
|
machine_add_tickfunction(machine, dev_foo_tick, d, |
355 |
|
|
FOO_TICKSHIFT); |
356 |
|
|
|
357 |
|
|
/* Return 1 if the device was successfully added. */ |
358 |
|
|
return 1; |
359 |
|
|
} |
360 |
|
|
</pre><br> |
361 |
|
|
|
362 |
dpavlin |
22 |
<p><tt>DEVINIT(foo)</tt> is defined as <tt>int devinit_foo(struct devinit *devinit)</tt>, |
363 |
|
|
and the <tt>devinit</tt> argument contains everything that the device driver's |
364 |
|
|
initialization function needs. |
365 |
|
|
|
366 |
|
|
<p> |
367 |
dpavlin |
10 |
<li>At the top of <tt>dev_foo.c</tt>, the <tt>foo_data</tt> struct |
368 |
|
|
should be defined. |
369 |
dpavlin |
2 |
<pre> |
370 |
|
|
struct foo_data { |
371 |
dpavlin |
42 |
struct interrupt irq; |
372 |
dpavlin |
2 |
/* ... */ |
373 |
|
|
} |
374 |
|
|
</pre><br> |
375 |
dpavlin |
42 |
(There is an exception to this rule; some legacy code and other |
376 |
|
|
ugly hacks have their device structs defined in |
377 |
|
|
<tt>src/include/devices.h</tt> instead of <tt>dev_foo.c</tt>. |
378 |
|
|
New code should not add stuff to <tt>devices.h</tt>.) |
379 |
dpavlin |
20 |
<p> |
380 |
dpavlin |
10 |
<li>If <tt>foo</tt> has a tick function (that is, something that needs to be |
381 |
|
|
run at regular intervals) then <tt>FOO_TICKSHIFT</tt> and a tick |
382 |
|
|
function need to be defined as well: |
383 |
dpavlin |
2 |
<pre> |
384 |
dpavlin |
20 |
#define FOO_TICKSHIFT 14 |
385 |
dpavlin |
2 |
|
386 |
dpavlin |
42 |
DEVICE_TICK(foo) |
387 |
dpavlin |
2 |
{ |
388 |
dpavlin |
42 |
struct foo_data *d = extra; |
389 |
dpavlin |
2 |
|
390 |
|
|
if (.....) |
391 |
dpavlin |
42 |
INTERRUPT_ASSERT(d->irq); |
392 |
dpavlin |
2 |
else |
393 |
dpavlin |
42 |
INTERRUPT_DEASSERT(d->irq); |
394 |
dpavlin |
2 |
} |
395 |
|
|
</pre><br> |
396 |
|
|
|
397 |
dpavlin |
20 |
<li>Does this device belong to a standard bus? |
398 |
|
|
<ul> |
399 |
|
|
<li>If this device should be detectable as a PCI device, then |
400 |
|
|
glue code should be added to |
401 |
|
|
<tt>src/devices/bus_pci.c</tt>. |
402 |
|
|
<li>If this is a legacy ISA device which should be usable by |
403 |
|
|
any machine which has an ISA bus, then the device should |
404 |
|
|
be added to <tt>src/devices/bus_isa.c</tt>. |
405 |
|
|
</ul> |
406 |
|
|
<p> |
407 |
dpavlin |
2 |
<li>And last but not least, the device should have an access function. |
408 |
|
|
The access function is called whenever there is a load or store |
409 |
dpavlin |
22 |
to an address which is in the device' memory mapped region. To |
410 |
|
|
simplify things a little, a macro <tt>DEVICE_ACCESS(x)</tt> |
411 |
|
|
is expanded into<pre> |
412 |
|
|
int dev_x_access(struct cpu *cpu, struct memory *mem, |
413 |
dpavlin |
2 |
uint64_t relative_addr, unsigned char *data, size_t len, |
414 |
|
|
int writeflag, void *extra) |
415 |
dpavlin |
22 |
</pre> The access function can look like this: |
416 |
|
|
<pre> |
417 |
|
|
DEVICE_ACCESS(foo) |
418 |
dpavlin |
2 |
{ |
419 |
|
|
struct foo_data *d = extra; |
420 |
|
|
uint64_t idata = 0, odata = 0; |
421 |
|
|
|
422 |
dpavlin |
42 |
if (writeflag == MEM_WRITE) |
423 |
|
|
idata = memory_readmax64(cpu, data, len); |
424 |
|
|
|
425 |
dpavlin |
2 |
switch (relative_addr) { |
426 |
dpavlin |
42 |
|
427 |
|
|
/* Handle accesses to individual addresses within |
428 |
|
|
the device here. */ |
429 |
|
|
|
430 |
|
|
/* ... */ |
431 |
|
|
|
432 |
dpavlin |
2 |
} |
433 |
|
|
|
434 |
|
|
if (writeflag == MEM_READ) |
435 |
|
|
memory_writemax64(cpu, data, len, odata); |
436 |
|
|
|
437 |
|
|
/* Perhaps interrupts need to be asserted or |
438 |
|
|
deasserted: */ |
439 |
|
|
dev_foo_tick(cpu, extra); |
440 |
|
|
|
441 |
|
|
/* Return successfully. */ |
442 |
|
|
return 1; |
443 |
|
|
} |
444 |
|
|
</pre><br> |
445 |
|
|
</ul> |
446 |
|
|
|
447 |
|
|
<p> |
448 |
dpavlin |
6 |
The return value of the access function has until 2004-07-02 been a |
449 |
dpavlin |
2 |
true/false value; 1 for success, or 0 for device access failure. A device |
450 |
|
|
access failure (on MIPS) will result in a DBE exception. |
451 |
|
|
|
452 |
|
|
<p> |
453 |
|
|
Some devices are converted to support arbitrary memory latency |
454 |
|
|
values. The return value is the number of cycles that the read or |
455 |
|
|
write access took. A value of 1 means one cycle, a value of 10 means 10 |
456 |
|
|
cycles. Negative values are used for device access failures, and the |
457 |
|
|
absolute value of the value is then the number of cycles; a value of -5 |
458 |
|
|
means that the access failed, and took 5 cycles. |
459 |
|
|
|
460 |
|
|
<p> |
461 |
|
|
To be compatible with pre-20040702 devices, a return value of 0 is treated |
462 |
dpavlin |
6 |
by the caller (in <tt>src/memory_rw.c</tt>) as a value of -1. |
463 |
dpavlin |
2 |
|
464 |
|
|
|
465 |
|
|
|
466 |
|
|
|
467 |
|
|
|
468 |
|
|
|
469 |
|
|
</body> |
470 |
|
|
</html> |