]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/mips/dv-tx3904sio.c
Initial creation of sourceware repository
[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 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_GET_TDIS(c) ((c)->sdisr & 0x00020000)
171 #define SDISR_SET_TDIS(c) ((c)->sdisr |= 0x00020000)
172 #define SDISR_GET_RDIS(c) ((c)->sdisr & 0x00010000)
173 #define SDISR_SET_RDIS(c) ((c)->sdisr |= 0x00010000)
174 unsigned_4 sfcr;
175 #define SFCR_WR_MASK 0x001f0000U
176 #define SFCR_SET_BYTE(c,o,b) ((c)->sfcr = SFCR_WR_MASK & (((c)->sfcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
177 #define SFCR_GET_TFRST(c) ((c)->sfcr & 0x00040000)
178 #define SFCR_GET_RFRST(c) ((c)->sfcr & 0x00020000)
179 #define SFCR_GET_FRSTE(c) ((c)->sfcr & 0x00010000)
180 unsigned_4 sbgr;
181 #define SBGR_WR_MASK 0x03ff0000U
182 #define SBGR_SET_BYTE(c,o,b) ((c)->sbgr = SBGR_WR_MASK & (((c)->sbgr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
183
184 /* Periodic I/O polling */
185 struct hw_event* poll_event;
186 };
187
188
189
190 /* Finish off the partially created hw device. Attach our local
191 callbacks. Wire up our port names etc */
192
193 static hw_io_read_buffer_method tx3904sio_io_read_buffer;
194 static hw_io_write_buffer_method tx3904sio_io_write_buffer;
195 static hw_port_event_method tx3904sio_port_event;
196
197
198 static void
199 attach_tx3904sio_regs (struct hw *me,
200 struct tx3904sio *controller)
201 {
202 unsigned_word attach_address;
203 int attach_space;
204 unsigned attach_size;
205 reg_property_spec reg;
206
207 if (hw_find_property (me, "reg") == NULL)
208 hw_abort (me, "Missing \"reg\" property");
209
210 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
211 hw_abort (me, "\"reg\" property must contain one addr/size entry");
212
213 hw_unit_address_to_attach_address (hw_parent (me),
214 &reg.address,
215 &attach_space,
216 &attach_address,
217 me);
218 hw_unit_size_to_attach_size (hw_parent (me),
219 &reg.size,
220 &attach_size, me);
221
222 hw_attach_address (hw_parent (me), 0,
223 attach_space, attach_address, attach_size,
224 me);
225
226 if(hw_find_property(me, "backend") != NULL)
227 {
228 const char* value = hw_find_string_property(me, "backend");
229 if(! strcmp(value, "tcp"))
230 controller->backend = sio_tcp;
231 else if(! strcmp(value, "stdio"))
232 controller->backend = sio_stdio;
233 else
234 hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value);
235 }
236
237 controller->base_address = attach_address;
238 }
239
240
241 static void
242 tx3904sio_finish (struct hw *me)
243 {
244 struct tx3904sio *controller;
245
246 controller = HW_ZALLOC (me, struct tx3904sio);
247 set_hw_data (me, controller);
248 set_hw_io_read_buffer (me, tx3904sio_io_read_buffer);
249 set_hw_io_write_buffer (me, tx3904sio_io_write_buffer);
250 set_hw_ports (me, tx3904sio_ports);
251 set_hw_port_event (me, tx3904sio_port_event);
252
253 /* Preset defaults */
254 controller->backend = sio_stdio;
255
256 /* Attach ourself to our parent bus */
257 attach_tx3904sio_regs (me, controller);
258
259 /* Initialize to reset state */
260 tx3904sio_fifo_reset(me, & controller->rx_fifo);
261 tx3904sio_fifo_reset(me, & controller->tx_fifo);
262 controller->slsr = controller->sdicr
263 = controller->sdisr = controller->sfcr
264 = controller->sbgr = 0;
265 controller->slcr = 0x40000000; /* set TWUB */
266 controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
267 controller->poll_event = NULL;
268 }
269
270
271
272 /* An event arrives on an interrupt port */
273
274 static void
275 tx3904sio_port_event (struct hw *me,
276 int my_port,
277 struct hw *source,
278 int source_port,
279 int level)
280 {
281 struct tx3904sio *controller = hw_data (me);
282
283 switch (my_port)
284 {
285 case RESET_PORT:
286 {
287 HW_TRACE ((me, "reset"));
288
289 tx3904sio_fifo_reset(me, & controller->rx_fifo);
290 tx3904sio_fifo_reset(me, & controller->tx_fifo);
291 controller->slsr = controller->sdicr
292 = controller->sdisr = controller->sfcr
293 = controller->sbgr = 0;
294 controller->slcr = 0x40000000; /* set TWUB */
295 controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
296 /* Don't interfere with I/O poller. */
297 break;
298 }
299
300 default:
301 hw_abort (me, "Event on unknown port %d", my_port);
302 break;
303 }
304 }
305
306
307 /* generic read/write */
308
309 static unsigned
310 tx3904sio_io_read_buffer (struct hw *me,
311 void *dest,
312 int space,
313 unsigned_word base,
314 unsigned nr_bytes)
315 {
316 struct tx3904sio *controller = hw_data (me);
317 unsigned byte;
318
319 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
320
321 /* tickle fifos */
322 tx3904sio_tickle(me);
323
324 for (byte = 0; byte < nr_bytes; byte++)
325 {
326 address_word address = base + byte;
327 int reg_number = (address - controller->base_address) / 4;
328 int reg_offset = (address - controller->base_address) % 4;
329 unsigned_4 register_value; /* in target byte order */
330
331 /* fill in entire register_value word */
332 switch (reg_number)
333 {
334 case SLCR_REG: register_value = controller->slcr; break;
335 case SLSR_REG: register_value = controller->slsr; break;
336 case SDICR_REG: register_value = controller->sdicr; break;
337 case SDISR_REG: register_value = controller->sdisr; break;
338 case SFCR_REG: register_value = controller->sfcr; break;
339 case SBGR_REG: register_value = controller->sbgr; break;
340 case TFIFO_REG: register_value = 0; break;
341 case SFIFO_REG:
342 /* consume rx fifo for MS byte */
343 if(reg_offset == 0 && tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
344 register_value = (tx3904sio_fifo_pop(me, & controller->rx_fifo) << 24);
345 else
346 register_value = 0;
347 break;
348 default: register_value = 0;
349 }
350
351 /* write requested byte out */
352 register_value = H2T_4(register_value);
353 /* HW_TRACE ((me, "byte %d %02x", reg_offset, ((char*)& register_value)[reg_offset])); */
354 memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
355 }
356
357 return nr_bytes;
358 }
359
360
361
362 static unsigned
363 tx3904sio_io_write_buffer (struct hw *me,
364 const void *source,
365 int space,
366 unsigned_word base,
367 unsigned nr_bytes)
368 {
369 struct tx3904sio *controller = hw_data (me);
370 unsigned byte;
371
372 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
373 for (byte = 0; byte < nr_bytes; byte++)
374 {
375 address_word address = base + byte;
376 unsigned_1 write_byte = ((const unsigned char*) source)[byte];
377 int reg_number = (address - controller->base_address) / 4;
378 int reg_offset = 3 - (address - controller->base_address) % 4;
379
380 /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */
381
382 /* fill in entire register_value word */
383 switch (reg_number)
384 {
385 case SLCR_REG:
386 SLCR_SET_BYTE(controller, reg_offset, write_byte);
387 break;
388
389 case SLSR_REG: /* unwriteable */ break;
390
391 case SDICR_REG:
392 {
393 unsigned_4 last_int, next_int;
394
395 /* deassert interrupt upon clear */
396 last_int = controller->sdisr & controller->sdicr;
397 /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x",
398 controller->sdisr, controller->sdicr)); */
399 SDICR_SET_BYTE(controller, reg_offset, write_byte);
400 /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x",
401 controller->sdisr, controller->sdicr)); */
402 next_int = controller->sdisr & controller->sdicr;
403
404 if(SDICR_GET_SDMAE(controller))
405 hw_abort(me, "Cannot support DMA-driven sio.");
406
407 if(~last_int & next_int) /* any bits set? */
408 hw_port_event(me, INT_PORT, 1);
409 if(last_int & ~next_int) /* any bits cleared? */
410 hw_port_event(me, INT_PORT, 0);
411 }
412 break;
413
414 case SDISR_REG:
415 {
416 unsigned_4 last_int, next_int;
417
418 /* deassert interrupt upon clear */
419 last_int = controller->sdisr & controller->sdicr;
420 /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x",
421 controller->sdisr, controller->sdicr)); */
422 SDISR_SET_BYTE(controller, reg_offset, write_byte);
423 /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x",
424 controller->sdisr, controller->sdicr)); */
425 next_int = controller->sdisr & controller->sdicr;
426
427 if(~last_int & next_int) /* any bits set? */
428 hw_port_event(me, INT_PORT, 1);
429 if(last_int & ~next_int) /* any bits cleared? */
430 hw_port_event(me, INT_PORT, 0);
431 }
432 break;
433
434 case SFCR_REG:
435 SFCR_SET_BYTE(controller, reg_offset, write_byte);
436 if(SFCR_GET_FRSTE(controller))
437 {
438 if(SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo);
439 if(SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo);
440 }
441 break;
442
443 case SBGR_REG:
444 SBGR_SET_BYTE(controller, reg_offset, write_byte);
445 break;
446
447 case SFIFO_REG: /* unwriteable */ break;
448
449 case TFIFO_REG:
450 if(reg_offset == 3) /* first byte */
451 tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte);
452 break;
453
454 default:
455 HW_TRACE ((me, "write to illegal register %d", reg_number));
456 }
457 } /* loop over bytes */
458
459 /* tickle fifos */
460 tx3904sio_tickle(me);
461
462 return nr_bytes;
463 }
464
465
466
467
468
469
470 /* Send enqueued characters from tx_fifo and trigger TX interrupt.
471 Receive characters into rx_fifo and trigger RX interrupt. */
472 void
473 tx3904sio_tickle(struct hw *me)
474 {
475 struct tx3904sio* controller = hw_data(me);
476 int c;
477 char cc;
478 unsigned_4 last_int, next_int;
479
480 /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
481 switch(controller->backend)
482 {
483 case sio_tcp:
484
485 while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
486 {
487 cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
488 dv_sockser_write(hw_system(me), cc);
489 HW_TRACE ((me, "tcp output: %02x", cc));
490 }
491
492 c = dv_sockser_read(hw_system(me));
493 while(c != -1)
494 {
495 cc = (char) c;
496 HW_TRACE ((me, "tcp input: %02x", cc));
497 tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
498 c = dv_sockser_read(hw_system(me));
499 }
500 break;
501
502 case sio_stdio:
503
504 while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
505 {
506 cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
507 sim_io_write_stdout(hw_system(me), & cc, 1);
508 sim_io_flush_stdout(hw_system(me));
509 HW_TRACE ((me, "stdio output: %02x", cc));
510 }
511
512 c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
513 while(c == 1)
514 {
515 HW_TRACE ((me, "stdio input: %02x", cc));
516 tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
517 c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
518 }
519
520 break;
521
522 default:
523 hw_abort(me, "Illegal backend mode: %d", controller->backend);
524 }
525
526 /* Update RDIS / TDIS flags */
527 last_int = controller->sdisr & controller->sdicr;
528 /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
529 if(tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
530 SDISR_SET_RDIS(controller);
531 if(! tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
532 SDISR_SET_TDIS(controller);
533 next_int = controller->sdisr & controller->sdicr;
534 /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
535
536 if(~last_int & next_int) /* any bits set? */
537 hw_port_event(me, INT_PORT, 1);
538 if(last_int & ~next_int) /* any bits cleared? */
539 hw_port_event(me, INT_PORT, 0);
540
541 /* Add periodic polling for this port, if it's not already going. */
542 if(controller->poll_event == NULL)
543 {
544 controller->poll_event = hw_event_queue_schedule (me, 1000,
545 tx3904sio_poll, NULL);
546
547 }
548 }
549
550
551
552
553 int
554 tx3904sio_fifo_nonempty(struct hw* me, struct tx3904sio_fifo* fifo)
555 {
556 /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */
557 return(fifo->used > 0);
558 }
559
560
561 char
562 tx3904sio_fifo_pop(struct hw* me, struct tx3904sio_fifo* fifo)
563 {
564 char it;
565 ASSERT(fifo->used > 0);
566 ASSERT(fifo->buffer != NULL);
567 it = fifo->buffer[0];
568 memcpy(& fifo->buffer[0], & fifo->buffer[1], fifo->used - 1);
569 fifo->used --;
570 /* HW_TRACE ((me, "pop fifo -> %02x", it)); */
571 return it;
572 }
573
574
575 void
576 tx3904sio_fifo_push(struct hw* me, struct tx3904sio_fifo* fifo, char it)
577 {
578 /* HW_TRACE ((me, "push %02x -> fifo", it)); */
579 if(fifo->size == fifo->used) /* full */
580 {
581 int next_size = fifo->size * 2 + 16;
582 char* next_buf = zalloc(next_size);
583 memcpy(next_buf, fifo->buffer, fifo->used);
584
585 if(fifo->buffer != NULL) zfree(fifo->buffer);
586 fifo->buffer = next_buf;
587 fifo->size = next_size;
588 }
589
590 fifo->buffer[fifo->used] = it;
591 fifo->used ++;
592 }
593
594
595 void
596 tx3904sio_fifo_reset(struct hw* me, struct tx3904sio_fifo* fifo)
597 {
598 /* HW_TRACE ((me, "reset fifo")); */
599 fifo->used = 0;
600 fifo->size = 0;
601 zfree(fifo->buffer);
602 fifo->buffer = 0;
603 }
604
605
606 void
607 tx3904sio_poll(struct hw* me, void* ignored)
608 {
609 struct tx3904sio* controller = hw_data (me);
610 tx3904sio_tickle (me);
611 hw_event_queue_deschedule (me, controller->poll_event);
612 controller->poll_event = hw_event_queue_schedule (me, 1000,
613 tx3904sio_poll, NULL);
614 }
615
616
617
618 const struct hw_descriptor dv_tx3904sio_descriptor[] = {
619 { "tx3904sio", tx3904sio_finish, },
620 { NULL },
621 };