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 }

Automatically generated by Doxygen 1.8.2 on Fri Mar 8 2013.