1 /* Hardware ports.
2    Copyright (C) 1998-2024 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 /* This must come before any other includes.  */
21 #include "defs.h"
22 
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "hw-main.h"
28 #include "hw-base.h"
29 
30 struct hw_port_edge
31 {
32   int my_port;
33   struct hw *dest;
34   int dest_port;
35   struct hw_port_edge *next;
36   object_disposition disposition;
37 };
38 
39 struct hw_port_data
40 {
41   hw_port_event_method *to_port_event;
42   const struct hw_port_descriptor *ports;
43   struct hw_port_edge *edges;
44 };
45 
46 const struct hw_port_descriptor empty_hw_ports[] =
47 {
48   { NULL, 0, 0, 0 },
49 };
50 
51 static void
panic_hw_port_event(struct hw * me,int my_port,struct hw * source,int source_port,int level)52 panic_hw_port_event (struct hw *me,
53                          int my_port,
54                          struct hw *source,
55                          int source_port,
56                          int level)
57 {
58   hw_abort (me, "no port method");
59 }
60 
61 void
create_hw_port_data(struct hw * me)62 create_hw_port_data (struct hw *me)
63 {
64   me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data);
65   set_hw_port_event (me, panic_hw_port_event);
66   set_hw_ports (me, empty_hw_ports);
67 }
68 
69 void
delete_hw_port_data(struct hw * me)70 delete_hw_port_data (struct hw *me)
71 {
72   hw_free (me, me->ports_of_hw);
73   me->ports_of_hw = NULL;
74 }
75 
76 void
set_hw_ports(struct hw * me,const struct hw_port_descriptor ports[])77 set_hw_ports (struct hw *me,
78                 const struct hw_port_descriptor ports[])
79 {
80   me->ports_of_hw->ports = ports;
81 }
82 
83 void
set_hw_port_event(struct hw * me,hw_port_event_method * port_event)84 set_hw_port_event (struct hw *me,
85                        hw_port_event_method *port_event)
86 {
87   me->ports_of_hw->to_port_event = port_event;
88 }
89 
90 
91 static void
attach_hw_port_edge(struct hw * me,struct hw_port_edge ** list,int my_port,struct hw * dest,int dest_port,object_disposition disposition)92 attach_hw_port_edge (struct hw *me,
93                          struct hw_port_edge **list,
94                          int my_port,
95                          struct hw *dest,
96                          int dest_port,
97                          object_disposition disposition)
98 {
99   struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge);
100   new_edge->my_port = my_port;
101   new_edge->dest = dest;
102   new_edge->dest_port = dest_port;
103   new_edge->next = *list;
104   new_edge->disposition = disposition;
105   *list = new_edge;
106 }
107 
108 
109 static void
detach_hw_port_edge(struct hw * me,struct hw_port_edge ** list,int my_port,struct hw * dest,int dest_port)110 detach_hw_port_edge (struct hw *me,
111                          struct hw_port_edge **list,
112                          int my_port,
113                          struct hw *dest,
114                          int dest_port)
115 {
116   while (*list != NULL)
117     {
118       struct hw_port_edge *old_edge = *list;
119       if (old_edge->dest == dest
120             && old_edge->dest_port == dest_port
121             && old_edge->my_port == my_port)
122           {
123             if (old_edge->disposition == permanent_object)
124               hw_abort (me, "attempt to delete permanent port edge");
125             *list = old_edge->next;
126             hw_free (me, old_edge);
127             return;
128           }
129     }
130   hw_abort (me, "attempt to delete unattached port");
131 }
132 
133 
134 #if 0
135 static void
136 clean_hw_port_edges (struct hw_port_edge **list)
137 {
138   while (*list != NULL)
139     {
140       struct hw_port_edge *old_edge = *list;
141       switch (old_edge->disposition)
142           {
143           case permanent_object:
144             list = &old_edge->next;
145             break;
146           case temporary_object:
147             *list = old_edge->next;
148             hw_free (me, old_edge);
149             break;
150           }
151     }
152 }
153 #endif
154 
155 
156 /* Ports: */
157 
158 void
hw_port_event(struct hw * me,int my_port,int level)159 hw_port_event (struct hw *me,
160                  int my_port,
161                  int level)
162 {
163   int found_an_edge = 0;
164   struct hw_port_edge *edge;
165   /* device's lines directly connected */
166   for (edge = me->ports_of_hw->edges;
167        edge != NULL;
168        edge = edge->next)
169     {
170       if (edge->my_port == my_port)
171           {
172             edge->dest->ports_of_hw->to_port_event (edge->dest,
173                                                               edge->dest_port,
174                                                               me,
175                                                               my_port,
176                                                               level);
177             found_an_edge = 1;
178           }
179     }
180   if (!found_an_edge)
181     hw_abort (me, "No edge for port %d", my_port);
182 }
183 
184 
185 void
hw_port_attach(struct hw * me,int my_port,struct hw * dest,int dest_port,object_disposition disposition)186 hw_port_attach (struct hw *me,
187                     int my_port,
188                     struct hw *dest,
189                     int dest_port,
190                     object_disposition disposition)
191 {
192   attach_hw_port_edge (me,
193                            &me->ports_of_hw->edges,
194                            my_port,
195                            dest,
196                            dest_port,
197                            disposition);
198 }
199 
200 
201 void
hw_port_detach(struct hw * me,int my_port,struct hw * dest,int dest_port)202 hw_port_detach (struct hw *me,
203                     int my_port,
204                     struct hw *dest,
205                     int dest_port)
206 {
207   detach_hw_port_edge (me,
208                            &me->ports_of_hw->edges,
209                            my_port,
210                            dest,
211                            dest_port);
212 }
213 
214 
215 void
hw_port_traverse(struct hw * me,hw_port_traverse_function * handler,void * data)216 hw_port_traverse (struct hw *me,
217                       hw_port_traverse_function *handler,
218                       void *data)
219 {
220   struct hw_port_edge *port_edge;
221   for (port_edge = me->ports_of_hw->edges;
222        port_edge != NULL;
223        port_edge = port_edge->next)
224     {
225       handler (me, port_edge->my_port,
226                  port_edge->dest, port_edge->dest_port,
227                  data);
228     }
229 }
230 
231 
232 int
hw_port_decode(struct hw * me,const char * port_name,port_direction direction)233 hw_port_decode (struct hw *me,
234                     const char *port_name,
235                     port_direction direction)
236 {
237   if (port_name == NULL || port_name[0] == '\0')
238     return 0;
239   if (isdigit (port_name[0]))
240     {
241       return strtoul (port_name, NULL, 0);
242     }
243   else
244     {
245       const struct hw_port_descriptor *ports =
246           me->ports_of_hw->ports;
247       if (ports != NULL)
248           {
249             while (ports->name != NULL)
250               {
251                 if (ports->direction == bidirect_port
252                       || ports->direction == direction)
253                     {
254                       if (ports->nr_ports > 0)
255                         {
256                           int len = strlen (ports->name);
257                           if (strncmp (port_name, ports->name, len) == 0)
258                               {
259                                 if (port_name[len] == '\0')
260                                   return ports->number;
261                                 else if (isdigit (port_name[len]))
262                                   {
263                                     int port = (ports->number
264                                                     + strtoul (&port_name[len], NULL, 0));
265                                     if (port >= ports->number + ports->nr_ports)
266                                         hw_abort (me,
267                                                     "Port %s out of range",
268                                                     port_name);
269                                     return port;
270                                   }
271                               }
272                         }
273                       else if (strcmp (port_name, ports->name) == 0)
274                         return ports->number;
275                     }
276                 ports++;
277               }
278           }
279     }
280   hw_abort (me, "Unrecognized port %s", port_name);
281   return 0;
282 }
283 
284 
285 int
hw_port_encode(struct hw * me,int port_number,char * buf,int sizeof_buf,port_direction direction)286 hw_port_encode (struct hw *me,
287                     int port_number,
288                     char *buf,
289                     int sizeof_buf,
290                     port_direction direction)
291 {
292   const struct hw_port_descriptor *ports = NULL;
293   ports = me->ports_of_hw->ports;
294   if (ports != NULL) {
295     while (ports->name != NULL)
296       {
297           if (ports->direction == bidirect_port
298               || ports->direction == direction)
299             {
300               if (ports->nr_ports > 0)
301                 {
302                     if (port_number >= ports->number
303                         && port_number < ports->number + ports->nr_ports)
304                       {
305                         strcpy (buf, ports->name);
306                         sprintf (buf + strlen (buf), "%d", port_number - ports->number);
307                         if (strlen (buf) >= sizeof_buf)
308                           hw_abort (me, "hw_port_encode: buffer overflow");
309                         return strlen (buf);
310                       }
311                 }
312               else
313                 {
314                     if (ports->number == port_number)
315                       {
316                         if (strlen (ports->name) >= sizeof_buf)
317                           hw_abort (me, "hw_port_encode: buffer overflow");
318                         strcpy (buf, ports->name);
319                         return strlen (buf);
320                       }
321                 }
322             }
323           ports++;
324       }
325   }
326   sprintf (buf, "%d", port_number);
327   if (strlen (buf) >= sizeof_buf)
328     hw_abort (me, "hw_port_encode: buffer overflow");
329   return strlen (buf);
330 }
331