]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/mips/dv-tx3904sio.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / sim / mips / dv-tx3904sio.c
1 /* This file is part of the program GDB, the GNU debugger.
2
3 Copyright (C) 1998, 1999, 2007 Free Software Foundation, Inc.
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
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22
23 #include "sim-main.h"
24 #include "hw-main.h"
25 #include "dv-sockser.h"
26 #include "sim-assert.h"
27
28
29 /* DEVICE
30
31
32 tx3904sio - tx3904 serial I/O
33
34
35 DESCRIPTION
36
37
38 Implements one tx3904 serial I/O controller described in the tx3904
39 user guide. Three instances are required for SIO0 and SIO1 within
40 the tx3904, at different base addresses.
41
42 Both internal and system clocks are synthesized as divided versions
43 of the simulator clock.
44
45 There is no support for:
46 - CTS/RTS flow control
47 - baud rate emulation - use infinite speed instead
48 - general frame format - use 8N1
49 - multi-controller system
50 - DMA - use interrupt-driven or polled-I/O instead
51
52
53 PROPERTIES
54
55
56 reg <base> <length>
57
58 Base of SIO control register bank. <length> must equal 0x100.
59 Register offsets: 0: SLCR: line control register
60 4: SLSR: line status register
61 8: SDICR: DMA/interrupt control register
62 12: SDISR: DMA/interrupt status register
63 16: SFCR: FIFO control register
64 20: SBGR: baud rate control register
65 32: transfer FIFO buffer
66 48: transfer FIFO buffer
67
68 backend {tcp | stdio}
69
70 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
71
72
73
74 PORTS
75
76
77 int (output)
78
79 Interrupt port. An event is generated when a timer interrupt
80 occurs.
81
82
83 reset (input)
84
85 Reset port.
86
87 */
88
89
90
91 /* static functions */
92
93 struct tx3904sio_fifo;
94
95 static void tx3904sio_tickle(struct hw*);
96 static int tx3904sio_fifo_nonempty(struct hw*, struct tx3904sio_fifo*);
97 static char tx3904sio_fifo_pop(struct hw*, struct tx3904sio_fifo*);
98 static void tx3904sio_fifo_push(struct hw*, struct tx3904sio_fifo*, char);
99 static void tx3904sio_fifo_reset(struct hw*, struct tx3904sio_fifo*);
100 static void tx3904sio_poll(struct hw*, void* data);
101
102
103 /* register numbers; each is one word long */
104 enum
105 {
106 SLCR_REG = 0,
107 SLSR_REG = 1,
108 SDICR_REG = 2,
109 SDISR_REG = 3,
110 SFCR_REG = 4,
111 SBGR_REG = 5,
112 TFIFO_REG = 8,
113 SFIFO_REG = 12,
114 };
115
116
117
118 /* port ID's */
119
120 enum
121 {
122 RESET_PORT,
123 INT_PORT,
124 };
125
126
127 static const struct hw_port_descriptor tx3904sio_ports[] =
128 {
129 { "int", INT_PORT, 0, output_port, },
130 { "reset", RESET_PORT, 0, input_port, },
131 { NULL, },
132 };
133
134
135
136 /* Generic FIFO */
137 struct tx3904sio_fifo
138 {
139 int size, used;
140 unsigned_1 *buffer;
141 };
142
143
144
145 /* The timer/counter register internal state. Note that we store
146 state using the control register images, in host endian order. */
147
148 struct tx3904sio
149 {
150 address_word base_address; /* control register base */
151 enum {sio_tcp, sio_stdio} backend; /* backend */
152
153 struct tx3904sio_fifo rx_fifo, tx_fifo; /* FIFOs */
154
155 unsigned_4 slcr;
156 #define SLCR_WR_MASK 0xe17f0000U
157 #define SLCR_SET_BYTE(c,o,b) ((c)->slcr = SLCR_WR_MASK & (((c)->slcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
158 unsigned_4 slsr;
159 #define SLSR_WR_MASK 0x00000000 /* UFER/UPER/UOER unimplemented */
160 unsigned_4 sdicr;
161 #define SDICR_WR_MASK 0x000f0000U
162 #define SDICR_SET_BYTE(c,o,b) ((c)->sdicr = SDICR_WR_MASK & (((c)->sdicr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
163 #define SDICR_GET_SDMAE(c) ((c)->sdicr & 0x00080000)
164 #define SDICR_GET_ERIE(c) ((c)->sdicr & 0x00040000)
165 #define SDICR_GET_TDIE(c) ((c)->sdicr & 0x00020000)
166 #define SDICR_GET_RDIE(c) ((c)->sdicr & 0x00010000)
167 unsigned_4 sdisr;
168 #define SDISR_WR_MASK 0x00070000U
169 #define SDISR_SET_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
170 #define SDISR_CLEAR_FLAG_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) & ((b)<< (o)*8)))
171 #define SDISR_GET_TDIS(c) ((c)->sdisr & 0x00020000)
172 #define SDISR_SET_TDIS(c) ((c)->sdisr |= 0x00020000)
173 #define SDISR_GET_RDIS(c) ((c)->sdisr & 0x00010000)
174 #define SDISR_SET_RDIS(c) ((c)->sdisr |= 0x00010000)
175 unsigned_4 sfcr;
176 #define SFCR_WR_MASK 0x001f0000U
177 #define SFCR_SET_BYTE(c,o,b) ((c)->sfcr = SFCR_WR_MASK & (((c)->sfcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
178 #define SFCR_GET_TFRST(c) ((c)->sfcr & 0x00040000)
179 #define SFCR_GET_RFRST(c) ((c)->sfcr & 0x00020000)
180 #define SFCR_GET_FRSTE(c) ((c)->sfcr & 0x00010000)
181 unsigned_4 sbgr;
182 #define SBGR_WR_MASK 0x03ff0000U
183 #define SBGR_SET_BYTE(c,o,b) ((c)->sbgr = SBGR_WR_MASK & (((c)->sbgr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
184
185 /* Periodic I/O polling */
186 struct hw_event* poll_event;
187 };
188
189
190
191 /* Finish off the partially created hw device. Attach our local
192 callbacks. Wire up our port names etc */
193
194 static hw_io_read_buffer_method tx3904sio_io_read_buffer;
195 static hw_io_write_buffer_method tx3904sio_io_write_buffer;
196 static hw_port_event_method tx3904sio_port_event;
197
198
199 static void
200 attach_tx3904sio_regs (struct hw *me,
201 struct tx3904sio *controller)
202 {
203 unsigned_word attach_address;
204 int attach_space;
205 unsigned attach_size;
206 reg_property_spec reg;
207
208 if (hw_find_property (me, "reg") == NULL)
209 hw_abort (me, "Missing \"reg\" property");
210
211 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
212 hw_abort (me, "\"reg\" property must contain one addr/size entry");
213
214 hw_unit_address_to_attach_address (hw_parent (me),
215 &reg.address,
216 &attach_space,
217 &attach_address,
218 me);
219 hw_unit_size_to_attach_size (hw_parent (me),
220 &reg.size,
221 &attach_size, me);
222
223 hw_attach_address (hw_parent (me), 0,
224 attach_space, attach_address, attach_size,
225 me);
226
227 if(hw_find_property(me, "backend") != NULL)
228 {
229 const char* value = hw_find_string_property(me, "backend");
230 if(! strcmp(value, "tcp"))
231 controller->backend = sio_tcp;
232 else if(! strcmp(value, "stdio"))
233 controller->backend = sio_stdio;
234 else
235 hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value);
236 }
237
238 controller->base_address = attach_address;
239 }
240
241
242 static void
243 tx3904sio_finish (struct hw *me)
244 {
245 struct tx3904sio *controller;
246
247 controller = HW_ZALLOC (me, struct tx3904sio);
248 set_hw_data (me, controller);
249 set_hw_io_read_buffer (me, tx3904sio_io_read_buffer);
250 set_hw_io_write_buffer (me, tx3904sio_io_write_buffer);
251 set_hw_ports (me, tx3904sio_ports);
252 set_hw_port_event (me, tx3904sio_port_event);
253
254 /* Preset defaults */
255 controller->backend = sio_stdio;
256
257 /* Attach ourself to our parent bus */
258 attach_tx3904sio_regs (me, controller);
259
260 /* Initialize to reset state */
261 tx3904sio_fifo_reset(me, & controller->rx_fifo);
262 tx3904sio_fifo_reset(me, & controller->tx_fifo);
263 controller->slsr = controller->sdicr
264 = controller->sdisr = controller->sfcr
265 = controller->sbgr = 0;
266 controller->slcr = 0x40000000; /* set TWUB */
267 controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
268 controller->poll_event = NULL;
269 }
270
271
272
273 /* An event arrives on an interrupt port */
274
275 static void
276 tx3904sio_port_event (struct hw *me,
277 int my_port,
278 struct hw *source,
279 int source_port,
280 int level)
281 {
282 struct tx3904sio *controller = hw_data (me);
283
284 switch (my_port)
285 {
286 case RESET_PORT:
287 {
288 HW_TRACE ((me, "reset"));
289
290 tx3904sio_fifo_reset(me, & controller->rx_fifo);
291 tx3904sio_fifo_reset(me, & controller->tx_fifo);
292 controller->slsr = controller->sdicr
293 = controller->sdisr = controller->sfcr
294 = controller->sbgr = 0;
295 controller->slcr = 0x40000000; /* set TWUB */
296 controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
297 /* Don't interfere with I/O poller. */
298 break;
299 }
300
301 default:
302 hw_abort (me, "Event on unknown port %d", my_port);
303 break;
304 }
305 }
306
307
308 /* generic read/write */
309
310 static unsigned
311 tx3904sio_io_read_buffer (struct hw *me,
312 void *dest,
313 int space,
314 unsigned_word base,
315 unsigned nr_bytes)
316 {
317 struct tx3904sio *controller = hw_data (me);
318 unsigned byte;
319
320 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
321
322 /* tickle fifos */
323 tx3904sio_tickle(me);
324
325 for (byte = 0; byte < nr_bytes; byte++)
326 {
327 address_word address = base + byte;
328 int reg_number = (address - controller->base_address) / 4;
329 int reg_offset = (address - controller->base_address) % 4;
330 unsigned_4 register_value; /* in target byte order */
331
332 /* fill in entire register_value word */
333 switch (reg_number)
334 {
335 case SLCR_REG: register_value = controller->slcr; break;
336 case SLSR_REG: register_value = controller->slsr; break;
337 case SDICR_REG: register_value = controller->sdicr; break;
338 case SDISR_REG: register_value = controller->sdisr; break;
339 case SFCR_REG: register_value = controller->sfcr; break;
340 case SBGR_REG: register_value = controller->sbgr; break;
341 case TFIFO_REG: register_value = 0; break;
342 case SFIFO_REG:
343 /* consume rx fifo for MS byte */
344 if(reg_offset == 0 && tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
345 register_value = (tx3904sio_fifo_pop(me, & controller->rx_fifo) << 24);
346 else
347 register_value = 0;
348 break;
349 default: register_value = 0;
350 }
351
352 /* write requested byte out */
353 register_value = H2T_4(register_value);
354 /* HW_TRACE ((me, "byte %d %02x", reg_offset, ((char*)& register_value)[reg_offset])); */
355 memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
356 }
357
358 return nr_bytes;
359 }
360
361
362
363 static unsigned
364 tx3904sio_io_write_buffer (struct hw *me,
365 const void *source,
366 int space,
367 unsigned_word base,
368 unsigned nr_bytes)
369 {
370 struct tx3904sio *controller = hw_data (me);
371 unsigned byte;
372
373 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
374 for (byte = 0; byte < nr_bytes; byte++)
375 {
376 address_word address = base + byte;
377 unsigned_1 write_byte = ((const unsigned char*) source)[byte];
378 int reg_number = (address - controller->base_address) / 4;
379 int reg_offset = 3 - (address - controller->base_address) % 4;
380
381 /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */
382
383 /* fill in entire register_value word */
384 switch (reg_number)
385 {
386 case SLCR_REG:
387 SLCR_SET_BYTE(controller, reg_offset, write_byte);
388 break;
389
390 case SLSR_REG: /* unwriteable */ break;
391
392 case SDICR_REG:
393 {
394 unsigned_4 last_int, next_int;
395
396 /* deassert interrupt upon clear */
397 last_int = controller->sdisr & controller->sdicr;
398 /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x",
399 controller->sdisr, controller->sdicr)); */
400 SDICR_SET_BYTE(controller, reg_offset, write_byte);
401 /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x",
402 controller->sdisr, controller->sdicr)); */
403 next_int = controller->sdisr & controller->sdicr;
404
405 if(SDICR_GET_SDMAE(controller))
406 hw_abort(me, "Cannot support DMA-driven sio.");
407
408 if(~last_int & next_int) /* any bits set? */
409 hw_port_event(me, INT_PORT, 1);
410 if(last_int & ~next_int) /* any bits cleared? */
411 hw_port_event(me, INT_PORT, 0);
412 }
413 break;
414
415 case SDISR_REG:
416 {
417 unsigned_4 last_int, next_int;
418
419 /* deassert interrupt upon clear */
420 last_int = controller->sdisr & controller->sdicr;
421 /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x",
422 controller->sdisr, controller->sdicr)); */
423 SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte);
424 /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x",
425 controller->sdisr, controller->sdicr)); */
426 next_int = controller->sdisr & controller->sdicr;
427
428 if(~last_int & next_int) /* any bits set? */
429 hw_port_event(me, INT_PORT, 1);
430 if(last_int & ~next_int) /* any bits cleared? */
431 hw_port_event(me, INT_PORT, 0);
432 }
433 break;
434
435 case SFCR_REG:
436 SFCR_SET_BYTE(controller, reg_offset, write_byte);
437 if(SFCR_GET_FRSTE(controller))
438 {
439 if(SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo);
440 if(SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo);
441 }
442 break;
443
444 case SBGR_REG:
445 SBGR_SET_BYTE(controller, reg_offset, write_byte);
446 break;
447
448 case SFIFO_REG: /* unwriteable */ break;
449
450 case TFIFO_REG:
451 if(reg_offset == 3) /* first byte */
452 tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte);
453 break;
454
455 default:
456 HW_TRACE ((me, "write to illegal register %d", reg_number));
457 }
458 } /* loop over bytes */
459
460 /* tickle fifos */
461 tx3904sio_tickle(me);
462
463 return nr_bytes;
464 }
465
466
467
468
469
470
471 /* Send enqueued characters from tx_fifo and trigger TX interrupt.
472 Receive characters into rx_fifo and trigger RX interrupt. */
473 void
474 tx3904sio_tickle(struct hw *me)
475 {
476 struct tx3904sio* controller = hw_data(me);
477 int c;
478 char cc;
479 unsigned_4 last_int, next_int;
480
481 /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
482 switch(controller->backend)
483 {
484 case sio_tcp:
485
486 while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
487 {
488 cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
489 dv_sockser_write(hw_system(me), cc);
490 HW_TRACE ((me, "tcp output: %02x", cc));
491 }
492
493 c = dv_sockser_read(hw_system(me));
494 while(c != -1)
495 {
496 cc = (char) c;
497 HW_TRACE ((me, "tcp input: %02x", cc));
498 tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
499 c = dv_sockser_read(hw_system(me));
500 }
501 break;
502
503 case sio_stdio:
504
505 while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
506 {
507 cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
508 sim_io_write_stdout(hw_system(me), & cc, 1);
509 sim_io_flush_stdout(hw_system(me));
510 HW_TRACE ((me, "stdio output: %02x", cc));
511 }
512
513 c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
514 while(c == 1)
515 {
516 HW_TRACE ((me, "stdio input: %02x", cc));
517 tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
518 c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
519 }
520
521 break;
522
523 default:
524 hw_abort(me, "Illegal backend mode: %d", controller->backend);
525 }
526
527 /* Update RDIS / TDIS flags */
528 last_int = controller->sdisr & controller->sdicr;
529 /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
530 if(tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
531 SDISR_SET_RDIS(controller);
532 if(! tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
533 SDISR_SET_TDIS(controller);
534 next_int = controller->sdisr & controller->sdicr;
535 /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
536
537 if(~last_int & next_int) /* any bits set? */
538 hw_port_event(me, INT_PORT, 1);
539 if(last_int & ~next_int) /* any bits cleared? */
540 hw_port_event(me, INT_PORT, 0);
541
542 /* Add periodic polling for this port, if it's not already going. */
543 if(controller->poll_event == NULL)
544 {
545 controller->poll_event = hw_event_queue_schedule (me, 1000,
546 tx3904sio_poll, NULL);
547
548 }
549 }
550
551
552
553
554 int
555 tx3904sio_fifo_nonempty(struct hw* me, struct tx3904sio_fifo* fifo)
556 {
557 /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */
558 return(fifo->used > 0);
559 }
560
561
562 char
563 tx3904sio_fifo_pop(struct hw* me, struct tx3904sio_fifo* fifo)
564 {
565 char it;
566 ASSERT(fifo->used > 0);
567 ASSERT(fifo->buffer != NULL);
568 it = fifo->buffer[0];
569 memcpy(& fifo->buffer[0], & fifo->buffer[1], fifo->used - 1);
570 fifo->used --;
571 /* HW_TRACE ((me, "pop fifo -> %02x", it)); */
572 return it;
573 }
574
575
576 void
577 tx3904sio_fifo_push(struct hw* me, struct tx3904sio_fifo* fifo, char it)
578 {
579 /* HW_TRACE ((me, "push %02x -> fifo", it)); */
580 if(fifo->size == fifo->used) /* full */
581 {
582 int next_size = fifo->size * 2 + 16;
583 char* next_buf = zalloc(next_size);
584 memcpy(next_buf, fifo->buffer, fifo->used);
585
586 if(fifo->buffer != NULL) zfree(fifo->buffer);
587 fifo->buffer = next_buf;
588 fifo->size = next_size;
589 }
590
591 fifo->buffer[fifo->used] = it;
592 fifo->used ++;
593 }
594
595
596 void
597 tx3904sio_fifo_reset(struct hw* me, struct tx3904sio_fifo* fifo)
598 {
599 /* HW_TRACE ((me, "reset fifo")); */
600 fifo->used = 0;
601 fifo->size = 0;
602 zfree(fifo->buffer);
603 fifo->buffer = 0;
604 }
605
606
607 void
608 tx3904sio_poll(struct hw* me, void* ignored)
609 {
610 struct tx3904sio* controller = hw_data (me);
611 tx3904sio_tickle (me);
612 hw_event_queue_deschedule (me, controller->poll_event);
613 controller->poll_event = hw_event_queue_schedule (me, 1000,
614 tx3904sio_poll, NULL);
615 }
616
617
618
619 const struct hw_descriptor dv_tx3904sio_descriptor[] = {
620 { "tx3904sio", tx3904sio_finish, },
621 { NULL },
622 };