1 |
330 |
jeremybenn |
This is a loose collection of notes for people hacking on simulators.
|
2 |
|
|
If this document gets big enough it can be prettied up then.
|
3 |
|
|
|
4 |
|
|
Contents
|
5 |
|
|
|
6 |
|
|
- The "common" directory
|
7 |
|
|
- Common Makefile Support
|
8 |
|
|
- TAGS support
|
9 |
|
|
- Generating "configure" files
|
10 |
|
|
- tconfig.in
|
11 |
|
|
- C Language Assumptions
|
12 |
|
|
- "dump" commands under gdb
|
13 |
|
|
|
14 |
|
|
The "common" directory
|
15 |
|
|
======================
|
16 |
|
|
|
17 |
|
|
The common directory contains:
|
18 |
|
|
|
19 |
|
|
- common documentation files (e.g. run.1, and maybe in time .texi files)
|
20 |
|
|
- common source files (e.g. run.c)
|
21 |
|
|
- common Makefile fragment and configury (e.g. Make-common.in, aclocal.m4).
|
22 |
|
|
|
23 |
|
|
In addition "common" contains portions of the system call support
|
24 |
|
|
(e.g. callback.c, nltvals.def).
|
25 |
|
|
|
26 |
|
|
Even though no files are built in this directory, it is still configured
|
27 |
|
|
so support for regenerating nltvals.def is present.
|
28 |
|
|
|
29 |
|
|
Common Makefile Support
|
30 |
|
|
=======================
|
31 |
|
|
|
32 |
|
|
A common configuration framework is available for simulators that want
|
33 |
|
|
to use it. The common framework exists to remove a lot of duplication
|
34 |
|
|
in configure.in and Makefile.in, and it also provides a foundation for
|
35 |
|
|
enhancing the simulators uniformly (e.g. the more they share in common
|
36 |
|
|
the easier a feature added to one is added to all).
|
37 |
|
|
|
38 |
|
|
The configure.in of a simulator using the common framework should look like:
|
39 |
|
|
|
40 |
|
|
--- snip ---
|
41 |
|
|
dnl Process this file with autoconf to produce a configure script.
|
42 |
|
|
sinclude(../common/aclocal.m4)
|
43 |
|
|
AC_PREREQ(2.5)dnl
|
44 |
|
|
AC_INIT(Makefile.in)
|
45 |
|
|
|
46 |
|
|
SIM_AC_COMMON
|
47 |
|
|
|
48 |
|
|
... target specific additions ...
|
49 |
|
|
|
50 |
|
|
SIM_AC_OUTPUT
|
51 |
|
|
--- snip ---
|
52 |
|
|
|
53 |
|
|
SIM_AC_COMMON:
|
54 |
|
|
|
55 |
|
|
- invokes the autoconf macros most often used by the simulators
|
56 |
|
|
- defines --enable/--with options usable by all simulators
|
57 |
|
|
- initializes sim_link_files/sim_link_links as the set of symbolic links
|
58 |
|
|
to set up
|
59 |
|
|
|
60 |
|
|
SIM_AC_OUTPUT:
|
61 |
|
|
|
62 |
|
|
- creates the symbolic links defined in sim_link_{files,links}
|
63 |
|
|
- creates config.h
|
64 |
|
|
- creates the Makefile
|
65 |
|
|
|
66 |
|
|
The Makefile.in of a simulator using the common framework should look like:
|
67 |
|
|
|
68 |
|
|
--- snip ---
|
69 |
|
|
# Makefile for blah ...
|
70 |
|
|
# Copyright blah ...
|
71 |
|
|
|
72 |
|
|
## COMMON_PRE_CONFIG_FRAG
|
73 |
|
|
|
74 |
|
|
# These variables are given default values in COMMON_PRE_CONFIG_FRAG.
|
75 |
|
|
# We override the ones we need to here.
|
76 |
|
|
# Not all of these need to be mentioned, only the necessary ones.
|
77 |
|
|
# In fact it is better to *not* mention ones if the value is the default.
|
78 |
|
|
|
79 |
|
|
# List of object files, less common parts.
|
80 |
|
|
SIM_OBJS =
|
81 |
|
|
# List of extra dependencies.
|
82 |
|
|
# Generally this consists of simulator specific files included by sim-main.h.
|
83 |
|
|
SIM_EXTRA_DEPS =
|
84 |
|
|
# List of flags to always pass to $(CC).
|
85 |
|
|
SIM_EXTRA_CFLAGS =
|
86 |
|
|
# List of extra libraries to link with.
|
87 |
|
|
SIM_EXTRA_LIBS =
|
88 |
|
|
# List of extra program dependencies.
|
89 |
|
|
SIM_EXTRA_LIBDEPS =
|
90 |
|
|
# List of main object files for `run'.
|
91 |
|
|
SIM_RUN_OBJS = run.o
|
92 |
|
|
# Dependency of `all' to build any extra files.
|
93 |
|
|
SIM_EXTRA_ALL =
|
94 |
|
|
# Dependency of `install' to install any extra files.
|
95 |
|
|
SIM_EXTRA_INSTALL =
|
96 |
|
|
# Dependency of `clean' to clean any extra files.
|
97 |
|
|
SIM_EXTRA_CLEAN =
|
98 |
|
|
|
99 |
|
|
## COMMON_POST_CONFIG_FRAG
|
100 |
|
|
|
101 |
|
|
# Rules need to build $(SIM_OBJS), plus whatever else the target wants.
|
102 |
|
|
|
103 |
|
|
... target specific rules ...
|
104 |
|
|
--- snip ---
|
105 |
|
|
|
106 |
|
|
COMMON_{PRE,POST}_CONFIG_FRAG are markers for SIM_AC_OUTPUT to tell it
|
107 |
|
|
where to insert the two pieces of common/Make-common.in.
|
108 |
|
|
The resulting Makefile is created by doing autoconf substitions on
|
109 |
|
|
both the target's Makefile.in and Make-common.in, and inserting
|
110 |
|
|
the two pieces of Make-common.in into the target's Makefile.in at
|
111 |
|
|
COMMON_{PRE,POST}_CONFIG_FRAG.
|
112 |
|
|
|
113 |
|
|
Note that SIM_EXTRA_{INSTALL,CLEAN} could be removed and "::" targets
|
114 |
|
|
could be used instead. However, it's not clear yet whether "::" targets
|
115 |
|
|
are portable enough.
|
116 |
|
|
|
117 |
|
|
TAGS support
|
118 |
|
|
============
|
119 |
|
|
|
120 |
|
|
Many files generate program symbols at compile time.
|
121 |
|
|
Such symbols can't be found with grep nor do they normally appear in
|
122 |
|
|
the TAGS file. To get around this, source files can add the comment
|
123 |
|
|
|
124 |
|
|
/* TAGS: foo1 foo2 */
|
125 |
|
|
|
126 |
|
|
where foo1, foo2 are program symbols. Symbols found in such comments
|
127 |
|
|
are greppable and appear in the TAGS file.
|
128 |
|
|
|
129 |
|
|
Generating "configure" files
|
130 |
|
|
============================
|
131 |
|
|
|
132 |
|
|
For targets using the common framework, "configure" can be generated
|
133 |
|
|
by running `autoconf'.
|
134 |
|
|
|
135 |
|
|
To regenerate the configure files for all targets using the common framework:
|
136 |
|
|
|
137 |
|
|
$ cd devo/sim
|
138 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoconf-common
|
139 |
|
|
|
140 |
|
|
To add a change-log entry to the ChangeLog file for each updated
|
141 |
|
|
directory (WARNING - check the modified new-ChangeLog files before
|
142 |
|
|
renaming):
|
143 |
|
|
|
144 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoconf-changelog
|
145 |
|
|
$ more */new-ChangeLog
|
146 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoconf-install
|
147 |
|
|
|
148 |
|
|
In a similar vein, both the configure and config.in files can be
|
149 |
|
|
updated using the sequence:
|
150 |
|
|
|
151 |
|
|
$ cd devo/sim
|
152 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoheader-common
|
153 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoheader-changelog
|
154 |
|
|
$ more */new-ChangeLog
|
155 |
|
|
$ make -f Makefile.in SHELL=/bin/sh autoheader-install
|
156 |
|
|
|
157 |
|
|
To add the entries to an alternative ChangeLog file, use:
|
158 |
|
|
|
159 |
|
|
$ make ChangeLog=MyChangeLog ....
|
160 |
|
|
|
161 |
|
|
|
162 |
|
|
tconfig.in
|
163 |
|
|
==========
|
164 |
|
|
|
165 |
|
|
File tconfig.in defines one or more target configuration macros
|
166 |
|
|
(e.g. a tm.h file). There are very few that need defining.
|
167 |
|
|
For a list of all of them, see common/tconfig.in.
|
168 |
|
|
It contains them all, commented out.
|
169 |
|
|
The intent is that a new port can just copy this file and
|
170 |
|
|
define the ones it needs.
|
171 |
|
|
|
172 |
|
|
C Language Assumptions
|
173 |
|
|
======================
|
174 |
|
|
|
175 |
|
|
The programmer may assume that the simulator is being built using an
|
176 |
|
|
ANSI C compiler that supports a 64 bit data type. Consequently:
|
177 |
|
|
|
178 |
|
|
o prototypes can be used (although using
|
179 |
|
|
PARAMS() and K&R declarations wouldn't
|
180 |
|
|
go astray).
|
181 |
|
|
|
182 |
|
|
o If sim-types.h is included, the two
|
183 |
|
|
types signed64 and unsigned64 are
|
184 |
|
|
available.
|
185 |
|
|
|
186 |
|
|
o The type `unsigned' is valid.
|
187 |
|
|
|
188 |
|
|
However, the user should be aware of the following:
|
189 |
|
|
|
190 |
|
|
o GCC's `LL' is NOT acceptable.
|
191 |
|
|
Microsoft-C doesn't reconize it.
|
192 |
|
|
|
193 |
|
|
o MSC's `i64' is NOT acceptable.
|
194 |
|
|
GCC doesn't reconize it.
|
195 |
|
|
|
196 |
|
|
o GCC's `long long' MSC's `_int64' can
|
197 |
|
|
NOT be used to define 64 bit integer data
|
198 |
|
|
types.
|
199 |
|
|
|
200 |
|
|
o An empty array (eg int a[0]) is not valid.
|
201 |
|
|
|
202 |
|
|
When building with GCC it is effectivly a requirement that
|
203 |
|
|
--enable-build-warnings=,-Werror be specified during configuration.
|
204 |
|
|
|
205 |
|
|
"dump" commands under gdb
|
206 |
|
|
=========================
|
207 |
|
|
|
208 |
|
|
gdbinit.in contains the following
|
209 |
|
|
|
210 |
|
|
define dump
|
211 |
|
|
set sim_debug_dump ()
|
212 |
|
|
end
|
213 |
|
|
|
214 |
|
|
Simulators that define the sim_debug_dump function can then have their
|
215 |
|
|
internal state pretty printed from gdb.
|
216 |
|
|
|
217 |
|
|
FIXME: This can obviously be made more elaborate. As needed it will be.
|
218 |
|
|
|
219 |
|
|
Rebuilding nltvals.def
|
220 |
|
|
======================
|
221 |
|
|
|
222 |
|
|
Checkout a copy of the SIM and LIBGLOSS modules (Unless you've already
|
223 |
|
|
got one to hand):
|
224 |
|
|
|
225 |
|
|
$ mkdir /tmp/$$
|
226 |
|
|
$ cd /tmp/$$
|
227 |
|
|
$ cvs checkout sim-no-testsuite libgloss-no-testsuite newlib-no-testsuite
|
228 |
|
|
|
229 |
|
|
Configure things for an arbitrary simulator target (I've d10v for
|
230 |
|
|
convenience):
|
231 |
|
|
|
232 |
|
|
$ mkdir /tmp/$$/build
|
233 |
|
|
$ cd /tmp/$$/build
|
234 |
|
|
$ /tmp/$$/devo/configure --target=d10v-elf
|
235 |
|
|
|
236 |
|
|
In the sim/common directory rebuild the headers:
|
237 |
|
|
|
238 |
|
|
$ cd sim/common
|
239 |
|
|
$ make headers
|
240 |
|
|
|
241 |
|
|
To add a new target:
|
242 |
|
|
|
243 |
|
|
devo/sim/common/gennltvals.sh
|
244 |
|
|
|
245 |
|
|
Add your new processor target (you'll need to grub
|
246 |
|
|
around to find where your syscall.h lives).
|
247 |
|
|
|
248 |
|
|
devo/sim//Makefile.in
|
249 |
|
|
|
250 |
|
|
Add the definition:
|
251 |
|
|
|
252 |
|
|
``NL_TARGET = -DNL_TARGET_d10v''
|
253 |
|
|
|
254 |
|
|
just before the line COMMON_POST_CONFIG_FRAG.
|
255 |
|
|
|
256 |
|
|
devo/sim//*.[ch]
|
257 |
|
|
|
258 |
|
|
Include targ-vals.h instead of syscall.h.
|
259 |
|
|
|
260 |
|
|
Tracing
|
261 |
|
|
=======
|
262 |
|
|
|
263 |
|
|
For ports based on CGEN, tracing instrumentation should largely be for free,
|
264 |
|
|
so we will cover the basic non-CGEN setup here. The assumption is that your
|
265 |
|
|
target is using the common autoconf macros and so the build system already
|
266 |
|
|
includes the sim-trace configure flag.
|
267 |
|
|
|
268 |
|
|
The full tracing API is covered in sim-trace.h, so this section is an overview.
|
269 |
|
|
|
270 |
|
|
Before calling any trace function, you should make a call to the trace_prefix()
|
271 |
|
|
function. This is usually done in the main sim_engine_run() loop before
|
272 |
|
|
simulating the next instruction. You should make this call before every
|
273 |
|
|
simulated insn. You can probably copy & paste this:
|
274 |
|
|
if (TRACE_ANY_P (cpu))
|
275 |
|
|
trace_prefix (sd, cpu, NULL_CIA, oldpc, TRACE_LINENUM_P (cpu), NULL, 0, "");
|
276 |
|
|
|
277 |
|
|
You will then need to instrument your simulator code with calls to the
|
278 |
|
|
trace_generic() function with the appropriate trace index. Typically, this
|
279 |
|
|
will take a form similar to the above snippet. So to trace instructions, you
|
280 |
|
|
would use something like:
|
281 |
|
|
if (TRACE_INSN_P (cpu))
|
282 |
|
|
trace_generic (sd, cpu, TRACE_INSN_IDX, "NOP;");
|
283 |
|
|
|
284 |
|
|
The exact output format is up to you. See the trace index enum in sim-trace.h
|
285 |
|
|
to see the different tracing info available.
|
286 |
|
|
|
287 |
|
|
To utilize the tracing features at runtime, simply use the --trace-xxx flags.
|
288 |
|
|
run --trace-insn ./some-program
|
289 |
|
|
|
290 |
|
|
Profiling
|
291 |
|
|
=========
|
292 |
|
|
|
293 |
|
|
Similar to the tracing section, this is merely an overview for non-CGEN based
|
294 |
|
|
ports. The full API may be found in sim-profile.h. Its API is also similar
|
295 |
|
|
to the tracing API.
|
296 |
|
|
|
297 |
|
|
Note that unlike the tracing command line options, in addition to the profile
|
298 |
|
|
flags, you have to use the --verbose option to view the summary report after
|
299 |
|
|
execution. Tracing output is displayed on the fly, but the profile output is
|
300 |
|
|
only summarized.
|
301 |
|
|
|
302 |
|
|
To profile core accesses (such as data reads/writes and insn fetches), add
|
303 |
|
|
calls to PROFILE_COUNT_CORE() to your read/write functions. So in your data
|
304 |
|
|
fetch function, you'd use something like:
|
305 |
|
|
PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_read);
|
306 |
|
|
Then in your data write function:
|
307 |
|
|
PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_write);
|
308 |
|
|
And in your insn fetcher:
|
309 |
|
|
PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_exec);
|
310 |
|
|
|
311 |
|
|
To use the PC profiling code, you simply have to tell the system where to find
|
312 |
|
|
your simulator's PC and its size. So in your sim_open() function:
|
313 |
|
|
STATE_WATCHPOINTS (sd)->pc = address_of_cpu0_pc;
|
314 |
|
|
STATE_WATCHPOINTS (sd)->sizeof_pc = number_of_bytes_for_pc_storage;
|
315 |
|
|
In a typical 32bit system, the sizeof_pc will be 4 bytes.
|
316 |
|
|
|
317 |
|
|
To profile branches, in every location where a branch insn is executed, call
|
318 |
|
|
one of the related helpers:
|
319 |
|
|
PROFILE_BRANCH_TAKEN (cpu);
|
320 |
|
|
PROFILE_BRANCH_UNTAKEN (cpu);
|
321 |
|
|
If you have stall information, you can utilize the other helpers too.
|
322 |
|
|
|
323 |
|
|
Environment Simulation
|
324 |
|
|
======================
|
325 |
|
|
|
326 |
|
|
The simplest simulator doesn't include environment support -- it merely
|
327 |
|
|
simulates the Instruction Set Architecture (ISA). Once you're ready to move
|
328 |
|
|
on to the next level, call the common macro in your configure.ac:
|
329 |
|
|
SIM_AC_OPTION_ENVIRONMENT
|
330 |
|
|
|
331 |
|
|
This will support for the user, virtual, and operating environments. See the
|
332 |
|
|
sim-config.h header for a more detailed description of them. The former are
|
333 |
|
|
pretty straight forward as things like exceptions (making system calls) are
|
334 |
|
|
handled in the simulator. Which is to say, an exception does not trigger an
|
335 |
|
|
exception handler in the simulator target -- that is what the operating env
|
336 |
|
|
is about. See the following userspace section for more information.
|
337 |
|
|
|
338 |
|
|
Userspace System Calls
|
339 |
|
|
======================
|
340 |
|
|
|
341 |
|
|
By default, the libgloss userspace is simulated. That means the system call
|
342 |
|
|
numbers and calling convention matches that of libgloss. Simulating other
|
343 |
|
|
userspaces (such as Linux) is pretty straightforward, but let's first focus
|
344 |
|
|
on the basics. The basic API is covered in include/gdb/callback.h.
|
345 |
|
|
|
346 |
|
|
When an instruction is simulated that invokes the system call method (such as
|
347 |
|
|
forcing a hardware trap or exception), your simulator code should set up the
|
348 |
|
|
CB_SYSCALL data structure before calling the common cb_syscall() function.
|
349 |
|
|
For example:
|
350 |
|
|
static int
|
351 |
|
|
syscall_read_mem (host_callback *cb, struct cb_syscall *sc,
|
352 |
|
|
unsigned long taddr, char *buf, int bytes)
|
353 |
|
|
{
|
354 |
|
|
SIM_DESC sd = (SIM_DESC) sc->p1;
|
355 |
|
|
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
|
356 |
|
|
return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
|
357 |
|
|
}
|
358 |
|
|
static int
|
359 |
|
|
syscall_write_mem (host_callback *cb, struct cb_syscall *sc,
|
360 |
|
|
unsigned long taddr, const char *buf, int bytes)
|
361 |
|
|
{
|
362 |
|
|
SIM_DESC sd = (SIM_DESC) sc->p1;
|
363 |
|
|
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
|
364 |
|
|
return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
|
365 |
|
|
}
|
366 |
|
|
void target_sim_syscall (SIM_CPU *cpu)
|
367 |
|
|
{
|
368 |
|
|
SIM_DESC sd = CPU_STATE (cpu);
|
369 |
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
370 |
|
|
CB_SYSCALL sc;
|
371 |
|
|
|
372 |
|
|
CB_SYSCALL_INIT (&sc);
|
373 |
|
|
|
374 |
|
|
sc.func = ;
|
375 |
|
|
sc.arg1 = ;
|
376 |
|
|
sc.arg2 = ;
|
377 |
|
|
sc.arg3 = ;
|
378 |
|
|
sc.arg4 = ;
|
379 |
|
|
sc.p1 = (PTR) sd;
|
380 |
|
|
sc.p2 = (PTR) cpu;
|
381 |
|
|
sc.read_mem = syscall_read_mem;
|
382 |
|
|
sc.write_mem = syscall_write_mem;
|
383 |
|
|
|
384 |
|
|
cb_syscall (cb, &sc);
|
385 |
|
|
|
386 |
|
|
;
|
387 |
|
|
;
|
388 |
|
|
}
|
389 |
|
|
Some targets store the result and error code in different places, while others
|
390 |
|
|
only store the error code when the result is an error.
|
391 |
|
|
|
392 |
|
|
Keep in mind that the CB_SYS_xxx defines are normalized values with no real
|
393 |
|
|
meaning with respect to the target. They provide a unique map on the host so
|
394 |
|
|
that it can parse things sanely. For libgloss, the common/nltvals.def file
|
395 |
|
|
creates the target's system call numbers to the CB_SYS_xxx values.
|
396 |
|
|
|
397 |
|
|
To simulate other userspace targets, you really only need to update the maps
|
398 |
|
|
pointers that are part of the callback interface. So create CB_TARGET_DEFS_MAP
|
399 |
|
|
arrays for each set (system calls, errnos, open bits, etc...) and in a place
|
400 |
|
|
you find useful, do something like:
|
401 |
|
|
|
402 |
|
|
...
|
403 |
|
|
static CB_TARGET_DEFS_MAP cb_linux_syscall_map[] = {
|
404 |
|
|
# define TARGET_LINUX_SYS_open 5
|
405 |
|
|
{ CB_SYS_open, TARGET_LINUX_SYS_open },
|
406 |
|
|
...
|
407 |
|
|
{ -1, -1 },
|
408 |
|
|
};
|
409 |
|
|
...
|
410 |
|
|
host_callback *cb = STATE_CALLBACK (sd);
|
411 |
|
|
cb->syscall_map = cb_linux_syscall_map;
|
412 |
|
|
cb->errno_map = cb_linux_errno_map;
|
413 |
|
|
cb->open_map = cb_linux_open_map;
|
414 |
|
|
cb->signal_map = cb_linux_signal_map;
|
415 |
|
|
cb->stat_map = cb_linux_stat_map;
|
416 |
|
|
...
|
417 |
|
|
|
418 |
|
|
Each of these cb_linux_*_map's are manually declared by the arch target.
|
419 |
|
|
|
420 |
|
|
The target_sim_syscall() example above will then work unchanged (ignoring the
|
421 |
|
|
system call convention) because all of the callback functions go through these
|
422 |
|
|
mapping arrays.
|
423 |
|
|
|
424 |
|
|
Events
|
425 |
|
|
======
|
426 |
|
|
|
427 |
|
|
Events are scheduled and executed on behalf of either a cpu or hardware devices.
|
428 |
|
|
The API is pretty much the same and can be found in common/sim-events.h and
|
429 |
|
|
common/hw-events.h.
|
430 |
|
|
|
431 |
|
|
For simulator targets, you really just have to worry about the schedule and
|
432 |
|
|
deschedule functions.
|
433 |
|
|
|
434 |
|
|
Device Trees
|
435 |
|
|
============
|
436 |
|
|
|
437 |
|
|
The device tree model is based on the OpenBoot specification. Since this is
|
438 |
|
|
largely inherited from the psim code, consult the existing psim documentation
|
439 |
|
|
for some in-depth details.
|
440 |
|
|
http://sourceware.org/psim/manual/
|
441 |
|
|
|
442 |
|
|
Hardware Devices
|
443 |
|
|
================
|
444 |
|
|
|
445 |
|
|
The simplest simulator doesn't include hardware device support. Once you're
|
446 |
|
|
ready to move on to the next level, call the common macro in your configure.ac:
|
447 |
|
|
SIM_AC_OPTION_HARDWARE(yes,,devone devtwo devthree)
|
448 |
|
|
|
449 |
|
|
The basic hardware API is documented in common/hw-device.h.
|
450 |
|
|
|
451 |
|
|
Each device has to have a matching file name with a "dv-" prefix. So there has
|
452 |
|
|
to be a dv-devone.c, dv-devtwo.c, and dv-devthree.c files. Further, each file
|
453 |
|
|
has to have a matching hw_descriptor structure. So the dv-devone.c file has to
|
454 |
|
|
have something like:
|
455 |
|
|
const struct hw_descriptor dv_devone_descriptor[] = {
|
456 |
|
|
{"devone", devone_finish,},
|
457 |
|
|
{NULL, NULL},
|
458 |
|
|
};
|
459 |
|
|
|
460 |
|
|
The "devone" string as well as the "devone_finish" function are not hard
|
461 |
|
|
requirements, just common conventions. The structure name is a hard
|
462 |
|
|
requirement.
|
463 |
|
|
|
464 |
|
|
The devone_finish() callback function is used to instantiate this device by
|
465 |
|
|
parsing the corresponding properties in the device tree.
|
466 |
|
|
|
467 |
|
|
Hardware devices typically attach address ranges to themselves. Then when
|
468 |
|
|
accesses to those addresses are made, the hardware will have its callback
|
469 |
|
|
invoked. The exact callback could be a normal I/O read/write access, as
|
470 |
|
|
well as a DMA access. This makes it easy to simulate memory mapped registers.
|
471 |
|
|
|
472 |
|
|
Keep in mind that like a proper device driver, it may be instantiated many
|
473 |
|
|
times over. So any device state it needs to be maintained should be allocated
|
474 |
|
|
during the finish callback and attached to the hardware device via set_hw_data.
|
475 |
|
|
Any hardware functions can access this private data via the hw_data function.
|
476 |
|
|
|
477 |
|
|
Ports (Interrupts / IRQs)
|
478 |
|
|
=========================
|
479 |
|
|
|
480 |
|
|
First, a note on terminology. A "port" is an aspect of a hardware device that
|
481 |
|
|
accepts or generates interrupts. So devices with input ports may be the target
|
482 |
|
|
of an interrupt (accept it), and/or they have output ports so that they may be
|
483 |
|
|
the source of an interrupt (generate it).
|
484 |
|
|
|
485 |
|
|
Each port has a symbolic name and a unique number. These are used to identify
|
486 |
|
|
the port in different contexts. The output port name has no hard relationship
|
487 |
|
|
to the input port name (same for the unique number). The callback that accepts
|
488 |
|
|
the interrupt uses the name/id of its input port, while the generator function
|
489 |
|
|
uses the name/id of its output port.
|
490 |
|
|
|
491 |
|
|
The device tree is used to connect the output port of a device to the input
|
492 |
|
|
port of another device. There are no limits on the number of inputs connected
|
493 |
|
|
to an output, or outputs to an input, or the devices attached to the ports.
|
494 |
|
|
In other words, the input port and output port could be the same device.
|
495 |
|
|
|
496 |
|
|
The basics are:
|
497 |
|
|
- each hardware device declares an array of ports (hw_port_descriptor).
|
498 |
|
|
any mix of input and output ports is allowed.
|
499 |
|
|
- when setting up the device, attach the array (set_hw_ports).
|
500 |
|
|
- if the device accepts interrupts, it will have to attach a port callback
|
501 |
|
|
function (set_hw_port_event)
|
502 |
|
|
- connect ports with the device tree
|
503 |
|
|
- handle incoming interrupts with the callback
|
504 |
|
|
- generate outgoing interrupts with hw_port_event
|