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