xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/lm32/dv-lm32uart.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1a5a4af3bSchristos /*  Lattice Mico32 UART model.
2a5a4af3bSchristos     Contributed by Jon Beniston <jon@beniston.com>
3a5a4af3bSchristos 
4*8b657b07Schristos    Copyright (C) 2009-2023 Free Software Foundation, Inc.
5a5a4af3bSchristos 
6a5a4af3bSchristos    This file is part of GDB.
7a5a4af3bSchristos 
8a5a4af3bSchristos    This program is free software; you can redistribute it and/or modify
9a5a4af3bSchristos    it under the terms of the GNU General Public License as published by
10a5a4af3bSchristos    the Free Software Foundation; either version 3 of the License, or
11a5a4af3bSchristos    (at your option) any later version.
12a5a4af3bSchristos 
13a5a4af3bSchristos    This program is distributed in the hope that it will be useful,
14a5a4af3bSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a5a4af3bSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a5a4af3bSchristos    GNU General Public License for more details.
17a5a4af3bSchristos 
18a5a4af3bSchristos    You should have received a copy of the GNU General Public License
19a5a4af3bSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20a5a4af3bSchristos 
21*8b657b07Schristos /* This must come before any other includes.  */
22*8b657b07Schristos #include "defs.h"
23*8b657b07Schristos 
24a5a4af3bSchristos #include "sim-main.h"
25a5a4af3bSchristos #include "hw-main.h"
26a5a4af3bSchristos #include "sim-assert.h"
27a5a4af3bSchristos 
28a5a4af3bSchristos #include <stdio.h>
29*8b657b07Schristos #include <sys/select.h>
30a5a4af3bSchristos #include <sys/time.h>
31a5a4af3bSchristos 
32a5a4af3bSchristos struct lm32uart
33a5a4af3bSchristos {
34a5a4af3bSchristos   unsigned base;		/* Base address of this UART.  */
35a5a4af3bSchristos   unsigned limit;		/* Limit address of this UART.  */
36a5a4af3bSchristos   unsigned char rbr;
37a5a4af3bSchristos   unsigned char thr;
38a5a4af3bSchristos   unsigned char ier;
39a5a4af3bSchristos   unsigned char iir;
40a5a4af3bSchristos   unsigned char lcr;
41a5a4af3bSchristos   unsigned char mcr;
42a5a4af3bSchristos   unsigned char lsr;
43a5a4af3bSchristos   unsigned char msr;
44a5a4af3bSchristos   unsigned char div;
45a5a4af3bSchristos   struct hw_event *event;
46a5a4af3bSchristos };
47a5a4af3bSchristos 
48a5a4af3bSchristos /* UART registers.  */
49a5a4af3bSchristos 
50a5a4af3bSchristos #define LM32_UART_RBR           0x0
51a5a4af3bSchristos #define LM32_UART_THR           0x0
52a5a4af3bSchristos #define LM32_UART_IER           0x4
53a5a4af3bSchristos #define LM32_UART_IIR           0x8
54a5a4af3bSchristos #define LM32_UART_LCR           0xc
55a5a4af3bSchristos #define LM32_UART_MCR           0x10
56a5a4af3bSchristos #define LM32_UART_LSR           0x14
57a5a4af3bSchristos #define LM32_UART_MSR           0x18
58a5a4af3bSchristos #define LM32_UART_DIV           0x1c
59a5a4af3bSchristos 
60a5a4af3bSchristos #define LM32_UART_IER_RX_INT    0x1
61a5a4af3bSchristos #define LM32_UART_IER_TX_INT    0x2
62a5a4af3bSchristos 
63a5a4af3bSchristos #define MICOUART_IIR_TXRDY      0x2
64a5a4af3bSchristos #define MICOUART_IIR_RXRDY      0x4
65a5a4af3bSchristos 
66a5a4af3bSchristos #define LM32_UART_LSR_RX_RDY    0x01
67a5a4af3bSchristos #define LM32_UART_LSR_TX_RDY    0x20
68a5a4af3bSchristos 
69a5a4af3bSchristos #define LM32_UART_LCR_WLS_MASK  0x3
70a5a4af3bSchristos #define LM32_UART_LCR_WLS_5     0x0
71a5a4af3bSchristos #define LM32_UART_LCR_WLS_6     0x1
72a5a4af3bSchristos #define LM32_UART_LCR_WLS_7     0x2
73a5a4af3bSchristos #define LM32_UART_LCR_WLS_8     0x3
74a5a4af3bSchristos 
75a5a4af3bSchristos /* UART ports.  */
76a5a4af3bSchristos 
77a5a4af3bSchristos enum
78a5a4af3bSchristos {
79a5a4af3bSchristos   INT_PORT
80a5a4af3bSchristos };
81a5a4af3bSchristos 
82a5a4af3bSchristos static const struct hw_port_descriptor lm32uart_ports[] = {
83a5a4af3bSchristos   {"int", INT_PORT, 0, output_port},
84a5a4af3bSchristos   {}
85a5a4af3bSchristos };
86a5a4af3bSchristos 
87a5a4af3bSchristos static void
88a5a4af3bSchristos do_uart_tx_event (struct hw *me, void *data)
89a5a4af3bSchristos {
90a5a4af3bSchristos   struct lm32uart *uart = hw_data (me);
91a5a4af3bSchristos   char c;
92a5a4af3bSchristos 
93a5a4af3bSchristos   /* Generate interrupt when transmission is complete.  */
94a5a4af3bSchristos   if (uart->ier & LM32_UART_IER_TX_INT)
95a5a4af3bSchristos     {
96a5a4af3bSchristos       /* Generate interrupt */
97a5a4af3bSchristos       hw_port_event (me, INT_PORT, 1);
98a5a4af3bSchristos     }
99a5a4af3bSchristos 
100a5a4af3bSchristos   /* Indicate which interrupt has occured.  */
101a5a4af3bSchristos   uart->iir = MICOUART_IIR_TXRDY;
102a5a4af3bSchristos 
103a5a4af3bSchristos   /* Indicate THR is empty.  */
104a5a4af3bSchristos   uart->lsr |= LM32_UART_LSR_TX_RDY;
105a5a4af3bSchristos 
106a5a4af3bSchristos   /* Output the character in the THR.  */
107a5a4af3bSchristos   c = (char) uart->thr;
108a5a4af3bSchristos 
109a5a4af3bSchristos   /* WLS field in LCR register specifies the number of bits to output.  */
110a5a4af3bSchristos   switch (uart->lcr & LM32_UART_LCR_WLS_MASK)
111a5a4af3bSchristos     {
112a5a4af3bSchristos     case LM32_UART_LCR_WLS_5:
113a5a4af3bSchristos       c &= 0x1f;
114a5a4af3bSchristos       break;
115a5a4af3bSchristos     case LM32_UART_LCR_WLS_6:
116a5a4af3bSchristos       c &= 0x3f;
117a5a4af3bSchristos       break;
118a5a4af3bSchristos     case LM32_UART_LCR_WLS_7:
119a5a4af3bSchristos       c &= 0x7f;
120a5a4af3bSchristos       break;
121a5a4af3bSchristos     }
122a5a4af3bSchristos   printf ("%c", c);
123a5a4af3bSchristos }
124a5a4af3bSchristos 
125a5a4af3bSchristos static unsigned
126a5a4af3bSchristos lm32uart_io_write_buffer (struct hw *me,
127a5a4af3bSchristos 			  const void *source,
128a5a4af3bSchristos 			  int space, unsigned_word base, unsigned nr_bytes)
129a5a4af3bSchristos {
130a5a4af3bSchristos   struct lm32uart *uart = hw_data (me);
131a5a4af3bSchristos   int uart_reg;
132a5a4af3bSchristos   const unsigned char *source_bytes = source;
133a5a4af3bSchristos   int value = 0;
134a5a4af3bSchristos 
135a5a4af3bSchristos   HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
136a5a4af3bSchristos 	     (int) nr_bytes, value));
137a5a4af3bSchristos 
138a5a4af3bSchristos   if (nr_bytes == 4)
139a5a4af3bSchristos     value = (source_bytes[0] << 24)
140a5a4af3bSchristos       | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
141a5a4af3bSchristos   else
142a5a4af3bSchristos     hw_abort (me, "write of unsupported number of bytes: %d.", nr_bytes);
143a5a4af3bSchristos 
144a5a4af3bSchristos   uart_reg = base - uart->base;
145a5a4af3bSchristos 
146a5a4af3bSchristos   switch (uart_reg)
147a5a4af3bSchristos     {
148a5a4af3bSchristos     case LM32_UART_THR:
149a5a4af3bSchristos       /* Buffer the character to output.  */
150a5a4af3bSchristos       uart->thr = value;
151a5a4af3bSchristos 
152a5a4af3bSchristos       /* Indicate the THR is full.  */
153a5a4af3bSchristos       uart->lsr &= ~LM32_UART_LSR_TX_RDY;
154a5a4af3bSchristos 
155a5a4af3bSchristos       /* deassert interrupt when IER is loaded.  */
156a5a4af3bSchristos       uart->iir &= ~MICOUART_IIR_TXRDY;
157a5a4af3bSchristos 
158a5a4af3bSchristos       /* schedule an event to output the character.  */
159a5a4af3bSchristos       hw_event_queue_schedule (me, 1, do_uart_tx_event, 0);
160a5a4af3bSchristos 
161a5a4af3bSchristos       break;
162a5a4af3bSchristos     case LM32_UART_IER:
163a5a4af3bSchristos       uart->ier = value;
164a5a4af3bSchristos       if ((value & LM32_UART_IER_TX_INT)
165a5a4af3bSchristos 	  && (uart->lsr & LM32_UART_LSR_TX_RDY))
166a5a4af3bSchristos 	{
167a5a4af3bSchristos 	  /* hw_event_queue_schedule (me, 1, do_uart_tx_event, 0); */
168a5a4af3bSchristos 	  uart->lsr |= LM32_UART_LSR_TX_RDY;
169a5a4af3bSchristos 	  uart->iir |= MICOUART_IIR_TXRDY;
170a5a4af3bSchristos 	  hw_port_event (me, INT_PORT, 1);
171a5a4af3bSchristos 	}
172a5a4af3bSchristos       else if ((value & LM32_UART_IER_TX_INT) == 0)
173a5a4af3bSchristos 	{
174a5a4af3bSchristos 	  hw_port_event (me, INT_PORT, 0);
175a5a4af3bSchristos 	}
176a5a4af3bSchristos       break;
177a5a4af3bSchristos     case LM32_UART_IIR:
178a5a4af3bSchristos       uart->iir = value;
179a5a4af3bSchristos       break;
180a5a4af3bSchristos     case LM32_UART_LCR:
181a5a4af3bSchristos       uart->lcr = value;
182a5a4af3bSchristos       break;
183a5a4af3bSchristos     case LM32_UART_MCR:
184a5a4af3bSchristos       uart->mcr = value;
185a5a4af3bSchristos       break;
186a5a4af3bSchristos     case LM32_UART_LSR:
187a5a4af3bSchristos       uart->lsr = value;
188a5a4af3bSchristos       break;
189a5a4af3bSchristos     case LM32_UART_MSR:
190a5a4af3bSchristos       uart->msr = value;
191a5a4af3bSchristos       break;
192a5a4af3bSchristos     case LM32_UART_DIV:
193a5a4af3bSchristos       uart->div = value;
194a5a4af3bSchristos       break;
195a5a4af3bSchristos     default:
196a5a4af3bSchristos       hw_abort (me, "write to invalid register address: 0x%x.", uart_reg);
197a5a4af3bSchristos     }
198a5a4af3bSchristos 
199a5a4af3bSchristos   return nr_bytes;
200a5a4af3bSchristos }
201a5a4af3bSchristos 
202a5a4af3bSchristos static unsigned
203a5a4af3bSchristos lm32uart_io_read_buffer (struct hw *me,
204a5a4af3bSchristos 			 void *dest,
205a5a4af3bSchristos 			 int space, unsigned_word base, unsigned nr_bytes)
206a5a4af3bSchristos {
207a5a4af3bSchristos   struct lm32uart *uart = hw_data (me);
208a5a4af3bSchristos   int uart_reg;
209a5a4af3bSchristos   int value;
210a5a4af3bSchristos   unsigned char *dest_bytes = dest;
211a5a4af3bSchristos   fd_set fd;
212a5a4af3bSchristos   struct timeval tv;
213a5a4af3bSchristos 
214a5a4af3bSchristos   HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes));
215a5a4af3bSchristos 
216a5a4af3bSchristos   uart_reg = base - uart->base;
217a5a4af3bSchristos 
218a5a4af3bSchristos   switch (uart_reg)
219a5a4af3bSchristos     {
220a5a4af3bSchristos     case LM32_UART_RBR:
221a5a4af3bSchristos       value = getchar ();
222a5a4af3bSchristos       uart->lsr &= ~LM32_UART_LSR_RX_RDY;
223a5a4af3bSchristos       break;
224a5a4af3bSchristos     case LM32_UART_IER:
225a5a4af3bSchristos       value = uart->ier;
226a5a4af3bSchristos       break;
227a5a4af3bSchristos     case LM32_UART_IIR:
228a5a4af3bSchristos       value = uart->iir;
229a5a4af3bSchristos       break;
230a5a4af3bSchristos     case LM32_UART_LCR:
231a5a4af3bSchristos       value = uart->lcr;
232a5a4af3bSchristos       break;
233a5a4af3bSchristos     case LM32_UART_MCR:
234a5a4af3bSchristos       value = uart->mcr;
235a5a4af3bSchristos       break;
236a5a4af3bSchristos     case LM32_UART_LSR:
237a5a4af3bSchristos       /* Check to see if any data waiting in stdin.  */
238a5a4af3bSchristos       FD_ZERO (&fd);
239a5a4af3bSchristos       FD_SET (fileno (stdin), &fd);
240a5a4af3bSchristos       tv.tv_sec = 0;
241a5a4af3bSchristos       tv.tv_usec = 1;
242a5a4af3bSchristos       if (select (fileno (stdin) + 1, &fd, NULL, NULL, &tv))
243a5a4af3bSchristos 	uart->lsr |= LM32_UART_LSR_RX_RDY;
244a5a4af3bSchristos       value = uart->lsr;
245a5a4af3bSchristos       break;
246a5a4af3bSchristos     case LM32_UART_MSR:
247a5a4af3bSchristos       value = uart->msr;
248a5a4af3bSchristos       break;
249a5a4af3bSchristos     case LM32_UART_DIV:
250a5a4af3bSchristos       value = uart->div;
251a5a4af3bSchristos       break;
252a5a4af3bSchristos     default:
253a5a4af3bSchristos       hw_abort (me, "read from invalid register address: 0x%x.", uart_reg);
254a5a4af3bSchristos     }
255a5a4af3bSchristos 
256a5a4af3bSchristos   if (nr_bytes == 4)
257a5a4af3bSchristos     {
258a5a4af3bSchristos       dest_bytes[0] = value >> 24;
259a5a4af3bSchristos       dest_bytes[1] = value >> 16;
260a5a4af3bSchristos       dest_bytes[2] = value >> 8;
261a5a4af3bSchristos       dest_bytes[3] = value;
262a5a4af3bSchristos     }
263a5a4af3bSchristos   else
264a5a4af3bSchristos     hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes);
265a5a4af3bSchristos 
266a5a4af3bSchristos   return nr_bytes;
267a5a4af3bSchristos }
268a5a4af3bSchristos 
269a5a4af3bSchristos static void
270a5a4af3bSchristos attach_lm32uart_regs (struct hw *me, struct lm32uart *uart)
271a5a4af3bSchristos {
272a5a4af3bSchristos   unsigned_word attach_address;
273a5a4af3bSchristos   int attach_space;
274a5a4af3bSchristos   unsigned attach_size;
275a5a4af3bSchristos   reg_property_spec reg;
276a5a4af3bSchristos 
277a5a4af3bSchristos   if (hw_find_property (me, "reg") == NULL)
278a5a4af3bSchristos     hw_abort (me, "Missing \"reg\" property");
279a5a4af3bSchristos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
280a5a4af3bSchristos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
281a5a4af3bSchristos   hw_unit_address_to_attach_address (hw_parent (me),
282a5a4af3bSchristos 				     &reg.address,
283a5a4af3bSchristos 				     &attach_space, &attach_address, me);
284a5a4af3bSchristos   uart->base = attach_address;
285a5a4af3bSchristos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
286a5a4af3bSchristos   uart->limit = attach_address + (attach_size - 1);
287a5a4af3bSchristos   hw_attach_address (hw_parent (me),
288a5a4af3bSchristos 		     0, attach_space, attach_address, attach_size, me);
289a5a4af3bSchristos }
290a5a4af3bSchristos 
291a5a4af3bSchristos static void
292a5a4af3bSchristos lm32uart_finish (struct hw *me)
293a5a4af3bSchristos {
294a5a4af3bSchristos   struct lm32uart *uart;
295a5a4af3bSchristos   int i;
296a5a4af3bSchristos 
297a5a4af3bSchristos   uart = HW_ZALLOC (me, struct lm32uart);
298a5a4af3bSchristos   set_hw_data (me, uart);
299a5a4af3bSchristos   set_hw_io_read_buffer (me, lm32uart_io_read_buffer);
300a5a4af3bSchristos   set_hw_io_write_buffer (me, lm32uart_io_write_buffer);
301a5a4af3bSchristos   set_hw_ports (me, lm32uart_ports);
302a5a4af3bSchristos 
303a5a4af3bSchristos   /* Attach ourself to our parent bus.  */
304a5a4af3bSchristos   attach_lm32uart_regs (me, uart);
305a5a4af3bSchristos 
306a5a4af3bSchristos   /* Initialize the UART.  */
307a5a4af3bSchristos   uart->rbr = 0;
308a5a4af3bSchristos   uart->thr = 0;
309a5a4af3bSchristos   uart->ier = 0;
310a5a4af3bSchristos   uart->iir = 0;
311a5a4af3bSchristos   uart->lcr = 0;
312a5a4af3bSchristos   uart->mcr = 0;
313a5a4af3bSchristos   uart->lsr = LM32_UART_LSR_TX_RDY;
314a5a4af3bSchristos   uart->msr = 0;
315a5a4af3bSchristos   uart->div = 0;		/* By setting to zero, characters are output immediately.  */
316a5a4af3bSchristos }
317a5a4af3bSchristos 
318a5a4af3bSchristos const struct hw_descriptor dv_lm32uart_descriptor[] = {
319a5a4af3bSchristos   {"lm32uart", lm32uart_finish,},
320a5a4af3bSchristos   {NULL},
321a5a4af3bSchristos };
322