Commit | Line | Data |
---|---|---|
b1e9223c AC |
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 + 0) | |
143 | ||
144 | /* Device private data */ | |
145 | ||
146 | #define hw_data(hw) ((hw)->data_of_hw) | |
147 | ||
148 | ||
149 | \f | |
150 | /* Perform a soft reset of the device */ | |
151 | ||
152 | typedef unsigned (hw_reset_callback) | |
153 | (struct hw *me); | |
154 | ||
155 | #define hw_reset(hw) ((hw)->to_reset (hw)) | |
156 | ||
157 | \f | |
158 | /* Hardware operations: | |
159 | ||
160 | Connecting a parent to its children is a common bus. The parent | |
161 | node is described as the bus owner and is responisble for | |
162 | co-ordinating bus operations. On the bus, a SPACE:ADDR pair is used | |
163 | to specify an address. A device that is both a bus owner (parent) | |
164 | and bus client (child) are refered to as a bridging device. | |
165 | ||
166 | A child performing a data (DMA) transfer will pass its request to | |
167 | the bus owner (the devices parent). The bus owner will then either | |
168 | reflect the request to one of the other devices attached to the bus | |
169 | (a child of the bus owner) or bridge the request up the tree to the | |
170 | next bus. */ | |
171 | ||
172 | ||
173 | /* Children attached to a bus can register (attach) themselves to | |
174 | specific addresses on their attached bus. | |
175 | ||
176 | (A device may also be implicitly attached to certain bus | |
177 | addresses). | |
178 | ||
179 | The SPACE:ADDR pair specify an address on the common bus that | |
180 | connects the parent and child devices. */ | |
181 | ||
182 | typedef void (hw_attach_address_callback) | |
183 | (struct hw *me, | |
184 | int level, | |
185 | int space, | |
186 | address_word addr, | |
187 | address_word nr_bytes, | |
188 | struct hw *client); /*callback/default*/ | |
189 | ||
190 | #define hw_attach_address(me, level, space, addr, nr_bytes, client) \ | |
191 | ((me)->to_attach_address (me, level, space, addr, nr_bytes, client)) | |
192 | ||
193 | ||
194 | typedef void (hw_detach_address_callback) | |
195 | (struct hw *me, | |
196 | int level, | |
197 | int space, | |
198 | address_word addr, | |
199 | address_word nr_bytes, | |
200 | struct hw *client); /*callback/default*/ | |
201 | ||
202 | #define hw_detach_address(me, level, space, addr, nr_bytes, client) \ | |
203 | ((me)->to_detach_address (me, level, space, addr, nr_bytes, client)) | |
204 | ||
205 | ||
206 | /* An IO operation from a parent to a child via the conecting bus. | |
207 | ||
208 | The SPACE:ADDR pair specify an address on the bus shared between | |
209 | the parent and child devices. */ | |
210 | ||
211 | typedef unsigned (hw_io_read_buffer_callback) | |
212 | (struct hw *me, | |
213 | void *dest, | |
214 | int space, | |
215 | unsigned_word addr, | |
216 | unsigned nr_bytes, | |
217 | sim_cpu *processor, | |
218 | sim_cia cia); | |
219 | ||
220 | #define hw_io_read_buffer(hw, dest, space, addr, nr_bytes, processor, cia) \ | |
221 | ((hw)->to_io_read_buffer (hw, dest, space, addr, nr_bytes, processor, cia)) | |
222 | ||
223 | typedef unsigned (hw_io_write_buffer_callback) | |
224 | (struct hw *me, | |
225 | const void *source, | |
226 | int space, | |
227 | unsigned_word addr, | |
228 | unsigned nr_bytes, | |
229 | sim_cpu *processor, | |
230 | sim_cia cia); | |
231 | ||
232 | #define hw_io_write_buffer(hw, src, space, addr, nr_bytes, processor, cia) \ | |
233 | ((hw)->to_io_write_buffer (hw, src, space, addr, nr_bytes, processor, cia)) | |
234 | ||
235 | ||
236 | ||
237 | /* Conversly, the device pci1000,1@1 may need to perform a dma transfer | |
238 | into the cpu/memory core. Just as I/O moves towards the leaves, | |
239 | dma transfers move towards the core via the initiating devices | |
240 | parent nodes. The root device (special) converts the DMA transfer | |
241 | into reads/writes to memory. | |
242 | ||
243 | The SPACE:ADDR pair specify an address on the common bus connecting | |
244 | the parent and child devices. */ | |
245 | ||
246 | typedef unsigned (hw_dma_read_buffer_callback) | |
247 | (struct hw *bus, | |
248 | void *dest, | |
249 | int space, | |
250 | unsigned_word addr, | |
251 | unsigned nr_bytes); | |
252 | ||
253 | #define hw_dma_read_buffer(bus, dest, space, addr, nr_bytes) \ | |
254 | ((bus)->to_dma_read_buffer (bus, dest, space, addr, nr_bytes)) | |
255 | ||
256 | typedef unsigned (hw_dma_write_buffer_callback) | |
257 | (struct hw *bus, | |
258 | const void *source, | |
259 | int space, | |
260 | unsigned_word addr, | |
261 | unsigned nr_bytes, | |
262 | int violate_read_only_section); | |
263 | ||
264 | #define hw_dma_write_buffer(bus, src, space, addr, nr_bytes, violate_ro) \ | |
265 | ((bus)->to_dma_write_buffer (bus, src, space, addr, nr_bytes, violate_ro)) | |
266 | \f | |
267 | /* Address/size specs for devices are encoded following a convention | |
268 | similar to that used by OpenFirmware. In particular, an | |
269 | address/size is packed into a sequence of up to four cell words. | |
270 | The number of words determined by the number of {address,size} | |
271 | cells attributes of the device. */ | |
272 | ||
273 | typedef struct _hw_unit { | |
274 | int nr_cells; | |
275 | unsigned_cell cells[4]; /* unused cells are zero */ | |
276 | } hw_unit; | |
277 | ||
278 | ||
279 | /* For the given bus, the number of address and size cells used in a | |
280 | hw_unit. */ | |
281 | ||
282 | #define hw_unit_nr_address_cells(bus) ((bus)->nr_address_cells_of_hw_unit + 0) | |
283 | ||
284 | #define hw_unit_nr_size_cells(bus) ((bus)->nr_size_cells_of_hw_unit + 0) | |
285 | ||
286 | ||
287 | /* For the given device, its identifying hw_unit address. | |
288 | ||
289 | Each device has an identifying hw_unit address. That address is | |
290 | used when identifying one of a number of identical devices on a | |
291 | common controller bus. ex fd0&fd1. */ | |
292 | ||
293 | const hw_unit *hw_unit_address | |
294 | (struct hw *me); | |
295 | ||
296 | ||
297 | /* Convert between a textual and the internal representation of a | |
298 | hw_unit address/size. | |
299 | ||
300 | NOTE: A device asks its parent to translate between a hw_unit and | |
301 | textual representation. This is because the textual address of a | |
302 | device is specified using the parent busses notation. */ | |
303 | ||
304 | typedef int (hw_unit_decode_callback) | |
305 | (struct hw *bus, | |
306 | const char *encoded, | |
307 | hw_unit *unit); | |
308 | ||
309 | #define hw_unit_decode(bus, encoded, unit) \ | |
310 | ((bus)->to_unit_decode (bus, encoded, unit)) | |
311 | ||
312 | ||
313 | typedef int (hw_unit_encode_callback) | |
314 | (struct hw *bus, | |
315 | const hw_unit *unit, | |
316 | char *encoded, | |
317 | int sizeof_buf); | |
318 | ||
319 | #define hw_unit_encode(bus, unit, encoded, sizeof_encoded) \ | |
320 | ((bus)->to_unit_encode (bus, unit, encoded, sizeof_encoded)) | |
321 | ||
322 | ||
323 | ||
324 | /* As the bus that the device is attached too, to translate a devices | |
325 | hw_unit address/size into a form suitable for an attach address | |
326 | call. | |
327 | ||
328 | Return a zero result if the address should be ignored when looking | |
329 | for attach addresses. */ | |
330 | ||
331 | typedef int (hw_unit_address_to_attach_address_callback) | |
332 | (struct hw *bus, | |
333 | const hw_unit *unit_addr, | |
334 | int *attach_space, | |
335 | unsigned_word *attach_addr, | |
336 | struct hw *client); | |
337 | ||
338 | #define hw_unit_address_to_attach_address(bus, unit_addr, attach_space, attach_addr, client) \ | |
339 | ((bus)->to_unit_address_to_attach_address (bus, unit_addr, attach_space, attach_addr, client)) | |
340 | ||
341 | ||
342 | typedef int (hw_unit_size_to_attach_size_callback) | |
343 | (struct hw *bus, | |
344 | const hw_unit *unit_size, | |
345 | unsigned *attach_size, | |
346 | struct hw *client); | |
347 | ||
348 | #define hw_unit_size_to_attach_size(bus, unit_size, attach_size, client) \ | |
349 | ((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client)) | |
350 | ||
351 | ||
e5f0d498 AC |
352 | \f |
353 | /* Memory allocator / de-allocator. | |
354 | ||
355 | All memory allocated using the below will be automatically | |
356 | reclaimed when the device is deleted. | |
357 | ||
358 | A device implementation can either use these functions when | |
359 | allocating memory or use malloc/zalloc/free an co-ordinate its own | |
360 | garbage collection. */ | |
361 | ||
362 | #define HW_ZALLOC(me,type) (type*) hw_zalloc (me, sizeof (type)) | |
363 | #define HW_MALLOC(me,type) (type*) hw_malloc (me, sizeof (type)) | |
364 | ||
365 | extern void *hw_zalloc (struct hw *me, unsigned long size); | |
366 | extern void *hw_malloc (struct hw *me, unsigned long size); | |
367 | extern void hw_free (struct hw *me, void *); | |
368 | extern void hw_free_all (struct hw *me); | |
369 | ||
370 | ||
b1e9223c AC |
371 | \f |
372 | /* Utilities: | |
373 | ||
374 | */ | |
375 | ||
376 | /* IOCTL:: | |
377 | ||
378 | Often devices require `out of band' operations to be performed. | |
379 | For instance a pal device may need to notify a PCI bridge device | |
380 | that an interrupt ack cycle needs to be performed on the PCI bus. | |
381 | Within PSIM such operations are performed by using the generic | |
382 | ioctl call <<hw_ioctl()>>. | |
383 | ||
384 | */ | |
385 | ||
386 | typedef enum { | |
387 | hw_ioctl_break, /* unsigned_word requested_break */ | |
388 | hw_ioctl_set_trace, /* void */ | |
389 | hw_ioctl_create_stack, /* unsigned_word *sp, char **argv, char **envp */ | |
390 | hw_ioctl_change_media, /* const char *new_image (possibly NULL) */ | |
391 | nr_hw_ioctl_requests, | |
392 | } hw_ioctl_request; | |
393 | ||
394 | typedef int (hw_ioctl_callback) | |
395 | (struct hw *me, | |
396 | sim_cpu *processor, | |
397 | sim_cia cia, | |
398 | hw_ioctl_request request, | |
399 | va_list ap); | |
400 | ||
401 | int hw_ioctl | |
402 | (struct hw *me, | |
403 | sim_cpu *processor, | |
404 | sim_cia cia, | |
405 | hw_ioctl_request request, | |
406 | ...); | |
407 | ||
408 | ||
409 | /* Event queue: | |
410 | ||
411 | Device specific versions of certain event handlers */ | |
412 | ||
413 | typedef struct _hw_event hw_event; | |
414 | typedef void (hw_event_handler) (struct hw *me, void *data); | |
415 | ||
416 | hw_event *hw_event_queue_schedule | |
417 | (struct hw *me, | |
418 | signed64 delta_time, | |
419 | hw_event_handler *handler, | |
420 | void *data); | |
421 | ||
422 | void hw_event_queue_deschedule | |
423 | (struct hw *me, | |
424 | hw_event *event_to_remove); | |
425 | ||
426 | signed64 hw_event_queue_time | |
427 | (struct hw *me); | |
428 | ||
429 | ||
430 | ||
431 | /* Error reporting:: | |
432 | ||
433 | So that errors originating from devices appear in a consistent | |
434 | format, the <<hw_abort()>> function can be used. Formats and | |
435 | outputs the error message before aborting the simulation | |
436 | ||
437 | Devices should use this function to abort the simulation except | |
438 | when the abort reason leaves the simulation in a hazardous | |
439 | condition (for instance a failed malloc). | |
440 | ||
441 | */ | |
442 | ||
443 | void volatile NORETURN hw_abort | |
444 | (struct hw *me, | |
445 | const char *fmt, | |
446 | ...) __attribute__ ((format (printf, 2, 3))); | |
447 | ||
448 | #define hw_trace_p(hw) ((hw)->trace_of_hw_p + 0) | |
449 | ||
937a4bdc AC |
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) | |
b1e9223c AC |
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; | |
e5f0d498 | 469 | struct hw_alloc_data; |
b1e9223c AC |
470 | |
471 | /* Finally the hardware device - keep your grubby little mits off of | |
472 | these internals! :-) */ | |
473 | ||
474 | struct hw { | |
475 | ||
476 | /* our relatives */ | |
477 | struct hw *parent_of_hw; | |
478 | struct hw *sibling_of_hw; | |
479 | struct hw *child_of_hw; | |
480 | ||
481 | /* our identity */ | |
482 | const char *name_of_hw; | |
483 | const char *family_of_hw; | |
484 | const char *args_of_hw; | |
485 | const char *path_of_hw; | |
486 | ||
487 | /* our data */ | |
488 | void *data_of_hw; | |
489 | ||
490 | /* hot links */ | |
491 | struct hw *root_of_hw; | |
492 | SIM_DESC system_of_hw; | |
493 | ||
494 | /* identifying data */ | |
495 | hw_unit unit_address_of_hw; | |
496 | int nr_address_cells_of_hw_unit; | |
497 | int nr_size_cells_of_hw_unit; | |
498 | ||
499 | /* Soft reset */ | |
500 | hw_reset_callback *to_reset; | |
501 | ||
502 | /* Basic callbacks */ | |
503 | hw_io_read_buffer_callback *to_io_read_buffer; | |
504 | hw_io_write_buffer_callback *to_io_write_buffer; | |
505 | hw_dma_read_buffer_callback *to_dma_read_buffer; | |
506 | hw_dma_write_buffer_callback *to_dma_write_buffer; | |
507 | hw_attach_address_callback *to_attach_address; | |
508 | hw_detach_address_callback *to_detach_address; | |
509 | ||
510 | /* More complicated callbacks */ | |
511 | hw_ioctl_callback *to_ioctl; | |
512 | int trace_of_hw_p; | |
513 | ||
514 | /* address callbacks */ | |
515 | hw_unit_decode_callback *to_unit_decode; | |
516 | hw_unit_encode_callback *to_unit_encode; | |
517 | hw_unit_address_to_attach_address_callback *to_unit_address_to_attach_address; | |
518 | hw_unit_size_to_attach_size_callback *to_unit_size_to_attach_size; | |
519 | ||
520 | /* related data */ | |
521 | struct hw_property_data *properties_of_hw; | |
522 | struct hw_port_data *ports_of_hw; | |
523 | struct hw_base_data *base_of_hw; | |
e5f0d498 | 524 | struct hw_alloc_data *alloc_of_hw; |
b1e9223c AC |
525 | |
526 | }; | |
527 | ||
528 | ||
529 | #endif |