]>
Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* This file is part of the program GDB, the GNU debugger. |
2 | ||
213516ef | 3 | Copyright (C) 1998-2023 Free Software Foundation, Inc. |
c906108c SS |
4 | Contributed by Cygnus Solutions. |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
4744ac1b | 8 | the Free Software Foundation; either version 3 of the License, or |
c906108c | 9 | (at your option) any later version. |
4744ac1b | 10 | |
c906108c SS |
11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
4744ac1b | 15 | |
c906108c | 16 | You should have received a copy of the GNU General Public License |
4744ac1b | 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
c906108c SS |
18 | |
19 | */ | |
20 | ||
6df01ab8 MF |
21 | /* This must come before any other includes. */ |
22 | #include "defs.h" | |
23 | ||
c906108c SS |
24 | #include "sim-main.h" |
25 | #include "hw-main.h" | |
26 | ||
27 | /* DEVICE | |
28 | ||
29 | ||
30 | mn103iop - mn103002 I/O ports 0-3. | |
31 | ||
32 | ||
33 | DESCRIPTION | |
34 | ||
35 | Implements the mn103002 i/o ports as described in the mn103002 user guide. | |
36 | ||
37 | ||
38 | PROPERTIES | |
39 | ||
40 | reg = <ioport-addr> <ioport-size> ... | |
41 | ||
42 | ||
43 | BUGS | |
44 | ||
45 | */ | |
46 | ||
47 | ||
48 | /* The I/O ports' registers' address block */ | |
49 | ||
50 | struct mn103iop_block { | |
51 | unsigned_word base; | |
52 | unsigned_word bound; | |
53 | }; | |
54 | ||
55 | ||
56 | ||
57 | enum io_port_register_types { | |
58 | P0OUT, | |
59 | P1OUT, | |
60 | P2OUT, | |
61 | P3OUT, | |
62 | P0MD, | |
63 | P1MD, | |
64 | P2MD, | |
65 | P3MD, | |
66 | P2SS, | |
67 | P4SS, | |
68 | P0DIR, | |
69 | P1DIR, | |
70 | P2DIR, | |
71 | P3DIR, | |
72 | P0IN, | |
73 | P1IN, | |
74 | P2IN, | |
75 | P3IN, | |
76 | }; | |
77 | ||
78 | #define NR_PORTS 4 | |
79 | ||
80 | enum { | |
81 | OUTPUT_BLOCK, | |
82 | MODE_BLOCK, | |
83 | DED_CTRL_BLOCK, | |
84 | CTRL_BLOCK, | |
85 | PIN_BLOCK, | |
86 | NR_BLOCKS | |
87 | }; | |
88 | ||
89 | typedef struct _mn10300_ioport { | |
74ccc978 | 90 | uint8_t output, output_mode, control, pin; |
c906108c SS |
91 | struct hw_event *event; |
92 | } mn10300_ioport; | |
93 | ||
94 | ||
95 | ||
96 | struct mn103iop { | |
97 | struct mn103iop_block block[NR_BLOCKS]; | |
98 | mn10300_ioport port[NR_PORTS]; | |
74ccc978 | 99 | uint8_t p2ss, p4ss; |
c906108c SS |
100 | }; |
101 | ||
102 | ||
103 | /* Finish off the partially created hw device. Attach our local | |
104 | callbacks. Wire up our port names etc */ | |
105 | ||
106 | static hw_io_read_buffer_method mn103iop_io_read_buffer; | |
107 | static hw_io_write_buffer_method mn103iop_io_write_buffer; | |
108 | ||
109 | static void | |
110 | attach_mn103iop_regs (struct hw *me, | |
111 | struct mn103iop *io_port) | |
112 | { | |
113 | int i; | |
114 | unsigned_word attach_address; | |
115 | int attach_space; | |
116 | unsigned attach_size; | |
117 | reg_property_spec reg; | |
118 | ||
119 | if (hw_find_property (me, "reg") == NULL) | |
120 | hw_abort (me, "Missing \"reg\" property"); | |
121 | ||
122 | for (i=0; i < NR_BLOCKS; ++i ) | |
123 | { | |
124 | if (!hw_find_reg_array_property (me, "reg", i, ®)) | |
125 | hw_abort (me, "\"reg\" property must contain five addr/size entries"); | |
126 | hw_unit_address_to_attach_address (hw_parent (me), | |
127 | ®.address, | |
128 | &attach_space, | |
129 | &attach_address, | |
130 | me); | |
131 | io_port->block[i].base = attach_address; | |
132 | hw_unit_size_to_attach_size (hw_parent (me), | |
133 | ®.size, | |
134 | &attach_size, me); | |
135 | io_port->block[i].bound = attach_address + (attach_size - 1); | |
136 | hw_attach_address (hw_parent (me), | |
137 | 0, | |
138 | attach_space, attach_address, attach_size, | |
139 | me); | |
140 | } | |
141 | } | |
142 | ||
143 | static void | |
144 | mn103iop_finish (struct hw *me) | |
145 | { | |
146 | struct mn103iop *io_port; | |
147 | int i; | |
148 | ||
149 | io_port = HW_ZALLOC (me, struct mn103iop); | |
150 | set_hw_data (me, io_port); | |
151 | set_hw_io_read_buffer (me, mn103iop_io_read_buffer); | |
152 | set_hw_io_write_buffer (me, mn103iop_io_write_buffer); | |
153 | ||
154 | /* Attach ourself to our parent bus */ | |
155 | attach_mn103iop_regs (me, io_port); | |
156 | ||
157 | /* Initialize the i/o port registers. */ | |
158 | for ( i=0; i<NR_PORTS; ++i ) | |
159 | { | |
160 | io_port->port[i].output = 0; | |
161 | io_port->port[i].output_mode = 0; | |
162 | io_port->port[i].control = 0; | |
163 | io_port->port[i].pin = 0; | |
164 | } | |
165 | io_port->port[2].output_mode = 0xff; | |
166 | io_port->p2ss = 0; | |
167 | io_port->p4ss = 0x0f; | |
168 | } | |
169 | ||
170 | ||
171 | /* read and write */ | |
172 | ||
173 | static int | |
174 | decode_addr (struct hw *me, | |
175 | struct mn103iop *io_port, | |
176 | unsigned_word address) | |
177 | { | |
178 | unsigned_word offset; | |
179 | offset = address - io_port->block[0].base; | |
180 | switch (offset) | |
181 | { | |
182 | case 0x00: return P0OUT; | |
183 | case 0x01: return P1OUT; | |
184 | case 0x04: return P2OUT; | |
185 | case 0x05: return P3OUT; | |
186 | case 0x20: return P0MD; | |
187 | case 0x21: return P1MD; | |
188 | case 0x24: return P2MD; | |
189 | case 0x25: return P3MD; | |
190 | case 0x44: return P2SS; | |
191 | case 0x48: return P4SS; | |
192 | case 0x60: return P0DIR; | |
193 | case 0x61: return P1DIR; | |
194 | case 0x64: return P2DIR; | |
195 | case 0x65: return P3DIR; | |
196 | case 0x80: return P0IN; | |
197 | case 0x81: return P1IN; | |
198 | case 0x84: return P2IN; | |
199 | case 0x85: return P3IN; | |
200 | default: | |
201 | { | |
202 | hw_abort (me, "bad address"); | |
203 | return -1; | |
204 | } | |
205 | } | |
206 | } | |
207 | ||
208 | ||
209 | static void | |
210 | read_output_reg (struct hw *me, | |
211 | struct mn103iop *io_port, | |
212 | unsigned_word io_port_reg, | |
213 | const void *dest, | |
214 | unsigned nr_bytes) | |
215 | { | |
216 | if ( nr_bytes == 1 ) | |
217 | { | |
74ccc978 | 218 | *(uint8_t *)dest = io_port->port[io_port_reg].output; |
c906108c SS |
219 | } |
220 | else | |
221 | { | |
222 | hw_abort (me, "bad read size of %d bytes from P%dOUT.", nr_bytes, | |
223 | io_port_reg); | |
224 | } | |
225 | } | |
226 | ||
227 | ||
228 | static void | |
229 | read_output_mode_reg (struct hw *me, | |
230 | struct mn103iop *io_port, | |
231 | unsigned_word io_port_reg, | |
232 | const void *dest, | |
233 | unsigned nr_bytes) | |
234 | { | |
235 | if ( nr_bytes == 1 ) | |
236 | { | |
237 | /* check if there are fields which can't be written and | |
238 | take appropriate action depending what bits are set */ | |
74ccc978 | 239 | *(uint8_t *)dest = io_port->port[io_port_reg].output_mode; |
c906108c SS |
240 | } |
241 | else | |
242 | { | |
243 | hw_abort (me, "bad read size of %d bytes to P%dMD.", nr_bytes, | |
244 | io_port_reg); | |
245 | } | |
246 | } | |
247 | ||
248 | ||
249 | static void | |
250 | read_control_reg (struct hw *me, | |
251 | struct mn103iop *io_port, | |
252 | unsigned_word io_port_reg, | |
253 | const void *dest, | |
254 | unsigned nr_bytes) | |
255 | { | |
256 | if ( nr_bytes == 1 ) | |
257 | { | |
74ccc978 | 258 | *(uint8_t *)dest = io_port->port[io_port_reg].control; |
c906108c SS |
259 | } |
260 | else | |
261 | { | |
262 | hw_abort (me, "bad read size of %d bytes to P%dDIR.", nr_bytes, | |
263 | io_port_reg); | |
264 | } | |
265 | } | |
266 | ||
267 | ||
268 | static void | |
269 | read_pin_reg (struct hw *me, | |
270 | struct mn103iop *io_port, | |
271 | unsigned_word io_port_reg, | |
272 | const void *dest, | |
273 | unsigned nr_bytes) | |
274 | { | |
275 | if ( nr_bytes == 1 ) | |
276 | { | |
74ccc978 | 277 | *(uint8_t *)dest = io_port->port[io_port_reg].pin; |
c906108c SS |
278 | } |
279 | else | |
280 | { | |
281 | hw_abort (me, "bad read size of %d bytes to P%dIN.", nr_bytes, | |
282 | io_port_reg); | |
283 | } | |
284 | } | |
285 | ||
286 | ||
287 | static void | |
288 | read_dedicated_control_reg (struct hw *me, | |
289 | struct mn103iop *io_port, | |
290 | unsigned_word io_port_reg, | |
291 | const void *dest, | |
292 | unsigned nr_bytes) | |
293 | { | |
294 | if ( nr_bytes == 1 ) | |
295 | { | |
296 | /* select on io_port_reg: */ | |
297 | if ( io_port_reg == P2SS ) | |
298 | { | |
74ccc978 | 299 | *(uint8_t *)dest = io_port->p2ss; |
c906108c SS |
300 | } |
301 | else | |
302 | { | |
74ccc978 | 303 | *(uint8_t *)dest = io_port->p4ss; |
c906108c SS |
304 | } |
305 | } | |
306 | else | |
307 | { | |
308 | hw_abort (me, "bad read size of %d bytes to PSS.", nr_bytes); | |
309 | } | |
310 | } | |
311 | ||
312 | ||
313 | static unsigned | |
314 | mn103iop_io_read_buffer (struct hw *me, | |
315 | void *dest, | |
316 | int space, | |
317 | unsigned_word base, | |
318 | unsigned nr_bytes) | |
319 | { | |
320 | struct mn103iop *io_port = hw_data (me); | |
321 | enum io_port_register_types io_port_reg; | |
322 | HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); | |
323 | ||
324 | io_port_reg = decode_addr (me, io_port, base); | |
325 | switch (io_port_reg) | |
326 | { | |
327 | /* Port output registers */ | |
328 | case P0OUT: | |
329 | case P1OUT: | |
330 | case P2OUT: | |
331 | case P3OUT: | |
332 | read_output_reg(me, io_port, io_port_reg-P0OUT, dest, nr_bytes); | |
333 | break; | |
334 | ||
335 | /* Port output mode registers */ | |
336 | case P0MD: | |
337 | case P1MD: | |
338 | case P2MD: | |
339 | case P3MD: | |
340 | read_output_mode_reg(me, io_port, io_port_reg-P0MD, dest, nr_bytes); | |
341 | break; | |
342 | ||
343 | /* Port control registers */ | |
344 | case P0DIR: | |
345 | case P1DIR: | |
346 | case P2DIR: | |
347 | case P3DIR: | |
348 | read_control_reg(me, io_port, io_port_reg-P0DIR, dest, nr_bytes); | |
349 | break; | |
350 | ||
351 | /* Port pin registers */ | |
352 | case P0IN: | |
353 | case P1IN: | |
354 | case P2IN: | |
355 | read_pin_reg(me, io_port, io_port_reg-P0IN, dest, nr_bytes); | |
356 | break; | |
357 | ||
358 | case P2SS: | |
359 | case P4SS: | |
360 | read_dedicated_control_reg(me, io_port, io_port_reg, dest, nr_bytes); | |
361 | break; | |
362 | ||
363 | default: | |
364 | hw_abort(me, "invalid address"); | |
365 | } | |
366 | ||
367 | return nr_bytes; | |
368 | } | |
369 | ||
370 | ||
371 | static void | |
372 | write_output_reg (struct hw *me, | |
373 | struct mn103iop *io_port, | |
374 | unsigned_word io_port_reg, | |
375 | const void *source, | |
376 | unsigned nr_bytes) | |
377 | { | |
74ccc978 | 378 | uint8_t buf = *(uint8_t *)source; |
c906108c SS |
379 | if ( nr_bytes == 1 ) |
380 | { | |
381 | if ( io_port_reg == 3 && (buf & 0xfc) != 0 ) | |
382 | { | |
383 | hw_abort(me, "Cannot write to read-only bits of P3OUT."); | |
384 | } | |
385 | else | |
386 | { | |
387 | io_port->port[io_port_reg].output = buf; | |
388 | } | |
389 | } | |
390 | else | |
391 | { | |
392 | hw_abort (me, "bad read size of %d bytes from P%dOUT.", nr_bytes, | |
393 | io_port_reg); | |
394 | } | |
395 | } | |
396 | ||
397 | ||
398 | static void | |
399 | write_output_mode_reg (struct hw *me, | |
400 | struct mn103iop *io_port, | |
401 | unsigned_word io_port_reg, | |
402 | const void *source, | |
403 | unsigned nr_bytes) | |
404 | { | |
74ccc978 | 405 | uint8_t buf = *(uint8_t *)source; |
c906108c SS |
406 | if ( nr_bytes == 1 ) |
407 | { | |
408 | /* check if there are fields which can't be written and | |
409 | take appropriate action depending what bits are set */ | |
410 | if ( ( io_port_reg == 3 && (buf & 0xfc) != 0 ) | |
411 | || ( (io_port_reg == 0 || io_port_reg == 1) && (buf & 0xfe) != 0 ) ) | |
412 | { | |
413 | hw_abort(me, "Cannot write to read-only bits of output mode register."); | |
414 | } | |
415 | else | |
416 | { | |
417 | io_port->port[io_port_reg].output_mode = buf; | |
418 | } | |
419 | } | |
420 | else | |
421 | { | |
422 | hw_abort (me, "bad write size of %d bytes to P%dMD.", nr_bytes, | |
423 | io_port_reg); | |
424 | } | |
425 | } | |
426 | ||
427 | ||
428 | static void | |
429 | write_control_reg (struct hw *me, | |
430 | struct mn103iop *io_port, | |
431 | unsigned_word io_port_reg, | |
432 | const void *source, | |
433 | unsigned nr_bytes) | |
434 | { | |
74ccc978 | 435 | uint8_t buf = *(uint8_t *)source; |
c906108c SS |
436 | if ( nr_bytes == 1 ) |
437 | { | |
438 | if ( io_port_reg == 3 && (buf & 0xfc) != 0 ) | |
439 | { | |
440 | hw_abort(me, "Cannot write to read-only bits of P3DIR."); | |
441 | } | |
442 | else | |
443 | { | |
444 | io_port->port[io_port_reg].control = buf; | |
445 | } | |
446 | } | |
447 | else | |
448 | { | |
449 | hw_abort (me, "bad write size of %d bytes to P%dDIR.", nr_bytes, | |
450 | io_port_reg); | |
451 | } | |
452 | } | |
453 | ||
454 | ||
455 | static void | |
456 | write_dedicated_control_reg (struct hw *me, | |
457 | struct mn103iop *io_port, | |
458 | unsigned_word io_port_reg, | |
459 | const void *source, | |
460 | unsigned nr_bytes) | |
461 | { | |
74ccc978 | 462 | uint8_t buf = *(uint8_t *)source; |
c906108c SS |
463 | if ( nr_bytes == 1 ) |
464 | { | |
465 | /* select on io_port_reg: */ | |
466 | if ( io_port_reg == P2SS ) | |
467 | { | |
481d7981 | 468 | if ( (buf & 0xfc) != 0 ) |
c906108c SS |
469 | { |
470 | hw_abort(me, "Cannot write to read-only bits in p2ss."); | |
471 | } | |
472 | else | |
473 | { | |
474 | io_port->p2ss = buf; | |
475 | } | |
476 | } | |
477 | else | |
478 | { | |
481d7981 | 479 | if ( (buf & 0xf0) != 0 ) |
c906108c SS |
480 | { |
481 | hw_abort(me, "Cannot write to read-only bits in p4ss."); | |
482 | } | |
483 | else | |
484 | { | |
485 | io_port->p4ss = buf; | |
486 | } | |
487 | } | |
488 | } | |
489 | else | |
490 | { | |
491 | hw_abort (me, "bad write size of %d bytes to PSS.", nr_bytes); | |
492 | } | |
493 | } | |
494 | ||
495 | ||
496 | static unsigned | |
497 | mn103iop_io_write_buffer (struct hw *me, | |
498 | const void *source, | |
499 | int space, | |
500 | unsigned_word base, | |
501 | unsigned nr_bytes) | |
502 | { | |
503 | struct mn103iop *io_port = hw_data (me); | |
504 | enum io_port_register_types io_port_reg; | |
505 | HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); | |
506 | ||
507 | io_port_reg = decode_addr (me, io_port, base); | |
508 | switch (io_port_reg) | |
509 | { | |
510 | /* Port output registers */ | |
511 | case P0OUT: | |
512 | case P1OUT: | |
513 | case P2OUT: | |
514 | case P3OUT: | |
515 | write_output_reg(me, io_port, io_port_reg-P0OUT, source, nr_bytes); | |
516 | break; | |
517 | ||
518 | /* Port output mode registers */ | |
519 | case P0MD: | |
520 | case P1MD: | |
521 | case P2MD: | |
522 | case P3MD: | |
523 | write_output_mode_reg(me, io_port, io_port_reg-P0MD, source, nr_bytes); | |
524 | break; | |
525 | ||
526 | /* Port control registers */ | |
527 | case P0DIR: | |
528 | case P1DIR: | |
529 | case P2DIR: | |
530 | case P3DIR: | |
531 | write_control_reg(me, io_port, io_port_reg-P0DIR, source, nr_bytes); | |
532 | break; | |
533 | ||
534 | /* Port pin registers */ | |
535 | case P0IN: | |
536 | case P1IN: | |
537 | case P2IN: | |
538 | hw_abort(me, "Cannot write to pin register."); | |
539 | break; | |
540 | ||
541 | case P2SS: | |
542 | case P4SS: | |
543 | write_dedicated_control_reg(me, io_port, io_port_reg, source, nr_bytes); | |
544 | break; | |
545 | ||
546 | default: | |
547 | hw_abort(me, "invalid address"); | |
548 | } | |
549 | ||
550 | return nr_bytes; | |
551 | } | |
552 | ||
553 | ||
554 | const struct hw_descriptor dv_mn103iop_descriptor[] = { | |
555 | { "mn103iop", mn103iop_finish, }, | |
556 | { NULL }, | |
557 | }; |