]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/bfin/dv-bfin_uart.c
sim: switch config.h usage to defs.h
[thirdparty/binutils-gdb.git] / sim / bfin / dv-bfin_uart.c
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "old style" UARTs on BF53x/etc... parts.
3
4 Copyright (C) 2010-2021 Free Software Foundation, Inc.
5 Contributed by Analog Devices, Inc.
6
7 This file is part of simulators.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 /* This must come before any other includes. */
23 #include "defs.h"
24
25 #include "sim-main.h"
26 #include "dv-sockser.h"
27 #include "devices.h"
28 #include "dv-bfin_uart.h"
29
30 /* XXX: Should we bother emulating the TX/RX FIFOs ? */
31
32 /* Internal state needs to be the same as bfin_uart2. */
33 struct bfin_uart
34 {
35 /* This top portion matches common dv_bfin struct. */
36 bu32 base;
37 struct hw *dma_master;
38 bool acked;
39
40 struct hw_event *handler;
41 char saved_byte;
42 int saved_count;
43
44 /* This is aliased to DLH. */
45 bu16 ier;
46 /* These are aliased to DLL. */
47 bu16 thr, rbr;
48
49 /* Order after here is important -- matches hardware MMR layout. */
50 bu16 BFIN_MMR_16(dll);
51 bu16 BFIN_MMR_16(dlh);
52 bu16 BFIN_MMR_16(iir);
53 bu16 BFIN_MMR_16(lcr);
54 bu16 BFIN_MMR_16(mcr);
55 bu16 BFIN_MMR_16(lsr);
56 bu16 BFIN_MMR_16(msr);
57 bu16 BFIN_MMR_16(scr);
58 bu16 _pad0[2];
59 bu16 BFIN_MMR_16(gctl);
60 };
61 #define mmr_base() offsetof(struct bfin_uart, dll)
62 #define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
63
64 static const char * const mmr_names[] =
65 {
66 "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
67 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
68 };
69 static const char *mmr_name (struct bfin_uart *uart, bu32 idx)
70 {
71 if (uart->lcr & DLAB)
72 if (idx < 2)
73 return idx == 0 ? "UART_DLL" : "UART_DLH";
74 return mmr_names[idx];
75 }
76 #define mmr_name(off) mmr_name (uart, (off) / 4)
77
78 static void
79 bfin_uart_poll (struct hw *me, void *data)
80 {
81 struct bfin_uart *uart = data;
82 bu16 lsr;
83
84 uart->handler = NULL;
85
86 lsr = bfin_uart_get_status (me);
87 if (lsr & DR)
88 hw_port_event (me, DV_PORT_RX, 1);
89
90 bfin_uart_reschedule (me);
91 }
92
93 void
94 bfin_uart_reschedule (struct hw *me)
95 {
96 struct bfin_uart *uart = hw_data (me);
97
98 if (uart->ier & ERBFI)
99 {
100 if (!uart->handler)
101 uart->handler = hw_event_queue_schedule (me, 10000,
102 bfin_uart_poll, uart);
103 }
104 else
105 {
106 if (uart->handler)
107 {
108 hw_event_queue_deschedule (me, uart->handler);
109 uart->handler = NULL;
110 }
111 }
112 }
113
114 bu16
115 bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr)
116 {
117 struct bfin_uart *uart = hw_data (me);
118 unsigned char ch = thr;
119
120 if (mcr & LOOP_ENA)
121 {
122 /* XXX: This probably doesn't work exactly right with
123 external FIFOs ... */
124 uart->saved_byte = thr;
125 uart->saved_count = 1;
126 }
127
128 bfin_uart_write_buffer (me, &ch, 1);
129
130 return thr;
131 }
132
133 static unsigned
134 bfin_uart_io_write_buffer (struct hw *me, const void *source,
135 int space, address_word addr, unsigned nr_bytes)
136 {
137 struct bfin_uart *uart = hw_data (me);
138 bu32 mmr_off;
139 bu32 value;
140 bu16 *valuep;
141
142 /* Invalid access mode is higher priority than missing register. */
143 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
144 return 0;
145
146 value = dv_load_2 (source);
147 mmr_off = addr - uart->base;
148 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
149
150 HW_TRACE_WRITE ();
151
152 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
153 switch (mmr_off)
154 {
155 case mmr_offset(dll):
156 if (uart->lcr & DLAB)
157 uart->dll = value;
158 else
159 {
160 uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
161
162 if (uart->ier & ETBEI)
163 hw_port_event (me, DV_PORT_TX, 1);
164 }
165 break;
166 case mmr_offset(dlh):
167 if (uart->lcr & DLAB)
168 uart->dlh = value;
169 else
170 {
171 uart->ier = value;
172 bfin_uart_reschedule (me);
173 }
174 break;
175 case mmr_offset(iir):
176 case mmr_offset(lsr):
177 /* XXX: Writes are ignored ? */
178 break;
179 case mmr_offset(lcr):
180 case mmr_offset(mcr):
181 case mmr_offset(scr):
182 case mmr_offset(gctl):
183 *valuep = value;
184 break;
185 default:
186 dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
187 return 0;
188 }
189
190 return nr_bytes;
191 }
192
193 /* Switch between socket and stdin on the fly. */
194 bu16
195 bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bu16 mcr, bool *fresh)
196 {
197 SIM_DESC sd = hw_system (me);
198 struct bfin_uart *uart = hw_data (me);
199 int status = dv_sockser_status (sd);
200 bool _fresh;
201
202 /* NB: The "uart" here may only use interal state. */
203
204 if (!fresh)
205 fresh = &_fresh;
206
207 *fresh = false;
208
209 if (uart->saved_count > 0)
210 {
211 *fresh = true;
212 rbr = uart->saved_byte;
213 --uart->saved_count;
214 }
215 else if (mcr & LOOP_ENA)
216 {
217 /* RX is disconnected, so only return local data. */
218 }
219 else if (status & DV_SOCKSER_DISCONNECTED)
220 {
221 char byte;
222 int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
223
224 if (ret > 0)
225 {
226 *fresh = true;
227 rbr = byte;
228 }
229 }
230 else
231 rbr = dv_sockser_read (sd);
232
233 return rbr;
234 }
235
236 bu16
237 bfin_uart_get_status (struct hw *me)
238 {
239 SIM_DESC sd = hw_system (me);
240 struct bfin_uart *uart = hw_data (me);
241 int status = dv_sockser_status (sd);
242 bu16 lsr = 0;
243
244 if (status & DV_SOCKSER_DISCONNECTED)
245 {
246 if (uart->saved_count <= 0)
247 uart->saved_count = sim_io_poll_read (sd, 0/*STDIN*/,
248 &uart->saved_byte, 1);
249 lsr |= TEMT | THRE | (uart->saved_count > 0 ? DR : 0);
250 }
251 else
252 lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
253 (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
254
255 return lsr;
256 }
257
258 static unsigned
259 bfin_uart_io_read_buffer (struct hw *me, void *dest,
260 int space, address_word addr, unsigned nr_bytes)
261 {
262 struct bfin_uart *uart = hw_data (me);
263 bu32 mmr_off;
264 bu16 *valuep;
265
266 /* Invalid access mode is higher priority than missing register. */
267 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
268 return 0;
269
270 mmr_off = addr - uart->base;
271 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
272
273 HW_TRACE_READ ();
274
275 switch (mmr_off)
276 {
277 case mmr_offset(dll):
278 if (uart->lcr & DLAB)
279 dv_store_2 (dest, uart->dll);
280 else
281 {
282 uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
283 dv_store_2 (dest, uart->rbr);
284 }
285 break;
286 case mmr_offset(dlh):
287 if (uart->lcr & DLAB)
288 dv_store_2 (dest, uart->dlh);
289 else
290 dv_store_2 (dest, uart->ier);
291 break;
292 case mmr_offset(lsr):
293 /* XXX: Reads are destructive on most parts, but not all ... */
294 uart->lsr |= bfin_uart_get_status (me);
295 dv_store_2 (dest, *valuep);
296 uart->lsr = 0;
297 break;
298 case mmr_offset(iir):
299 /* XXX: Reads are destructive ... */
300 case mmr_offset(lcr):
301 case mmr_offset(mcr):
302 case mmr_offset(scr):
303 case mmr_offset(gctl):
304 dv_store_2 (dest, *valuep);
305 break;
306 default:
307 dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
308 return 0;
309 }
310
311 return nr_bytes;
312 }
313
314 unsigned
315 bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
316 {
317 SIM_DESC sd = hw_system (me);
318 struct bfin_uart *uart = hw_data (me);
319 int status = dv_sockser_status (sd);
320 unsigned i = 0;
321
322 if (status & DV_SOCKSER_DISCONNECTED)
323 {
324 int ret;
325
326 while (uart->saved_count > 0 && i < nr_bytes)
327 {
328 buffer[i++] = uart->saved_byte;
329 --uart->saved_count;
330 }
331
332 ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
333 if (ret > 0)
334 i += ret;
335 }
336 else
337 buffer[i++] = dv_sockser_read (sd);
338
339 return i;
340 }
341
342 static unsigned
343 bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
344 unsigned_word addr, unsigned nr_bytes)
345 {
346 HW_TRACE_DMA_READ ();
347 return bfin_uart_read_buffer (me, dest, nr_bytes);
348 }
349
350 unsigned
351 bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
352 unsigned nr_bytes)
353 {
354 SIM_DESC sd = hw_system (me);
355 int status = dv_sockser_status (sd);
356
357 if (status & DV_SOCKSER_DISCONNECTED)
358 {
359 sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
360 sim_io_flush_stdout (sd);
361 }
362 else
363 {
364 /* Normalize errors to a value of 0. */
365 int ret = dv_sockser_write_buffer (sd, buffer, nr_bytes);
366 nr_bytes = CLAMP (ret, 0, nr_bytes);
367 }
368
369 return nr_bytes;
370 }
371
372 static unsigned
373 bfin_uart_dma_write_buffer (struct hw *me, const void *source,
374 int space, unsigned_word addr,
375 unsigned nr_bytes,
376 int violate_read_only_section)
377 {
378 struct bfin_uart *uart = hw_data (me);
379 unsigned ret;
380
381 HW_TRACE_DMA_WRITE ();
382
383 ret = bfin_uart_write_buffer (me, source, nr_bytes);
384
385 if (ret == nr_bytes && (uart->ier & ETBEI))
386 hw_port_event (me, DV_PORT_TX, 1);
387
388 return ret;
389 }
390
391 static const struct hw_port_descriptor bfin_uart_ports[] =
392 {
393 { "tx", DV_PORT_TX, 0, output_port, },
394 { "rx", DV_PORT_RX, 0, output_port, },
395 { "stat", DV_PORT_STAT, 0, output_port, },
396 { NULL, 0, 0, 0, },
397 };
398
399 static void
400 attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
401 {
402 address_word attach_address;
403 int attach_space;
404 unsigned attach_size;
405 reg_property_spec reg;
406
407 if (hw_find_property (me, "reg") == NULL)
408 hw_abort (me, "Missing \"reg\" property");
409
410 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
411 hw_abort (me, "\"reg\" property must contain three addr/size entries");
412
413 hw_unit_address_to_attach_address (hw_parent (me),
414 &reg.address,
415 &attach_space, &attach_address, me);
416 hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
417
418 if (attach_size != BFIN_MMR_UART_SIZE)
419 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
420
421 hw_attach_address (hw_parent (me),
422 0, attach_space, attach_address, attach_size, me);
423
424 uart->base = attach_address;
425 }
426
427 static void
428 bfin_uart_finish (struct hw *me)
429 {
430 struct bfin_uart *uart;
431
432 uart = HW_ZALLOC (me, struct bfin_uart);
433
434 set_hw_data (me, uart);
435 set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
436 set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
437 set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
438 set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
439 set_hw_ports (me, bfin_uart_ports);
440
441 attach_bfin_uart_regs (me, uart);
442
443 /* Initialize the UART. */
444 uart->dll = 0x0001;
445 uart->iir = 0x0001;
446 uart->lsr = 0x0060;
447 }
448
449 const struct hw_descriptor dv_bfin_uart_descriptor[] =
450 {
451 {"bfin_uart", bfin_uart_finish,},
452 {NULL, NULL},
453 };