MicroBlaze: Add features/microblaze-linux.xml
[binutils-gdb.git] / sim / bfin / dv-bfin_uart.c
blob24b7faaaef9a01247441bc75347596be5e95bc37
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "old style" UARTs on BF53x/etc... parts.
4 Copyright (C) 2010-2024 Free Software Foundation, Inc.
5 Contributed by Analog Devices, Inc.
7 This file is part of simulators.
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.
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.
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/>. */
22 /* This must come before any other includes. */
23 #include "defs.h"
25 #include "sim-main.h"
26 #include "dv-sockser.h"
27 #include "devices.h"
28 #include "dv-bfin_uart.h"
30 /* XXX: Should we bother emulating the TX/RX FIFOs ? */
32 /* Internal state needs to be the same as bfin_uart2. */
33 struct bfin_uart
35 /* This top portion matches common dv_bfin struct. */
36 bu32 base;
37 struct hw *dma_master;
38 bool acked;
40 struct hw_event *handler;
41 char saved_byte;
42 int saved_count;
44 /* This is aliased to DLH. */
45 bu16 ier;
46 /* These are aliased to DLL. */
47 bu16 thr, rbr;
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);
61 #define mmr_base() offsetof(struct bfin_uart, dll)
62 #define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
64 static const char * const mmr_names[] =
66 "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
67 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
69 static const char *mmr_name (struct bfin_uart *uart, bu32 idx)
71 if (uart->lcr & DLAB)
72 if (idx < 2)
73 return idx == 0 ? "UART_DLL" : "UART_DLH";
74 return mmr_names[idx];
76 #define mmr_name(off) mmr_name (uart, (off) / 4)
78 static void
79 bfin_uart_poll (struct hw *me, void *data)
81 struct bfin_uart *uart = data;
82 bu16 lsr;
84 uart->handler = NULL;
86 lsr = bfin_uart_get_status (me);
87 if (lsr & DR)
88 hw_port_event (me, DV_PORT_RX, 1);
90 bfin_uart_reschedule (me);
93 void
94 bfin_uart_reschedule (struct hw *me)
96 struct bfin_uart *uart = hw_data (me);
98 if (uart->ier & ERBFI)
100 if (!uart->handler)
101 uart->handler = hw_event_queue_schedule (me, 10000,
102 bfin_uart_poll, uart);
104 else
106 if (uart->handler)
108 hw_event_queue_deschedule (me, uart->handler);
109 uart->handler = NULL;
114 bu16
115 bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr)
117 struct bfin_uart *uart = hw_data (me);
118 unsigned char ch = thr;
120 if (mcr & LOOP_ENA)
122 /* XXX: This probably doesn't work exactly right with
123 external FIFOs ... */
124 uart->saved_byte = thr;
125 uart->saved_count = 1;
128 bfin_uart_write_buffer (me, &ch, 1);
130 return thr;
133 static unsigned
134 bfin_uart_io_write_buffer (struct hw *me, const void *source,
135 int space, address_word addr, unsigned nr_bytes)
137 struct bfin_uart *uart = hw_data (me);
138 bu32 mmr_off;
139 bu32 value;
140 bu16 *valuep;
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;
146 value = dv_load_2 (source);
147 mmr_off = addr - uart->base;
148 valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
150 HW_TRACE_WRITE ();
152 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
153 switch (mmr_off)
155 case mmr_offset(dll):
156 if (uart->lcr & DLAB)
157 uart->dll = value;
158 else
160 uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
162 if (uart->ier & ETBEI)
163 hw_port_event (me, DV_PORT_TX, 1);
165 break;
166 case mmr_offset(dlh):
167 if (uart->lcr & DLAB)
168 uart->dlh = value;
169 else
171 uart->ier = value;
172 bfin_uart_reschedule (me);
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;
190 return nr_bytes;
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)
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;
202 /* NB: The "uart" here may only use interal state. */
204 if (!fresh)
205 fresh = &_fresh;
207 *fresh = false;
209 if (uart->saved_count > 0)
211 *fresh = true;
212 rbr = uart->saved_byte;
213 --uart->saved_count;
215 else if (mcr & LOOP_ENA)
217 /* RX is disconnected, so only return local data. */
219 else if (status & DV_SOCKSER_DISCONNECTED)
221 char byte;
222 int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
224 if (ret > 0)
226 *fresh = true;
227 rbr = byte;
230 else
231 rbr = dv_sockser_read (sd);
233 return rbr;
236 bu16
237 bfin_uart_get_status (struct hw *me)
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;
244 if (status & DV_SOCKSER_DISCONNECTED)
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);
251 else
252 lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
253 (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
255 return lsr;
258 static unsigned
259 bfin_uart_io_read_buffer (struct hw *me, void *dest,
260 int space, address_word addr, unsigned nr_bytes)
262 struct bfin_uart *uart = hw_data (me);
263 bu32 mmr_off;
264 bu16 *valuep;
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;
270 mmr_off = addr - uart->base;
271 valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
273 HW_TRACE_READ ();
275 switch (mmr_off)
277 case mmr_offset(dll):
278 if (uart->lcr & DLAB)
279 dv_store_2 (dest, uart->dll);
280 else
282 uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
283 dv_store_2 (dest, uart->rbr);
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;
311 return nr_bytes;
314 unsigned
315 bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
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;
322 if (status & DV_SOCKSER_DISCONNECTED)
324 int ret;
326 while (uart->saved_count > 0 && i < nr_bytes)
328 buffer[i++] = uart->saved_byte;
329 --uart->saved_count;
332 ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
333 if (ret > 0)
334 i += ret;
336 else
337 buffer[i++] = dv_sockser_read (sd);
339 return i;
342 static unsigned
343 bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
344 unsigned_word addr, unsigned nr_bytes)
346 HW_TRACE_DMA_READ ();
347 return bfin_uart_read_buffer (me, dest, nr_bytes);
350 unsigned
351 bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
352 unsigned nr_bytes)
354 SIM_DESC sd = hw_system (me);
355 int status = dv_sockser_status (sd);
357 if (status & DV_SOCKSER_DISCONNECTED)
359 sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
360 sim_io_flush_stdout (sd);
362 else
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);
369 return nr_bytes;
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)
378 struct bfin_uart *uart = hw_data (me);
379 unsigned ret;
381 HW_TRACE_DMA_WRITE ();
383 ret = bfin_uart_write_buffer (me, source, nr_bytes);
385 if (ret == nr_bytes && (uart->ier & ETBEI))
386 hw_port_event (me, DV_PORT_TX, 1);
388 return ret;
391 static const struct hw_port_descriptor bfin_uart_ports[] =
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, },
399 static void
400 attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
402 address_word attach_address;
403 int attach_space;
404 unsigned attach_size;
405 reg_property_spec reg;
407 if (hw_find_property (me, "reg") == NULL)
408 hw_abort (me, "Missing \"reg\" property");
410 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
411 hw_abort (me, "\"reg\" property must contain three addr/size entries");
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);
418 if (attach_size != BFIN_MMR_UART_SIZE)
419 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
421 hw_attach_address (hw_parent (me),
422 0, attach_space, attach_address, attach_size, me);
424 uart->base = attach_address;
427 static void
428 bfin_uart_finish (struct hw *me)
430 struct bfin_uart *uart;
432 uart = HW_ZALLOC (me, struct bfin_uart);
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);
441 attach_bfin_uart_regs (me, uart);
443 /* Initialize the UART. */
444 uart->dll = 0x0001;
445 uart->iir = 0x0001;
446 uart->lsr = 0x0060;
449 const struct hw_descriptor dv_bfin_uart_descriptor[] =
451 {"bfin_uart", bfin_uart_finish,},
452 {NULL, NULL},