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