]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/README-HACKING
sim: modules.c: fix generation after recent refactors
[thirdparty/binutils-gdb.git] / sim / README-HACKING
CommitLineData
c906108c
SS
1This is a loose collection of notes for people hacking on simulators.
2If this document gets big enough it can be prettied up then.
3
4Contents
5
6- The "common" directory
7- Common Makefile Support
8- TAGS support
9- Generating "configure" files
c906108c
SS
10- C Language Assumptions
11- "dump" commands under gdb
12\f
13The "common" directory
14======================
15
16The common directory contains:
17
18- common documentation files (e.g. run.1, and maybe in time .texi files)
19- common source files (e.g. run.c)
fe0adb53 20- common Makefile fragment and configury (e.g. common/local.mk)
c906108c
SS
21
22In addition "common" contains portions of the system call support
64ae70dd 23(e.g. callback.c, target-newlib-*.c).
c906108c 24\f
c906108c
SS
25TAGS support
26============
27
28Many files generate program symbols at compile time.
29Such symbols can't be found with grep nor do they normally appear in
30the TAGS file. To get around this, source files can add the comment
31
32/* TAGS: foo1 foo2 */
33
34where foo1, foo2 are program symbols. Symbols found in such comments
35are greppable and appear in the TAGS file.
36\f
37Generating "configure" files
38============================
39
508de641 40"configure" can be generated by running `autoreconf'.
c906108c
SS
41\f
42C Language Assumptions
43======================
44
46f900c0 45An ISO C11 compiler is required, as is an ISO C standard library.
c906108c
SS
46\f
47"dump" commands under gdb
48=========================
49
50gdbinit.in contains the following
51
52define dump
53set sim_debug_dump ()
54end
55
56Simulators that define the sim_debug_dump function can then have their
57internal state pretty printed from gdb.
58
59FIXME: This can obviously be made more elaborate. As needed it will be.
60\f
64ae70dd
MF
61Rebuilding target-newlib-* files
62================================
c906108c
SS
63
64Checkout a copy of the SIM and LIBGLOSS modules (Unless you've already
65got one to hand):
66
67 $ mkdir /tmp/$$
68 $ cd /tmp/$$
69 $ cvs checkout sim-no-testsuite libgloss-no-testsuite newlib-no-testsuite
70
bd0918c9 71Configure things for an arbitrary simulator target (d10v is used here for
c906108c
SS
72convenience):
73
74 $ mkdir /tmp/$$/build
75 $ cd /tmp/$$/build
76 $ /tmp/$$/devo/configure --target=d10v-elf
77
5e25901f 78In the sim/ directory rebuild the headers:
c906108c 79
5e25901f
MF
80 $ cd sim/
81 $ make nltvals
c906108c 82
bd0918c9
MF
83If the target uses the common syscall table (libgloss/syscall.h), then you're
84all set! If the target has a custom syscall table, you need to declare it:
c906108c 85
bd0918c9 86 devo/sim/common/gennltvals.py
c906108c
SS
87
88 Add your new processor target (you'll need to grub
89 around to find where your syscall.h lives).
90
c906108c
SS
91 devo/sim/<processor>/*.[ch]
92
64ae70dd 93 Include target-newlib-syscall.h instead of syscall.h.
aba193a5
MF
94\f
95Tracing
96=======
97
98For ports based on CGEN, tracing instrumentation should largely be for free,
99so we will cover the basic non-CGEN setup here. The assumption is that your
100target is using the common autoconf macros and so the build system already
101includes the sim-trace configure flag.
102
103The full tracing API is covered in sim-trace.h, so this section is an overview.
104
105Before calling any trace function, you should make a call to the trace_prefix()
106function. This is usually done in the main sim_engine_run() loop before
107simulating the next instruction. You should make this call before every
108simulated insn. You can probably copy & paste this:
109 if (TRACE_ANY_P (cpu))
110 trace_prefix (sd, cpu, NULL_CIA, oldpc, TRACE_LINENUM_P (cpu), NULL, 0, "");
111
112You will then need to instrument your simulator code with calls to the
113trace_generic() function with the appropriate trace index. Typically, this
114will take a form similar to the above snippet. So to trace instructions, you
115would use something like:
116 if (TRACE_INSN_P (cpu))
117 trace_generic (sd, cpu, TRACE_INSN_IDX, "NOP;");
118
119The exact output format is up to you. See the trace index enum in sim-trace.h
120to see the different tracing info available.
121
122To utilize the tracing features at runtime, simply use the --trace-xxx flags.
123 run --trace-insn ./some-program
124\f
125Profiling
126=========
127
128Similar to the tracing section, this is merely an overview for non-CGEN based
129ports. The full API may be found in sim-profile.h. Its API is also similar
130to the tracing API.
131
132Note that unlike the tracing command line options, in addition to the profile
133flags, you have to use the --verbose option to view the summary report after
134execution. Tracing output is displayed on the fly, but the profile output is
135only summarized.
136
137To profile core accesses (such as data reads/writes and insn fetches), add
138calls to PROFILE_COUNT_CORE() to your read/write functions. So in your data
139fetch function, you'd use something like:
140 PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_read);
141Then in your data write function:
142 PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_write);
143And in your insn fetcher:
144 PROFILE_COUNT_CORE (cpu, target_addr, size_in_bytes, map_exec);
145
146To use the PC profiling code, you simply have to tell the system where to find
4c0d76b9
MF
147your simulator's PC. So in your model initialization function:
148 CPU_PC_FETCH (cpu) = function_that_fetches_the_pc;
aba193a5
MF
149
150To profile branches, in every location where a branch insn is executed, call
151one of the related helpers:
152 PROFILE_BRANCH_TAKEN (cpu);
153 PROFILE_BRANCH_UNTAKEN (cpu);
154If you have stall information, you can utilize the other helpers too.
155\f
156Environment Simulation
157======================
158
159The simplest simulator doesn't include environment support -- it merely
160simulates the Instruction Set Architecture (ISA). Once you're ready to move
425b0b1a
MF
161on to the next level, it's time to start handling the --env option. It's
162enabled by default for all ports already.
aba193a5
MF
163
164This will support for the user, virtual, and operating environments. See the
165sim-config.h header for a more detailed description of them. The former are
166pretty straight forward as things like exceptions (making system calls) are
167handled in the simulator. Which is to say, an exception does not trigger an
168exception handler in the simulator target -- that is what the operating env
169is about. See the following userspace section for more information.
170\f
171Userspace System Calls
172======================
173
174By default, the libgloss userspace is simulated. That means the system call
175numbers and calling convention matches that of libgloss. Simulating other
176userspaces (such as Linux) is pretty straightforward, but let's first focus
df68e12b 177on the basics. The basic API is covered in include/sim/callback.h.
aba193a5
MF
178
179When an instruction is simulated that invokes the system call method (such as
180forcing a hardware trap or exception), your simulator code should set up the
181CB_SYSCALL data structure before calling the common cb_syscall() function.
182For example:
183static int
184syscall_read_mem (host_callback *cb, struct cb_syscall *sc,
185 unsigned long taddr, char *buf, int bytes)
186{
187 SIM_DESC sd = (SIM_DESC) sc->p1;
188 SIM_CPU *cpu = (SIM_CPU *) sc->p2;
189 return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
190}
191static int
192syscall_write_mem (host_callback *cb, struct cb_syscall *sc,
193 unsigned long taddr, const char *buf, int bytes)
194{
195 SIM_DESC sd = (SIM_DESC) sc->p1;
196 SIM_CPU *cpu = (SIM_CPU *) sc->p2;
197 return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
198}
199void target_sim_syscall (SIM_CPU *cpu)
200{
201 SIM_DESC sd = CPU_STATE (cpu);
202 host_callback *cb = STATE_CALLBACK (sd);
203 CB_SYSCALL sc;
204
205 CB_SYSCALL_INIT (&sc);
206
207 sc.func = <fetch system call number>;
208 sc.arg1 = <fetch first system call argument>;
209 sc.arg2 = <fetch second system call argument>;
210 sc.arg3 = <fetch third system call argument>;
211 sc.arg4 = <fetch fourth system call argument>;
212 sc.p1 = (PTR) sd;
213 sc.p2 = (PTR) cpu;
214 sc.read_mem = syscall_read_mem;
215 sc.write_mem = syscall_write_mem;
216
217 cb_syscall (cb, &sc);
218
219 <store system call result from sc.result>;
220 <store system call error from sc.errcode>;
221}
222Some targets store the result and error code in different places, while others
223only store the error code when the result is an error.
224
225Keep in mind that the CB_SYS_xxx defines are normalized values with no real
226meaning with respect to the target. They provide a unique map on the host so
64ae70dd
MF
227that it can parse things sanely. For libgloss, the common/target-newlib-syscall
228file contains the target's system call numbers to the CB_SYS_xxx values.
aba193a5
MF
229
230To simulate other userspace targets, you really only need to update the maps
231pointers that are part of the callback interface. So create CB_TARGET_DEFS_MAP
232arrays for each set (system calls, errnos, open bits, etc...) and in a place
233you find useful, do something like:
234
235...
236static CB_TARGET_DEFS_MAP cb_linux_syscall_map[] = {
237# define TARGET_LINUX_SYS_open 5
238 { CB_SYS_open, TARGET_LINUX_SYS_open },
239 ...
240 { -1, -1 },
241};
242...
243 host_callback *cb = STATE_CALLBACK (sd);
244 cb->syscall_map = cb_linux_syscall_map;
245 cb->errno_map = cb_linux_errno_map;
246 cb->open_map = cb_linux_open_map;
247 cb->signal_map = cb_linux_signal_map;
248 cb->stat_map = cb_linux_stat_map;
249...
250
251Each of these cb_linux_*_map's are manually declared by the arch target.
252
253The target_sim_syscall() example above will then work unchanged (ignoring the
254system call convention) because all of the callback functions go through these
255mapping arrays.
256\f
257Events
258======
259
260Events are scheduled and executed on behalf of either a cpu or hardware devices.
261The API is pretty much the same and can be found in common/sim-events.h and
262common/hw-events.h.
263
264For simulator targets, you really just have to worry about the schedule and
265deschedule functions.
266\f
267Device Trees
268============
269
270The device tree model is based on the OpenBoot specification. Since this is
271largely inherited from the psim code, consult the existing psim documentation
272for some in-depth details.
273 http://sourceware.org/psim/manual/
274\f
275Hardware Devices
276================
277
278The simplest simulator doesn't include hardware device support. Once you're
be0387ee
MF
279ready to move on to the next level, declare in your Makefile.in:
280SIM_EXTRA_HW_DEVICES = devone devtwo devthree
aba193a5
MF
281
282The basic hardware API is documented in common/hw-device.h.
283
284Each device has to have a matching file name with a "dv-" prefix. So there has
285to be a dv-devone.c, dv-devtwo.c, and dv-devthree.c files. Further, each file
286has to have a matching hw_descriptor structure. So the dv-devone.c file has to
287have something like:
288 const struct hw_descriptor dv_devone_descriptor[] = {
289 {"devone", devone_finish,},
290 {NULL, NULL},
291 };
292
293The "devone" string as well as the "devone_finish" function are not hard
294requirements, just common conventions. The structure name is a hard
295requirement.
296
297The devone_finish() callback function is used to instantiate this device by
298parsing the corresponding properties in the device tree.
299
300Hardware devices typically attach address ranges to themselves. Then when
301accesses to those addresses are made, the hardware will have its callback
302invoked. The exact callback could be a normal I/O read/write access, as
303well as a DMA access. This makes it easy to simulate memory mapped registers.
304
305Keep in mind that like a proper device driver, it may be instantiated many
306times over. So any device state it needs to be maintained should be allocated
307during the finish callback and attached to the hardware device via set_hw_data.
308Any hardware functions can access this private data via the hw_data function.
309\f
310Ports (Interrupts / IRQs)
311=========================
c906108c 312
aba193a5
MF
313First, a note on terminology. A "port" is an aspect of a hardware device that
314accepts or generates interrupts. So devices with input ports may be the target
315of an interrupt (accept it), and/or they have output ports so that they may be
316the source of an interrupt (generate it).
317
318Each port has a symbolic name and a unique number. These are used to identify
319the port in different contexts. The output port name has no hard relationship
320to the input port name (same for the unique number). The callback that accepts
321the interrupt uses the name/id of its input port, while the generator function
322uses the name/id of its output port.
323
324The device tree is used to connect the output port of a device to the input
325port of another device. There are no limits on the number of inputs connected
326to an output, or outputs to an input, or the devices attached to the ports.
327In other words, the input port and output port could be the same device.
328
329The basics are:
330 - each hardware device declares an array of ports (hw_port_descriptor).
331 any mix of input and output ports is allowed.
332 - when setting up the device, attach the array (set_hw_ports).
333 - if the device accepts interrupts, it will have to attach a port callback
334 function (set_hw_port_event)
335 - connect ports with the device tree
336 - handle incoming interrupts with the callback
337 - generate outgoing interrupts with hw_port_event