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