Main Page

uart.c
Go to the documentation of this file.
1 /*
2 * $Id: uart.c,v 1.4 2008/03/16 21:14:08 joerg_wunsch Exp $
3 *
4 ****************************************************************************
5 *
6 * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7 * Copyright (C) 2003, 2004 Keith Gudger
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 2 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, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ****************************************************************************
24 */
25
26 /**
27 * \file uart.c
28 * \brief Module to simulate the AVR's uart module.
29 */
30
31 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "avrerror.h"
38 #include "avrmalloc.h"
39 #include "avrclass.h"
40 #include "utils.h"
41 #include "callback.h"
42 #include "op_names.h"
43
44 #include "storage.h"
45 #include "flash.h"
46
47 #include "vdevs.h"
48 #include "memory.h"
49 #include "stack.h"
50 #include "register.h"
51 #include "sram.h"
52 #include "eeprom.h"
53 #include "timers.h"
54 #include "ports.h"
55 #include "uart.h"
56
57 #include "avrcore.h"
58
59 #include "intvects.h"
60
61 /****************************************************************************\
62 *
63 * uart Interrupts
64 *
65 \****************************************************************************/
66
67 static void uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
68 void *data);
69 static uint8_t uart_intr_read (VDevice *dev, int addr);
70 static void uart_intr_write (VDevice *dev, int addr, uint8_t val);
71 static void uart_intr_reset (VDevice *dev);
72 static int uart_intr_cb (uint64_t time, AvrClass *data);
73
74 unsigned int UART_Int_Table[] = {
75 irq_vect_table_index (UART_RX), /* uart Rx complete */
76 irq_vect_table_index (UART_UDRE), /* uart data register empty */
77 irq_vect_table_index (UART_TX) /* uart Tx complete */
78 };
79
80 unsigned int UART0_Int_Table[] = {
81 irq_vect_table_index (USART0_RX), /* uart Rx complete */
82 irq_vect_table_index (USART0_UDRE), /* uart data register empty */
83 irq_vect_table_index (USART0_TX) /* uart Tx complete */
84 };
85
86 unsigned int UART1_Int_Table[] = {
87 irq_vect_table_index (USART1_RX), /* uart Rx complete */
88 irq_vect_table_index (USART1_UDRE), /* uart data register empty */
89 irq_vect_table_index (USART1_TX) /* uart Tx complete */
90 };
91
92 /** \brief Allocate a new uart interrupt */
93
94 VDevice *
95 uart_int_create (int addr, char *name, int rel_addr, void *data)
96 {
97 if (data)
98 return (VDevice *)uart_intr_new (addr, name, data);
99 else
100 avr_error ("Attempted UART create with NULL data pointer");
101 return 0;
102 }
103
104 UARTIntr_T *
105 uart_intr_new (int addr, char *name, void *data)
106 {
107 uint8_t *uart_num = (uint8_t *) data;
108 UARTIntr_T *uart;
109
110 uart = avr_new (UARTIntr_T, 1);
111 uart_intr_construct (uart, addr, name);
112 class_overload_destroy ((AvrClass *)uart, uart_intr_destroy);
113
114 if (*uart_num == USART0)
115 uart->Int_Table = &UART0_Int_Table[0];
116 else if (*uart_num == USART1)
117 uart->Int_Table = &UART1_Int_Table[0];
118 else
119 uart->Int_Table = &UART_Int_Table[0];
120
121 uart_iadd_addr ((VDevice *)uart, addr, name, 0, NULL);
122 return uart;
123 }
124
125 /** \brief Constructor for uart interrupt object. */
126
127 void
128 uart_intr_construct (UARTIntr_T *uart, int addr, char *name)
129 {
130 if (uart == NULL)
131 avr_error ("passed null ptr");
132
133 vdev_construct ((VDevice *)uart, uart_intr_read, uart_intr_write,
134 uart_intr_reset, uart_iadd_addr);
135
136 uart_intr_reset ((VDevice *)uart);
137 }
138
139 static void
140 uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
141 {
142 UARTIntr_T *uart = (UARTIntr_T *)vdev;
143
144 if (strncmp ("UBRRH", name, 5) == 0)
145 {
146 uart->ubrrh_addr = addr;
147 }
148
149 else if ((strncmp ("UBRR", name, 4) == 0)
150 || (strncmp ("UBRR0", name, 5) == 0)
151 || (strncmp ("UBRR1", name, 5) == 0))
152 {
153 uart->ubrrl_addr = addr;
154 }
155
156 else if ((strncmp ("USR", name, 3) == 0)
157 || (strncmp ("UCSR0A", name, 6) == 0)
158 || (strncmp ("UCSR1A", name, 6) == 0))
159 {
160 uart->usr_addr = addr;
161 }
162
163 else if ((strncmp ("UCR", name, 3) == 0)
164 || (strncmp ("UCSR0B", name, 6) == 0)
165 || (strncmp ("UCSR1B", name, 6) == 0))
166 {
167 uart->ucr_addr = addr;
168 }
169
170 else
171 {
172 avr_error ("invalid UART register name: '%s' @ 0x%04x", name, addr);
173 }
174 }
175
176 /** \brief Destructor for uart interrupt object. */
177
178 void
179 uart_intr_destroy (void *uart)
180 {
181 if (uart == NULL)
182 return;
183
184 vdev_destroy (uart);
185 }
186
187 static uint8_t
188 uart_intr_read (VDevice *dev, int addr)
189 {
190 UARTIntr_T *uart = (UARTIntr_T *)dev;
191
192 if (addr == uart->ubrrl_addr)
193 {
194 return (uart->ubrr & 0xff);
195 }
196
197 else if (addr == uart->ubrrh_addr)
198 {
199 return (uart->ubrr >> 8);
200 }
201
202 else if (addr == uart->ucr_addr)
203 {
204 return (uart->ucr);
205 }
206
207 else if (addr == uart->usr_addr)
208 {
209 return (uart->usr);
210 }
211
212 else
213 {
214 avr_error ("Bad address: 0x%04x", addr);
215 }
216
217 return 0; /* will never get here */
218 }
219
220 static void
221 uart_intr_write (VDevice *dev, int addr, uint8_t val)
222 {
223 UARTIntr_T *uart = (UARTIntr_T *)dev;
224 CallBack *cb;
225
226 if (addr == uart->ubrrl_addr)
227 {
228 uart->ubrr = val + (uart->ubrr_temp << 8);
229 }
230
231 else if (addr == uart->ubrrh_addr)
232 {
233 uart->ubrr_temp = val;
234 }
235
236 else if (addr == uart->usr)
237 {
238 if (val & mask_TXC)
239 uart->usr &= ~mask_TXC;
240 }
241
242 else if (addr == uart->ucr_addr)
243 {
244 (uart->ucr = val); /* look for interrupt enables */
245
246 if (((uart->ucr & mask_TXEN) && (uart->ucr & mask_TXCIE))
247 || ((uart->ucr & mask_RXEN) && (uart->ucr & mask_RXCIE))
248 || (uart->ucr & mask_UDRIE))
249 {
250 if (uart->intr_cb == NULL)
251 {
252 /* we need to install the intr_cb function */
253 cb = callback_new (uart_intr_cb, (AvrClass *)uart);
254 uart->intr_cb = cb;
255 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
256 }
257 }
258 else
259 {
260 uart->intr_cb = NULL;
261 /* no interrupt are enabled, remove the callback */
262 }
263 }
264
265 else
266 {
267 avr_error ("Bad address: 0x%04x", addr);
268 }
269 }
270
271 static void
272 uart_intr_reset (VDevice *dev)
273 {
274 UARTIntr_T *uart = (UARTIntr_T *)dev;
275
276 uart->intr_cb = NULL;
277
278 uart->ubrr = 0;
279 uart->usr = 0;
280 uart->ucr = 0;
281 uart->usr_shadow = 0;
282 }
283
284 static int
285 uart_intr_cb (uint64_t time, AvrClass *data)
286 {
287 UARTIntr_T *uart = (UARTIntr_T *)data;
288
289 if (uart->intr_cb == NULL)
290 return CB_RET_REMOVE;
291
292 if ((uart->ucr & mask_RXCIE) && (uart->usr & mask_RXC))
293 /* an enabled interrupt occured */
294 {
295 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
296 avr_core_irq_raise (core, (uart->Int_Table[URX]));
297 }
298
299 if ((uart->ucr & mask_TXCIE) && (uart->usr & mask_TXC))
300 /* an enabled interrupt occured */
301 {
302 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
303 avr_core_irq_raise (core, (uart->Int_Table[UTX]));
304 uart->usr &= ~mask_TXC;
305 }
306
307 if ((uart->ucr & mask_UDRIE) && (uart->usr & mask_UDRE)
308 && (uart->usr_shadow & mask_UDRE))
309 /* an enabled interrupt occured */
310 {
311 AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
312 avr_core_irq_raise (core, (uart->Int_Table[UUDRE]));
313 uart->usr_shadow &= ~mask_UDRE; /* only issue one interrupt / udre */
314 }
315
316 return CB_RET_RETAIN;
317 }
318
319 /****************************************************************************\
320 *
321 * uart
322 *
323 \****************************************************************************/
324
325 static void uart_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
326 void *data);
327 static uint8_t uart_read (VDevice *dev, int addr);
328 static void uart_write (VDevice *dev, int addr, uint8_t val);
329 static void uart_reset (VDevice *dev);
330 static int uart_clk_incr_cb (uint64_t ck, AvrClass *data);
331
332 /** \brief Allocate a new uart structure. */
333
334 VDevice *
335 uart_create (int addr, char *name, int rel_addr, void *data)
336 {
337 return (VDevice *)uart_new (addr, name, rel_addr);
338 }
339
340 UART_T *
341 uart_new (int addr, char *name, int rel_addr)
342 {
343 UART_T *uart;
344
345 uart = avr_new (UART_T, 1);
346 uart_construct (uart, addr, name, rel_addr);
347
348 class_overload_destroy ((AvrClass *)uart, uart_destroy);
349
350 return uart;
351 }
352
353 /** \brief Constructor for uart object. */
354
355 void
356 uart_construct (UART_T *uart, int addr, char *name, int rel_addr)
357 {
358 if (uart == NULL)
359 avr_error ("passed null ptr");
360
361 vdev_construct ((VDevice *)uart, uart_read, uart_write, uart_reset,
362 uart_add_addr);
363
364 uart_add_addr ((VDevice *)uart, addr, name, 0, NULL);
365 if (rel_addr)
366 uart->related_addr = rel_addr;
367 uart_reset ((VDevice *)uart);
368 }
369
370 static void
371 uart_add_addr (VDevice *vdev, int addr, char *name, int ref_addr, void *data)
372 {
373 UART_T *uart = (UART_T *)vdev;
374
375 if (strncmp ("UDR", name, 3) == 0)
376 {
377 uart->udr_addr = addr;
378 }
379
380 else
381 {
382 avr_error ("invalid SPI register name: '%s' @ 0x%04x", name, addr);
383 }
384 }
385
386 /** \brief Destructor for uart object. */
387
388 void
389 uart_destroy (void *uart)
390 {
391 if (uart == NULL)
392 return;
393
394 vdev_destroy (uart);
395 }
396
397 static uint8_t
398 uart_read (VDevice *dev, int addr)
399 {
400 UART_T *uart = (UART_T *)dev;
401 UARTIntr_T *uart_t;
402 uint16_t udr_temp;
403
404 uart_t =
405 (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
406 vdev_get_core ((VDevice *)
407 uart),
408 uart->related_addr);
409
410 if (addr == uart->udr_addr)
411 {
412 uart_t->usr &= ~mask_RXC; /* clear RXC bit in USR */
413 if (uart->clk_cb) /* call back already installed */
414 {
415 udr_temp = uart_port_rd (addr);
416 uart->udr_rx = (uint8_t) udr_temp; /* lower 8 bits */
417 if ((uart_t->ucr & mask_CHR9) && /* 9 bits rec'd */
418 (udr_temp & (1 << 8))) /* hi bit set */
419 uart_t->ucr |= mask_RXB8;
420 else
421 uart_t->ucr &= ~mask_RXB8;
422 }
423 return uart->udr_rx;
424 }
425
426 else
427 {
428 avr_error ("Bad address: 0x%04x", addr);
429 }
430
431 return 0; /* will never get here */
432 }
433
434 static void
435 uart_write (VDevice *dev, int addr, uint8_t val)
436 {
437 UART_T *uart = (UART_T *)dev;
438 UARTIntr_T *uart_t;
439 CallBack *cb;
440
441 uart_t =
442 (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
443 vdev_get_core ((VDevice *)
444 uart),
445 uart->related_addr);
446
447 if (addr == uart->udr_addr)
448 {
449 if (uart_t->usr & mask_UDRE)
450 {
451 uart_t->usr &= ~mask_UDRE;
452 uart_t->usr_shadow &= ~mask_UDRE;
453 }
454 else
455 {
456 uart_t->usr |= mask_UDRE;
457 uart_t->usr_shadow |= mask_UDRE;
458 }
459 uart->udr_tx = val;
460
461 /*
462 * When the user writes to UDR, a callback is installed for
463 * clock generated increments.
464 */
465
466 uart->divisor = (uart_t->ubrr + 1) * 16;
467
468 /* install the clock incrementor callback (with flair!) */
469
470 if (uart->clk_cb == NULL)
471 {
472 cb = callback_new (uart_clk_incr_cb, (AvrClass *)uart);
473 uart->clk_cb = cb;
474 avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)uart),
475 cb);
476 }
477
478 /* set up timer for 8 or 9 clocks based on ucr
479 (includes start and stop bits) */
480
481 uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
482 }
483
484 else
485 {
486 avr_error ("Bad address: 0x%04x", addr);
487 }
488 }
489
490 static void
491 uart_reset (VDevice *dev)
492 {
493 UART_T *uart = (UART_T *)dev;
494
495 uart->clk_cb = NULL;
496
497 uart->udr_rx = 0;
498 uart->udr_tx = 0;
499 uart->tcnt = 0;
500 uart->divisor = 0;
501 }
502
503 static int
504 uart_clk_incr_cb (uint64_t ck, AvrClass *data)
505 {
506 UART_T *uart = (UART_T *)data;
507 UARTIntr_T *uart_t;
508 uint8_t last = uart->tcnt;
509
510 uart_t =
511 (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
512 vdev_get_core ((VDevice *)
513 uart),
514 uart->related_addr);
515
516 if (uart->clk_cb == NULL)
517 return CB_RET_REMOVE;
518
519 if (uart->divisor <= 0)
520 avr_error ("Bad divisor value: %d", uart->divisor);
521
522 /* decrement clock if ck is a mutliple of divisor */
523
524 uart->tcnt -= ((ck % uart->divisor) == 0);
525
526 if (uart->tcnt != last) /* we've changed the counter */
527 {
528 if (uart->tcnt == 0)
529 {
530 if (uart_t->usr & mask_UDRE) /* data register empty */
531 {
532 uart_t->usr |= mask_TXC;
533 uart->clk_cb = NULL;
534 return CB_RET_REMOVE;
535 }
536 else /* there's a byte waiting to go */
537 {
538 uart_t->usr |= mask_UDRE;
539 uart_t->usr_shadow |= mask_UDRE; /* also write shadow */
540
541 /* set up timer for 8 or 9 clocks based on ucr,
542 (includes start and stop bits) */
543
544 uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
545 }
546 }
547 }
548
549 return CB_RET_RETAIN;
550 }
551
552 uint16_t
553 uart_port_rd (int addr)
554 {
555 int data;
556 char line[80];
557
558 while (1)
559 {
560 fprintf (stderr,
561 "\nEnter 9 bits of hex data to read into the uart at "
562 "address 0x%04x: ", addr);
563
564 /* try to read in a line of input */
565 if (fgets (line, sizeof (line), stdin) == NULL)
566 continue;
567
568 /* try to parse the line for a byte of data */
569 if (sscanf (line, "%x\n", &data) != 1)
570 continue;
571
572 break;
573 }
574
575 return (uint16_t) (data & 0x1ff);
576 }
577
578 void
579 uart_port_wr (uint8_t val)
580 {
581 fprintf (stderr, "wrote 0x%02x to uart\n", val);
582 }
avr_new
#define avr_new(type, count)
Macro for allocating memory.
Definition: avrmalloc.c:57
uart_destroy
void uart_destroy(void *uart)
Destructor for uart object.
Definition: uart.c:389
uart_intr_destroy
void uart_intr_destroy(void *uart)
Destructor for uart interrupt object.
Definition: uart.c:179
avr_core_async_cb_add
void avr_core_async_cb_add(AvrCore *core, CallBack *cb)
Add a new asynchronous callback to list.
uart_intr_construct
void uart_intr_construct(UARTIntr_T *uart, int addr, char *name)
Constructor for uart interrupt object.
Definition: uart.c:128
avr_core_get_vdev_by_addr
VDevice * avr_core_get_vdev_by_addr(AvrCore *core, int addr)
Returns the VDevice which handles the address addr.
vdev_destroy
void vdev_destroy(void *dev)
Destructor for a VDevice.
Definition: device.c:105
uart_int_create
VDevice * uart_int_create(int addr, char *name, int rel_addr, void *data)
Allocate a new uart interrupt.
Definition: uart.c:95
avr_core_irq_raise
void avr_core_irq_raise(AvrCore *core, unsigned int irq)
Raises an irq by adding it&#39;s data to the irq_pending list.
Definition: avrcore.c:854
vdev_get_core
AvrClass * vdev_get_core(VDevice *dev)
Get the core field.
uart_construct
void uart_construct(UART_T *uart, int addr, char *name, int rel_addr)
Constructor for uart object.
Definition: uart.c:356
vdev_construct
void vdev_construct(VDevice *dev, VDevFP_Read rd, VDevFP_Write wr, VDevFP_Reset reset, VDevFP_AddAddr add_addr)
Constructor for a VDevice.
Definition: device.c:89
avr_error
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
uart_create
VDevice * uart_create(int addr, char *name, int rel_addr, void *data)
Allocate a new uart structure.
Definition: uart.c:335
avr_core_clk_cb_add
void avr_core_clk_cb_add(AvrCore *core, CallBack *cb)
Add a new clock callback to list.
class_overload_destroy
void class_overload_destroy(AvrClass *klass, AvrClassFP_Destroy destroy)
Overload the default destroy method.
Definition: avrclass.c:92

Automatically generated by Doxygen 1.8.12 on Tue Apr 18 2017.