1/*  This file is part of the program GDB, the GNU debugger.
2
3    Copyright (C) 1998-2023 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 3 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, see <http://www.gnu.org/licenses/>.
18
19    */
20
21/* This must come before any other includes.  */
22#include "defs.h"
23
24#include "sim-main.h"
25#include "hw-main.h"
26#include "dv-sockser.h"
27#include "sim-assert.h"
28
29#include <stdlib.h>
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)))
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)))
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)); */
425	    SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte);
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      unsigned_1* next_buf = zalloc(next_size);
586      memcpy(next_buf, fifo->buffer, fifo->used);
587
588      if (fifo->buffer != NULL) free(fifo->buffer);
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;
604  free(fifo->buffer);
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};
625