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