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