daily update
[external/binutils.git] / sim / ppc / device_table.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1996, 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 _DEVICE_TABLE_C_
23 #define _DEVICE_TABLE_C_
24
25 #include "device_table.h"
26
27 #if HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30
31 #include <ctype.h>
32
33
34 /* Helper functions */
35
36
37 /* Go through the devices various reg properties for those that
38    specify attach addresses */
39
40
41 void
42 generic_device_init_address(device *me)
43 {
44   static const char *(reg_property_names[]) = {
45     "attach-addresses",
46     "assigned-addresses",
47     "reg",
48     "alternate-reg" ,
49     NULL
50   };
51   const char **reg_property_name;
52   int nr_valid_reg_properties = 0;
53   for (reg_property_name = reg_property_names;
54        *reg_property_name != NULL;
55        reg_property_name++) {
56     if (device_find_property(me, *reg_property_name) != NULL) {
57       reg_property_spec reg;
58       int reg_entry;
59       for (reg_entry = 0;
60            device_find_reg_array_property(me, *reg_property_name, reg_entry,
61                                           &reg);
62            reg_entry++) {
63         unsigned_word attach_address;
64         int attach_space;
65         unsigned attach_size;
66         if (!device_address_to_attach_address(device_parent(me),
67                                               &reg.address,
68                                               &attach_space, &attach_address,
69                                               me))
70           continue;
71         if (!device_size_to_attach_size(device_parent(me),
72                                         &reg.size,
73                                         &attach_size, me))
74           continue;
75         device_attach_address(device_parent(me),
76                               attach_callback,
77                               attach_space, attach_address, attach_size,
78                               access_read_write_exec,
79                               me);
80         nr_valid_reg_properties++;
81       }
82       /* if first option matches don't try for any others */
83       if (reg_property_name == reg_property_names)
84         break;
85     }
86   }
87 }
88
89 int
90 generic_device_unit_decode(device *bus,
91                            const char *unit,
92                            device_unit *phys)
93 {
94   memset(phys, 0, sizeof(device_unit));
95   if (unit == NULL)
96     return 0;
97   else {
98     int nr_cells = 0;
99     const int max_nr_cells = device_nr_address_cells(bus);
100     while (1) {
101       char *end = NULL;
102       unsigned long val;
103       val = strtoul(unit, &end, 0);
104       /* parse error? */
105       if (unit == end)
106         return -1;
107       /* two many cells? */
108       if (nr_cells >= max_nr_cells)
109         return -1;
110       /* save it */
111       phys->cells[nr_cells] = val;
112       nr_cells++;
113       unit = end;
114       /* more to follow? */
115       if (isspace(*unit) || *unit == '\0')
116         break;
117       if (*unit != ',')
118         return -1;
119       unit++;
120     }
121     if (nr_cells < max_nr_cells) {
122       /* shift everything to correct position */
123       int i;
124       for (i = 1; i <= nr_cells; i++)
125         phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
126       for (i = 0; i < (max_nr_cells - nr_cells); i++)
127         phys->cells[i] = 0;
128     }
129     phys->nr_cells = max_nr_cells;
130     return max_nr_cells;
131   }
132 }
133
134 int
135 generic_device_unit_encode(device *bus,
136                            const device_unit *phys,
137                            char *buf,
138                            int sizeof_buf)
139 {
140   int i;
141   int len;
142   char *pos = buf;
143   /* skip leading zero's */
144   for (i = 0; i < phys->nr_cells; i++) {
145     if (phys->cells[i] != 0)
146       break;
147   }
148   /* don't output anything if empty */
149   if (phys->nr_cells == 0) {
150     strcpy(pos, "");
151     len = 0;
152   }
153   else if (i == phys->nr_cells) {
154     /* all zero */
155     strcpy(pos, "0");
156     len = 1;
157   }
158   else {
159     for (; i < phys->nr_cells; i++) {
160       if (pos != buf) {
161         strcat(pos, ",");
162         pos = strchr(pos, '\0');
163       }
164       if (phys->cells[i] < 10)
165         sprintf(pos, "%ld", (unsigned long)phys->cells[i]);
166       else
167         sprintf(pos, "0x%lx", (unsigned long)phys->cells[i]);
168       pos = strchr(pos, '\0');
169     }
170     len = pos - buf;
171   }
172   if (len >= sizeof_buf)
173     error("generic_unit_encode - buffer overflow\n");
174   return len;
175 }
176
177 int
178 generic_device_address_to_attach_address(device *me,
179                                          const device_unit *address,
180                                          int *attach_space,
181                                          unsigned_word *attach_address,
182                                          device *client)
183 {
184   int i;
185   for (i = 0; i < address->nr_cells - 2; i++) {
186     if (address->cells[i] != 0)
187       device_error(me, "Only 32bit addresses supported");
188   }
189   if (address->nr_cells >= 2)
190     *attach_space = address->cells[address->nr_cells - 2];
191   else
192     *attach_space = 0;
193   *attach_address = address->cells[address->nr_cells - 1];
194   return 1;
195 }
196
197 int
198 generic_device_size_to_attach_size(device *me,
199                                    const device_unit *size,
200                                    unsigned *nr_bytes,
201                                    device *client)
202 {
203   int i;
204   for (i = 0; i < size->nr_cells - 1; i++) {
205     if (size->cells[i] != 0)
206       device_error(me, "Only 32bit sizes supported");
207   }
208   *nr_bytes = size->cells[0];
209   return *nr_bytes;
210 }
211
212
213 /* ignore/passthrough versions of each function */
214
215 void
216 passthrough_device_address_attach(device *me,
217                                   attach_type attach,
218                                   int space,
219                                   unsigned_word addr,
220                                   unsigned nr_bytes,
221                                   access_type access,
222                                   device *client) /*callback/default*/
223 {
224   device_attach_address(device_parent(me), attach,
225                         space, addr, nr_bytes,
226                         access,
227                         client);
228 }
229
230 void
231 passthrough_device_address_detach(device *me,
232                                   attach_type attach,
233                                   int space,
234                                   unsigned_word addr,
235                                   unsigned nr_bytes,
236                                   access_type access,
237                                   device *client) /*callback/default*/
238 {
239   device_detach_address(device_parent(me), attach,
240                         space, addr, nr_bytes, access,
241                         client);
242 }
243
244 unsigned
245 passthrough_device_dma_read_buffer(device *me,
246                                    void *dest,
247                                    int space,
248                                    unsigned_word addr,
249                                    unsigned nr_bytes)
250 {
251   return device_dma_read_buffer(device_parent(me), dest,
252                                 space, addr, nr_bytes);
253 }
254
255 unsigned
256 passthrough_device_dma_write_buffer(device *me,
257                              const void *source,
258                              int space,
259                              unsigned_word addr,
260                              unsigned nr_bytes,
261                              int violate_read_only_section)
262 {
263   return device_dma_write_buffer(device_parent(me), source,
264                                  space, addr,
265                                  nr_bytes,
266                                  violate_read_only_section);
267 }
268
269 int
270 ignore_device_unit_decode(device *me,
271                           const char *unit,
272                           device_unit *phys)
273 {
274   memset(phys, 0, sizeof(device_unit));
275   return 0;
276 }
277
278
279 static const device_callbacks passthrough_callbacks = {
280   { NULL, }, /* init */
281   { passthrough_device_address_attach,
282     passthrough_device_address_detach, },
283   { NULL, }, /* IO */
284   { passthrough_device_dma_read_buffer, passthrough_device_dma_write_buffer, },
285   { NULL, }, /* interrupt */
286   { generic_device_unit_decode,
287     generic_device_unit_encode, },
288 };
289
290
291 static const device_descriptor ob_device_table[] = {
292   /* standard OpenBoot devices */
293   { "aliases", NULL, &passthrough_callbacks },
294   { "options", NULL, &passthrough_callbacks },
295   { "chosen", NULL, &passthrough_callbacks },
296   { "packages", NULL, &passthrough_callbacks },
297   { "cpus", NULL, &passthrough_callbacks },
298   { "openprom", NULL, &passthrough_callbacks },
299   { "init", NULL, &passthrough_callbacks },
300   { NULL },
301 };
302
303 const device_descriptor *const device_table[] = {
304   ob_device_table,
305 #include "hw.c"
306   NULL,
307 };
308
309
310 #endif /* _DEVICE_TABLE_C_ */