8f88cb3fe4ef80de7436be2dc0e01c0b8eacd023
[platform/upstream/binutils.git] / sim / common / hw-ports.c
1 /* Hardware ports.
2    Copyright (C) 1998, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3    Contributed by Andrew Cagney and Cygnus Solutions.
4
5 This file is part of GDB, the GNU debugger.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20
21 #include "hw-main.h"
22 #include "hw-base.h"
23
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35
36 #include <ctype.h>
37
38
39 struct hw_port_edge {
40   int my_port;
41   struct hw *dest;
42   int dest_port;
43   struct hw_port_edge *next;
44   object_disposition disposition;
45 };
46
47 struct hw_port_data {
48   hw_port_event_method *to_port_event;
49   const struct hw_port_descriptor *ports;
50   struct hw_port_edge *edges;
51 };
52
53 const struct hw_port_descriptor empty_hw_ports[] = {
54   { NULL, },
55 };
56
57 static void
58 panic_hw_port_event (struct hw *me,
59                      int my_port,
60                      struct hw *source,
61                      int source_port,
62                      int level)
63 {
64   hw_abort (me, "no port method");
65 }
66
67 void
68 create_hw_port_data (struct hw *me)
69 {
70   me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data);
71   set_hw_port_event (me, panic_hw_port_event);
72   set_hw_ports (me, empty_hw_ports);
73 }
74
75 void
76 delete_hw_port_data (struct hw *me)
77 {
78   hw_free (me, me->ports_of_hw);
79   me->ports_of_hw = NULL;
80 }
81
82 void
83 set_hw_ports (struct hw *me,
84               const struct hw_port_descriptor ports[])
85 {
86   me->ports_of_hw->ports = ports;
87 }
88
89 void
90 set_hw_port_event (struct hw *me,
91                    hw_port_event_method *port_event)
92 {
93   me->ports_of_hw->to_port_event = port_event;
94 }
95
96
97 static void
98 attach_hw_port_edge (struct hw *me,
99                      struct hw_port_edge **list,
100                      int my_port,
101                      struct hw *dest,
102                      int dest_port,
103                      object_disposition disposition)
104 {
105   struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge);
106   new_edge->my_port = my_port;
107   new_edge->dest = dest;
108   new_edge->dest_port = dest_port;
109   new_edge->next = *list;
110   new_edge->disposition = disposition;
111   *list = new_edge;
112 }
113
114
115 static void
116 detach_hw_port_edge (struct hw *me,
117                      struct hw_port_edge **list,
118                      int my_port,
119                      struct hw *dest,
120                      int dest_port)
121 {
122   while (*list != NULL)
123     {
124       struct hw_port_edge *old_edge = *list;
125       if (old_edge->dest == dest
126           && old_edge->dest_port == dest_port
127           && old_edge->my_port == my_port)
128         {
129           if (old_edge->disposition == permenant_object)
130             hw_abort (me, "attempt to delete permenant port edge");
131           *list = old_edge->next;
132           hw_free (me, old_edge);
133           return;
134         }
135     }
136   hw_abort (me, "attempt to delete unattached port");
137 }
138
139
140 #if 0
141 static void
142 clean_hw_port_edges (struct hw_port_edge **list)
143 {
144   while (*list != NULL)
145     {
146       struct hw_port_edge *old_edge = *list;
147       switch (old_edge->disposition)
148         {
149         case permenant_object:
150           list = &old_edge->next;
151           break;
152         case temporary_object:
153           *list = old_edge->next;
154           hw_free (me, old_edge);
155           break;
156         }
157     }
158 }
159 #endif
160
161
162 /* Ports: */
163
164 void
165 hw_port_event (struct hw *me,
166                int my_port,
167                int level)
168 {
169   int found_an_edge = 0;
170   struct hw_port_edge *edge;
171   /* device's lines directly connected */
172   for (edge = me->ports_of_hw->edges;
173        edge != NULL;
174        edge = edge->next)
175     {
176       if (edge->my_port == my_port)
177         {
178           edge->dest->ports_of_hw->to_port_event (edge->dest,
179                                                   edge->dest_port,
180                                                   me,
181                                                   my_port,
182                                                   level);
183           found_an_edge = 1;
184         }
185     }
186   if (!found_an_edge)
187     hw_abort (me, "No edge for port %d", my_port);
188 }
189
190
191 void
192 hw_port_attach (struct hw *me,
193                 int my_port,
194                 struct hw *dest,
195                 int dest_port,
196                 object_disposition disposition)
197 {
198   attach_hw_port_edge (me,
199                        &me->ports_of_hw->edges,
200                        my_port,
201                        dest,
202                        dest_port,
203                        disposition);
204 }
205
206
207 void
208 hw_port_detach (struct hw *me,
209                 int my_port,
210                 struct hw *dest,
211                 int dest_port)
212 {
213   detach_hw_port_edge (me,
214                        &me->ports_of_hw->edges,
215                        my_port,
216                        dest,
217                        dest_port);
218 }
219
220
221 void
222 hw_port_traverse (struct hw *me,
223                   hw_port_traverse_function *handler,
224                   void *data)
225 {
226   struct hw_port_edge *port_edge;
227   for (port_edge = me->ports_of_hw->edges;
228        port_edge != NULL;
229        port_edge = port_edge->next)
230     {
231       handler (me, port_edge->my_port,
232                port_edge->dest, port_edge->dest_port,
233                data);
234     }
235 }
236
237
238 int
239 hw_port_decode (struct hw *me,
240                 const char *port_name,
241                 port_direction direction)
242 {
243   if (port_name == NULL || port_name[0] == '\0')
244     return 0;
245   if (isdigit(port_name[0]))
246     {
247       return strtoul (port_name, NULL, 0);
248     }
249   else
250     {
251       const struct hw_port_descriptor *ports =
252         me->ports_of_hw->ports;
253       if (ports != NULL) 
254         {
255           while (ports->name != NULL)
256             {
257               if (ports->direction == bidirect_port
258                   || ports->direction == direction)
259                 {
260                   if (ports->nr_ports > 0)
261                     {
262                       int len = strlen (ports->name);
263                       if (strncmp (port_name, ports->name, len) == 0)
264                         {
265                           if (port_name[len] == '\0')
266                             return ports->number;
267                           else if(isdigit (port_name[len]))
268                             {
269                               int port = (ports->number
270                                           + strtoul (&port_name[len], NULL, 0));
271                               if (port >= ports->number + ports->nr_ports)
272                                 hw_abort (me,
273                                           "Port %s out of range",
274                                           port_name);
275                               return port;
276                             }
277                         }
278                     }
279                   else if (strcmp (port_name, ports->name) == 0)
280                     return ports->number;
281                 }
282               ports++;
283             }
284         }
285     }
286   hw_abort (me, "Unreconized port %s", port_name);
287   return 0;
288 }
289
290
291 int
292 hw_port_encode (struct hw *me,
293                 int port_number,
294                 char *buf,
295                 int sizeof_buf,
296                 port_direction direction)
297 {
298   const struct hw_port_descriptor *ports = NULL;
299   ports = me->ports_of_hw->ports;
300   if (ports != NULL) {
301     while (ports->name != NULL)
302       {
303         if (ports->direction == bidirect_port
304             || ports->direction == direction)
305           {
306             if (ports->nr_ports > 0)
307               {
308                 if (port_number >= ports->number
309                     && port_number < ports->number + ports->nr_ports)
310                   {
311                     strcpy (buf, ports->name);
312                     sprintf (buf + strlen(buf), "%d", port_number - ports->number);
313                     if (strlen (buf) >= sizeof_buf)
314                       hw_abort (me, "hw_port_encode: buffer overflow");
315                     return strlen (buf);
316                   }
317               }
318             else
319               {
320                 if (ports->number == port_number)
321                   {
322                     if (strlen(ports->name) >= sizeof_buf)
323                       hw_abort (me, "hw_port_encode: buffer overflow");
324                     strcpy(buf, ports->name);
325                     return strlen(buf);
326                   }
327               }
328           }
329         ports++;
330       }
331   }
332   sprintf (buf, "%d", port_number);
333   if (strlen(buf) >= sizeof_buf)
334     hw_abort (me, "hw_port_encode: buffer overflow");
335   return strlen(buf);
336 }