1 /* This file is part of the program GDB, the GNU debugger.
3 Copyright (C) 1998 Free Software Foundation, Inc.
4 Contributed by Cygnus Solutions.
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.
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.
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.
25 #include "dv-sockser.h"
32 tx3904sio - tx3904 serial I/O
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.
42 Both internal and system clocks are synthesized as divided versions
43 of the simulator clock.
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
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
70 Use dv-sockser TCP-port backend or stdio for backend. Default: stdio.
79 Interrupt port. An event is generated when a timer interrupt
91 /* static functions */
93 struct tx3904sio_fifo
;
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
*);
103 /* register numbers; each is one word long */
127 static const struct hw_port_descriptor tx3904sio_ports
[] =
129 { "int", INT_PORT
, 0, output_port
, },
130 { "reset", RESET_PORT
, 0, input_port
, },
137 struct tx3904sio_fifo
145 /* The timer/counter register internal state. Note that we store
146 state using the control register images, in host endian order. */
150 address_word base_address
; /* control register base */
151 enum {sio_tcp
, sio_stdio
} backend
; /* backend */
153 struct tx3904sio_fifo rx_fifo
, tx_fifo
; /* FIFOs */
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)))
159 #define SLSR_WR_MASK 0x00000000 /* UFER/UPER/UOER unimplemented */
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)
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)
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)
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)))
187 /* Finish off the partially created hw device. Attach our local
188 callbacks. Wire up our port names etc */
190 static hw_io_read_buffer_method tx3904sio_io_read_buffer
;
191 static hw_io_write_buffer_method tx3904sio_io_write_buffer
;
192 static hw_port_event_method tx3904sio_port_event
;
196 attach_tx3904sio_regs (struct hw
*me
,
197 struct tx3904sio
*controller
)
199 unsigned_word attach_address
;
201 unsigned attach_size
;
202 reg_property_spec reg
;
204 if (hw_find_property (me
, "reg") == NULL
)
205 hw_abort (me
, "Missing \"reg\" property");
207 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
208 hw_abort (me
, "\"reg\" property must contain one addr/size entry");
210 hw_unit_address_to_attach_address (hw_parent (me
),
215 hw_unit_size_to_attach_size (hw_parent (me
),
219 hw_attach_address (hw_parent (me
), 0,
220 attach_space
, attach_address
, attach_size
,
223 if(hw_find_property(me
, "backend") != NULL
)
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
;
231 hw_abort(me
, "illegal value for backend parameter `%s': use tcp or stdio", value
);
234 controller
->base_address
= attach_address
;
239 tx3904sio_finish (struct hw
*me
)
241 struct tx3904sio
*controller
;
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
);
250 /* Preset defaults */
251 controller
->backend
= sio_stdio
;
253 /* Attach ourself to our parent bus */
254 attach_tx3904sio_regs (me
, controller
);
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 */
268 /* An event arrives on an interrupt port */
271 tx3904sio_port_event (struct hw
*me
,
277 struct tx3904sio
*controller
= hw_data (me
);
283 HW_TRACE ((me
, "reset"));
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 */
296 hw_abort (me
, "Event on unknown port %d", my_port
);
302 /* generic read/write */
305 tx3904sio_io_read_buffer (struct hw
*me
,
311 struct tx3904sio
*controller
= hw_data (me
);
314 HW_TRACE ((me
, "read 0x%08lx %d", (long) base
, (int) nr_bytes
));
317 tx3904sio_tickle(me
);
319 for (byte
= 0; byte
< nr_bytes
; byte
++)
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 */
326 /* fill in entire register_value word */
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;
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);
343 default: register_value
= 0;
346 /* write requested byte out */
347 memcpy ((char*) dest
+ byte
, ((char*)& register_value
)+reg_offset
, 1);
356 tx3904sio_io_write_buffer (struct hw
*me
,
362 struct tx3904sio
*controller
= hw_data (me
);
365 HW_TRACE ((me
, "write 0x%08lx %d", (long) base
, (int) nr_bytes
));
366 for (byte
= 0; byte
< nr_bytes
; byte
++)
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;
373 HW_TRACE ((me
, "byte %d %02x", reg_offset
, write_byte
));
375 /* fill in entire register_value word */
379 SLCR_SET_BYTE(controller
, reg_offset
, write_byte
);
382 case SLSR_REG
: /* unwriteable */ break;
386 unsigned_4 last_int
, next_int
;
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
;
397 if(SDICR_GET_SDMAE(controller
))
398 hw_abort(me
, "Cannot support DMA-driven sio.");
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);
409 unsigned_4 last_int
, next_int
;
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
;
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);
428 SFCR_SET_BYTE(controller
, reg_offset
, write_byte
);
429 if(SFCR_GET_FRSTE(controller
))
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
);
437 SBGR_SET_BYTE(controller
, reg_offset
, write_byte
);
440 case SFIFO_REG
: /* unwriteable */ break;
443 if(reg_offset
== 3) /* first byte */
444 tx3904sio_fifo_push(me
, & controller
->tx_fifo
, write_byte
);
448 HW_TRACE ((me
, "write to illegal register %d", reg_number
));
450 } /* loop over bytes */
453 tx3904sio_tickle(me
);
463 /* Send enqueued characters from tx_fifo and trigger TX interrupt.
464 Receive characters into rx_fifo and trigger RX interrupt. */
466 tx3904sio_tickle(struct hw
*me
)
468 struct tx3904sio
* controller
= hw_data(me
);
471 unsigned_4 last_int
, next_int
;
473 /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
474 switch(controller
->backend
)
478 while(tx3904sio_fifo_nonempty(me
, & controller
->tx_fifo
))
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
));
485 c
= dv_sockser_read(hw_system(me
));
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
));
497 while(tx3904sio_fifo_nonempty(me
, & controller
->tx_fifo
))
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
));
504 c
= sim_io_poll_read(hw_system(me
), 0 /* stdin */, & cc
, 1);
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);
515 hw_abort(me
, "Illegal backend mode: %d", controller
->backend
);
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)); */
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);
538 tx3904sio_fifo_nonempty(struct hw
* me
, struct tx3904sio_fifo
* fifo
)
540 /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */
541 return(fifo
->used
> 0);
546 tx3904sio_fifo_pop(struct hw
* me
, struct tx3904sio_fifo
* fifo
)
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);
554 /* HW_TRACE ((me, "pop fifo -> %02x", it)); */
560 tx3904sio_fifo_push(struct hw
* me
, struct tx3904sio_fifo
* fifo
, char it
)
562 /* HW_TRACE ((me, "push %02x -> fifo", it)); */
563 if(fifo
->size
== fifo
->used
) /* full */
565 int next_size
= fifo
->size
* 2 + 16;
566 char* next_buf
= zalloc(next_size
);
567 memcpy(next_buf
, fifo
->buffer
, fifo
->used
);
569 if(fifo
->buffer
!= NULL
) zfree(fifo
->buffer
);
570 fifo
->buffer
= next_buf
;
571 fifo
->size
= next_size
;
574 fifo
->buffer
[fifo
->used
] = it
;
580 tx3904sio_fifo_reset(struct hw
* me
, struct tx3904sio_fifo
* fifo
)
582 /* HW_TRACE ((me, "reset fifo")); */
592 const struct hw_descriptor dv_tx3904sio_descriptor
[] = {
593 { "tx3904sio", tx3904sio_finish
, },