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