Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* This file is part of the program psim. |
2 | ||
3 | Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | ||
19 | */ | |
20 | ||
21 | ||
22 | #ifndef HW_DEVICE_H | |
23 | #define HW_DEVICE_H | |
24 | ||
25 | /* declared in sim-basics.h, this object is used everywhere */ | |
26 | /* typedef struct _device device; */ | |
27 | ||
28 | ||
29 | /* Introduction: | |
30 | ||
31 | As explained in earlier sections, the device, device instance, | |
32 | property and ports lie at the heart of PSIM's device model. | |
33 | ||
34 | In the below a synopsis of the device object and the operations it | |
35 | supports are given. | |
36 | */ | |
37 | ||
38 | ||
39 | /* Creation: | |
40 | ||
41 | The devices are created using a sequence of steps. In particular: | |
42 | ||
43 | o A tree framework is created. | |
44 | ||
45 | At this point, properties can be modified and extra | |
46 | devices inserted (or removed?). | |
47 | ||
48 | #if LATER | |
49 | ||
50 | Any properties that have a run-time value (eg ihandle | |
51 | or device instance pointer properties) are entered | |
52 | into the device tree using a named reference to the | |
53 | corresponding runtime object that is to be created. | |
54 | ||
55 | #endif | |
56 | ||
57 | o Real devices are created for all the dummy devices. | |
58 | ||
59 | A device can assume that all of its parents have been | |
60 | initialized. | |
61 | ||
62 | A device can assume that all non run-time properties | |
63 | have been initialized. | |
64 | ||
65 | As part of being created, the device normally attaches | |
66 | itself to its parent bus. | |
67 | ||
68 | #if LATER | |
69 | ||
70 | Device instance data is initialized. | |
71 | ||
72 | #endif | |
73 | ||
74 | #if LATER | |
75 | ||
76 | o Any run-time properties are created. | |
77 | ||
78 | #endif | |
79 | ||
80 | #if MUCH_MUCH_LATER | |
81 | ||
82 | o Some devices, as part of their initialization | |
83 | might want to refer to ihandle properties | |
84 | in the device tree. | |
85 | ||
86 | #endif | |
87 | ||
88 | NOTES: | |
89 | ||
90 | o It is important to separate the creation | |
91 | of an actual device from the creation | |
92 | of the tree. The alternative creating | |
93 | the device in two stages: As a separate | |
94 | entity and then as a part of the tree. | |
95 | ||
96 | #if LATER | |
97 | o Run-time properties can not be created | |
98 | until after the devices in the tree | |
99 | have been created. Hence an extra pass | |
100 | for handling them. | |
101 | #endif | |
102 | ||
103 | */ | |
104 | ||
105 | /* Relationships: | |
106 | ||
107 | A device is able to determine its relationship to other devices | |
108 | within the tree. Operations include querying for a devices parent, | |
109 | sibling, child, name, and path (from the root). | |
110 | ||
111 | */ | |
112 | ||
113 | ||
114 | #define hw_parent(hw) ((hw)->parent_of_hw + 0) | |
115 | ||
116 | #define hw_sibling(hw) ((hw)->sibling_of_hw + 0) | |
117 | ||
118 | #define hw_child(hw) ((hw)->child_of_hw + 0) | |
119 | ||
120 | ||
121 | ||
122 | /* Herritage: | |
123 | ||
124 | */ | |
125 | ||
126 | #define hw_family(hw) ((hw)->family_of_hw + 0) | |
127 | ||
128 | #define hw_name(hw) ((hw)->name_of_hw + 0) | |
129 | ||
130 | #define hw_args(hw) ((hw)->args_of_hw + 0) | |
131 | ||
132 | #define hw_path(hw) ((hw)->path_of_hw + 0) | |
133 | ||
134 | ||
135 | ||
136 | /* Short cut to the root node of the tree */ | |
137 | ||
138 | #define hw_root(hw) ((hw)->root_of_hw + 0) | |
139 | ||
140 | /* Short cut back to the simulator object */ | |
141 | ||
142 | #define hw_system(hw) ((hw)->system_of_hw) | |
143 | ||
144 | /* For requests initiated by a CPU the cpu that initiated the request */ | |
145 | ||
146 | struct _sim_cpu *hw_system_cpu (struct hw *hw); | |
147 | ||
148 | ||
149 | /* Device private data */ | |
150 | ||
151 | #define hw_data(hw) ((hw)->data_of_hw) | |
152 | ||
153 | #define set_hw_data(hw, value) \ | |
154 | ((hw)->data_of_hw = (value)) | |
155 | ||
156 | ||
157 | \f | |
158 | /* Perform a soft reset of the device */ | |
159 | ||
160 | typedef unsigned (hw_reset_method) | |
161 | (struct hw *me); | |
162 | ||
163 | #define hw_reset(hw) ((hw)->to_reset (hw)) | |
164 | ||
165 | #define set_hw_reset(hw, method) \ | |
166 | ((hw)->to_reset = method) | |
167 | ||
168 | \f | |
169 | /* Hardware operations: | |
170 | ||
171 | Connecting a parent to its children is a common bus. The parent | |
172 | node is described as the bus owner and is responisble for | |
173 | co-ordinating bus operations. On the bus, a SPACE:ADDR pair is used | |
174 | to specify an address. A device that is both a bus owner (parent) | |
175 | and bus client (child) are refered to as a bridging device. | |
176 | ||
177 | A child performing a data (DMA) transfer will pass its request to | |
178 | the bus owner (the devices parent). The bus owner will then either | |
179 | reflect the request to one of the other devices attached to the bus | |
180 | (a child of the bus owner) or bridge the request up the tree to the | |
181 | next bus. */ | |
182 | ||
183 | ||
184 | /* Children attached to a bus can register (attach) themselves to | |
185 | specific addresses on their attached bus. | |
186 | ||
187 | (A device may also be implicitly attached to certain bus | |
188 | addresses). | |
189 | ||
190 | The SPACE:ADDR pair specify an address on the common bus that | |
191 | connects the parent and child devices. */ | |
192 | ||
193 | typedef void (hw_attach_address_method) | |
194 | (struct hw *me, | |
195 | int level, | |
196 | int space, | |
197 | address_word addr, | |
198 | address_word nr_bytes, | |
199 | struct hw *client); /*callback/default*/ | |
200 | ||
201 | #define hw_attach_address(me, level, space, addr, nr_bytes, client) \ | |
202 | ((me)->to_attach_address (me, level, space, addr, nr_bytes, client)) | |
203 | ||
204 | #define set_hw_attach_address(hw, method) \ | |
205 | ((hw)->to_attach_address = (method)) | |
206 | ||
207 | typedef void (hw_detach_address_method) | |
208 | (struct hw *me, | |
209 | int level, | |
210 | int space, | |
211 | address_word addr, | |
212 | address_word nr_bytes, | |
213 | struct hw *client); /*callback/default*/ | |
214 | ||
215 | #define hw_detach_address(me, level, space, addr, nr_bytes, client) \ | |
216 | ((me)->to_detach_address (me, level, space, addr, nr_bytes, client)) | |
217 | ||
218 | #define set_hw_detach_address(hw, method) \ | |
219 | ((hw)->to_detach_address = (method)) | |
220 | ||
221 | ||
222 | /* An IO operation from a parent to a child via the conecting bus. | |
223 | ||
224 | The SPACE:ADDR pair specify an address on the bus shared between | |
225 | the parent and child devices. */ | |
226 | ||
227 | typedef unsigned (hw_io_read_buffer_method) | |
228 | (struct hw *me, | |
229 | void *dest, | |
230 | int space, | |
231 | unsigned_word addr, | |
232 | unsigned nr_bytes); | |
233 | ||
234 | #define hw_io_read_buffer(hw, dest, space, addr, nr_bytes) \ | |
235 | ((hw)->to_io_read_buffer (hw, dest, space, addr, nr_bytes)) | |
236 | ||
237 | #define set_hw_io_read_buffer(hw, method) \ | |
238 | ((hw)->to_io_read_buffer = (method)) | |
239 | ||
240 | typedef unsigned (hw_io_write_buffer_method) | |
241 | (struct hw *me, | |
242 | const void *source, | |
243 | int space, | |
244 | unsigned_word addr, | |
245 | unsigned nr_bytes); | |
246 | ||
247 | #define hw_io_write_buffer(hw, src, space, addr, nr_bytes) \ | |
248 | ((hw)->to_io_write_buffer (hw, src, space, addr, nr_bytes)) | |
249 | ||
250 | #define set_hw_io_write_buffer(hw, method) \ | |
251 | ((hw)->to_io_write_buffer = (method)) | |
252 | ||
253 | ||
254 | /* Conversly, the device pci1000,1@1 may need to perform a dma transfer | |
255 | into the cpu/memory core. Just as I/O moves towards the leaves, | |
256 | dma transfers move towards the core via the initiating devices | |
257 | parent nodes. The root device (special) converts the DMA transfer | |
258 | into reads/writes to memory. | |
259 | ||
260 | The SPACE:ADDR pair specify an address on the common bus connecting | |
261 | the parent and child devices. */ | |
262 | ||
263 | typedef unsigned (hw_dma_read_buffer_method) | |
264 | (struct hw *bus, | |
265 | void *dest, | |
266 | int space, | |
267 | unsigned_word addr, | |
268 | unsigned nr_bytes); | |
269 | ||
270 | #define hw_dma_read_buffer(bus, dest, space, addr, nr_bytes) \ | |
271 | ((bus)->to_dma_read_buffer (bus, dest, space, addr, nr_bytes)) | |
272 | ||
273 | #define set_hw_dma_read_buffer(me, method) \ | |
274 | ((me)->to_dma_read_buffer = (method)) | |
275 | ||
276 | typedef unsigned (hw_dma_write_buffer_method) | |
277 | (struct hw *bus, | |
278 | const void *source, | |
279 | int space, | |
280 | unsigned_word addr, | |
281 | unsigned nr_bytes, | |
282 | int violate_read_only_section); | |
283 | ||
284 | #define hw_dma_write_buffer(bus, src, space, addr, nr_bytes, violate_ro) \ | |
285 | ((bus)->to_dma_write_buffer (bus, src, space, addr, nr_bytes, violate_ro)) | |
286 | ||
287 | #define set_hw_dma_write_buffer(me, method) \ | |
288 | ((me)->to_dma_write_buffer = (method)) | |
289 | \f | |
290 | /* Address/size specs for devices are encoded following a convention | |
291 | similar to that used by OpenFirmware. In particular, an | |
292 | address/size is packed into a sequence of up to four cell words. | |
293 | The number of words determined by the number of {address,size} | |
294 | cells attributes of the device. */ | |
295 | ||
296 | typedef struct _hw_unit { | |
297 | int nr_cells; | |
298 | unsigned_cell cells[4]; /* unused cells are zero */ | |
299 | } hw_unit; | |
300 | ||
301 | ||
302 | /* For the given bus, the number of address and size cells used in a | |
303 | hw_unit. */ | |
304 | ||
305 | #define hw_unit_nr_address_cells(bus) ((bus)->nr_address_cells_of_hw_unit + 0) | |
306 | ||
307 | #define hw_unit_nr_size_cells(bus) ((bus)->nr_size_cells_of_hw_unit + 0) | |
308 | ||
309 | ||
310 | /* For the given device, its identifying hw_unit address. | |
311 | ||
312 | Each device has an identifying hw_unit address. That address is | |
313 | used when identifying one of a number of identical devices on a | |
314 | common controller bus. ex fd0&fd1. */ | |
315 | ||
316 | const hw_unit *hw_unit_address | |
317 | (struct hw *me); | |
318 | ||
319 | ||
320 | /* Convert between a textual and the internal representation of a | |
321 | hw_unit address/size. | |
322 | ||
323 | NOTE: A device asks its parent to translate between a hw_unit and | |
324 | textual representation. This is because the textual address of a | |
325 | device is specified using the parent busses notation. */ | |
326 | ||
327 | typedef int (hw_unit_decode_method) | |
328 | (struct hw *bus, | |
329 | const char *encoded, | |
330 | hw_unit *unit); | |
331 | ||
332 | #define hw_unit_decode(bus, encoded, unit) \ | |
333 | ((bus)->to_unit_decode (bus, encoded, unit)) | |
334 | ||
335 | #define set_hw_unit_decode(hw, method) \ | |
336 | ((hw)->to_unit_decode = (method)) | |
337 | ||
338 | typedef int (hw_unit_encode_method) | |
339 | (struct hw *bus, | |
340 | const hw_unit *unit, | |
341 | char *encoded, | |
342 | int sizeof_buf); | |
343 | ||
344 | #define hw_unit_encode(bus, unit, encoded, sizeof_encoded) \ | |
345 | ((bus)->to_unit_encode (bus, unit, encoded, sizeof_encoded)) | |
346 | ||
347 | #define set_hw_unit_encode(hw, method) \ | |
348 | ((hw)->to_unit_encode = (method)) | |
349 | ||
350 | ||
351 | /* As the bus that the device is attached too, to translate a devices | |
352 | hw_unit address/size into a form suitable for an attach address | |
353 | call. | |
354 | ||
355 | Return a zero result if the address should be ignored when looking | |
356 | for attach addresses. */ | |
357 | ||
358 | typedef int (hw_unit_address_to_attach_address_method) | |
359 | (struct hw *bus, | |
360 | const hw_unit *unit_addr, | |
361 | int *attach_space, | |
362 | unsigned_word *attach_addr, | |
363 | struct hw *client); | |
364 | ||
365 | #define hw_unit_address_to_attach_address(bus, unit_addr, attach_space, attach_addr, client) \ | |
366 | ((bus)->to_unit_address_to_attach_address (bus, unit_addr, attach_space, attach_addr, client)) | |
367 | ||
368 | #define set_hw_unit_address_to_attach_address(hw, method) \ | |
369 | ((hw)->to_unit_address_to_attach_address = (method)) | |
370 | ||
371 | typedef int (hw_unit_size_to_attach_size_method) | |
372 | (struct hw *bus, | |
373 | const hw_unit *unit_size, | |
374 | unsigned *attach_size, | |
375 | struct hw *client); | |
376 | ||
377 | #define hw_unit_size_to_attach_size(bus, unit_size, attach_size, client) \ | |
378 | ((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client)) | |
379 | ||
380 | #define set_hw_unit_size_to_attach_size(hw, method) \ | |
381 | ((hw)->to_unit_size_to_attach_size = (method)) | |
382 | ||
383 | \f | |
384 | extern char *hw_strdup (struct hw *me, const char *str); | |
385 | ||
386 | \f | |
387 | /* Utilities: | |
388 | ||
389 | */ | |
390 | ||
391 | /* IOCTL:: | |
392 | ||
393 | Often devices require `out of band' operations to be performed. | |
394 | For instance a pal device may need to notify a PCI bridge device | |
395 | that an interrupt ack cycle needs to be performed on the PCI bus. | |
396 | Within PSIM such operations are performed by using the generic | |
397 | ioctl call <<hw_ioctl()>>. | |
398 | ||
399 | */ | |
400 | ||
401 | typedef enum { | |
402 | hw_ioctl_break, /* unsigned_word requested_break */ | |
403 | hw_ioctl_set_trace, /* void */ | |
404 | hw_ioctl_create_stack, /* unsigned_word *sp, char **argv, char **envp */ | |
405 | hw_ioctl_change_media, /* const char *new_image (possibly NULL) */ | |
406 | nr_hw_ioctl_requests, | |
407 | } hw_ioctl_request; | |
408 | ||
409 | typedef int (hw_ioctl_method) | |
410 | (struct hw *me, | |
411 | hw_ioctl_request request, | |
412 | va_list ap); | |
413 | ||
414 | int hw_ioctl | |
415 | (struct hw *me, | |
416 | hw_ioctl_request request, | |
417 | ...); | |
418 | ||
419 | ||
420 | /* Error reporting:: | |
421 | ||
422 | So that errors originating from devices appear in a consistent | |
423 | format, the <<hw_abort()>> function can be used. Formats and | |
424 | outputs the error message before aborting the simulation | |
425 | ||
426 | Devices should use this function to abort the simulation except | |
427 | when the abort reason leaves the simulation in a hazardous | |
428 | condition (for instance a failed malloc). | |
429 | ||
430 | */ | |
431 | ||
432 | void hw_abort | |
433 | (struct hw *me, | |
434 | const char *fmt, | |
435 | ...) __attribute__ ((format (printf, 2, 3))); | |
436 | ||
437 | void hw_vabort | |
438 | (struct hw *me, | |
439 | const char *fmt, | |
440 | va_list ap); | |
441 | ||
442 | void hw_halt | |
443 | (struct hw *me, | |
444 | int reason, | |
445 | int status); | |
446 | ||
447 | ||
448 | #define hw_trace_p(hw) ((hw)->trace_of_hw_p + 0) | |
449 | ||
450 | void hw_trace | |
451 | (struct hw *me, | |
452 | const char *fmt, | |
453 | ...) __attribute__ ((format (printf, 2, 3))); | |
454 | ||
455 | #define HW_TRACE(ARGS) \ | |
456 | do { \ | |
457 | if (hw_trace_p (me)) \ | |
458 | { \ | |
459 | hw_trace ARGS; \ | |
460 | } \ | |
461 | } while (0) | |
462 | ||
463 | ||
464 | /* Some of the related functions require specific types */ | |
465 | ||
466 | struct hw_property_data; | |
467 | struct hw_port_data; | |
468 | struct hw_base_data; | |
469 | struct hw_alloc_data; | |
470 | struct hw_event_data; | |
471 | struct hw_handle_data; | |
472 | struct hw_instance_data; | |
473 | ||
474 | /* Finally the hardware device - keep your grubby little mits off of | |
475 | these internals! :-) */ | |
476 | ||
477 | struct hw { | |
478 | ||
479 | /* our relatives */ | |
480 | struct hw *parent_of_hw; | |
481 | struct hw *sibling_of_hw; | |
482 | struct hw *child_of_hw; | |
483 | ||
484 | /* our identity */ | |
485 | const char *name_of_hw; | |
486 | const char *family_of_hw; | |
487 | const char *args_of_hw; | |
488 | const char *path_of_hw; | |
489 | ||
490 | /* our data */ | |
491 | void *data_of_hw; | |
492 | ||
493 | /* hot links */ | |
494 | struct hw *root_of_hw; | |
495 | struct sim_state *system_of_hw; | |
496 | ||
497 | /* identifying data */ | |
498 | hw_unit unit_address_of_hw; | |
499 | int nr_address_cells_of_hw_unit; | |
500 | int nr_size_cells_of_hw_unit; | |
501 | ||
502 | /* Soft reset */ | |
503 | hw_reset_method *to_reset; | |
504 | ||
505 | /* Basic callbacks */ | |
506 | hw_io_read_buffer_method *to_io_read_buffer; | |
507 | hw_io_write_buffer_method *to_io_write_buffer; | |
508 | hw_dma_read_buffer_method *to_dma_read_buffer; | |
509 | hw_dma_write_buffer_method *to_dma_write_buffer; | |
510 | hw_attach_address_method *to_attach_address; | |
511 | hw_detach_address_method *to_detach_address; | |
512 | ||
513 | /* More complicated callbacks */ | |
514 | hw_ioctl_method *to_ioctl; | |
515 | int trace_of_hw_p; | |
516 | ||
517 | /* address callbacks */ | |
518 | hw_unit_decode_method *to_unit_decode; | |
519 | hw_unit_encode_method *to_unit_encode; | |
520 | hw_unit_address_to_attach_address_method *to_unit_address_to_attach_address; | |
521 | hw_unit_size_to_attach_size_method *to_unit_size_to_attach_size; | |
522 | ||
523 | /* related data */ | |
524 | struct hw_property_data *properties_of_hw; | |
525 | struct hw_port_data *ports_of_hw; | |
526 | struct hw_base_data *base_of_hw; | |
527 | struct hw_alloc_data *alloc_of_hw; | |
528 | struct hw_event_data *events_of_hw; | |
529 | struct hw_handle_data *handles_of_hw; | |
530 | struct hw_instance_data *instances_of_hw; | |
531 | ||
532 | }; | |
533 | ||
534 | ||
535 | #endif |