uart.c

Go to the documentation of this file.
00001 /*
00002  * $Id: uart.c,v 1.3 2004/03/13 19:55:34 troth Exp $
00003  *
00004  ****************************************************************************
00005  *
00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
00007  * Copyright (C) 2003, 2004  Keith Gudger
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  ****************************************************************************
00024  */
00025 
00026 /**
00027  * \file uart.c
00028  * \brief Module to simulate the AVR's uart module.
00029  */
00030 
00031 #include <config.h>
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 
00037 #include "avrerror.h"
00038 #include "avrmalloc.h"
00039 #include "avrclass.h"
00040 #include "utils.h"
00041 #include "callback.h"
00042 #include "op_names.h"
00043 
00044 #include "storage.h"
00045 #include "flash.h"
00046 
00047 #include "vdevs.h"
00048 #include "memory.h"
00049 #include "stack.h"
00050 #include "register.h"
00051 #include "sram.h"
00052 #include "eeprom.h"
00053 #include "timers.h"
00054 #include "ports.h"
00055 #include "uart.h"
00056 
00057 #include "avrcore.h"
00058 
00059 #include "intvects.h"
00060 
00061 /****************************************************************************\
00062  *
00063  * uart Interrupts 
00064  *
00065 \****************************************************************************/
00066 
00067 static void uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00068                             void *data);
00069 static uint8_t uart_intr_read (VDevice *dev, int addr);
00070 static void uart_intr_write (VDevice *dev, int addr, uint8_t val);
00071 static void uart_intr_reset (VDevice *dev);
00072 static int uart_intr_cb (uint64_t time, AvrClass *data);
00073 
00074 int UART_Int_Table[] = {
00075     irq_vect_table_index (UART_RX), /* uart Rx complete */
00076     irq_vect_table_index (UART_UDRE), /* uart data register empty */
00077     irq_vect_table_index (UART_TX) /* uart Tx complete */
00078 };
00079 
00080 int UART0_Int_Table[] = {
00081     irq_vect_table_index (USART0_RX), /* uart Rx complete */
00082     irq_vect_table_index (USART0_UDRE), /* uart data register empty */
00083     irq_vect_table_index (USART0_TX) /* uart Tx complete */
00084 };
00085 
00086 int UART1_Int_Table[] = {
00087     irq_vect_table_index (USART1_RX), /* uart Rx complete */
00088     irq_vect_table_index (USART1_UDRE), /* uart data register empty */
00089     irq_vect_table_index (USART1_TX) /* uart Tx complete */
00090 };
00091 
00092 /** \brief Allocate a new uart interrupt */
00093 
00094 VDevice *
00095 uart_int_create (int addr, char *name, int rel_addr, void *data)
00096 {
00097     if (data)
00098         return (VDevice *)uart_intr_new (addr, name, data);
00099     else
00100         avr_error ("Attempted UART create with NULL data pointer");
00101     return 0;
00102 }
00103 
00104 UARTIntr_T *
00105 uart_intr_new (int addr, char *name, void *data)
00106 {
00107     uint8_t *uart_num = (uint8_t *) data;
00108     UARTIntr_T *uart;
00109 
00110     uart = avr_new (UARTIntr_T, 1);
00111     uart_intr_construct (uart, addr, name);
00112     class_overload_destroy ((AvrClass *)uart, uart_intr_destroy);
00113 
00114     if (*uart_num == USART0)
00115         uart->Int_Table = &UART0_Int_Table[0];
00116     else if (*uart_num == USART1)
00117         uart->Int_Table = &UART1_Int_Table[0];
00118     else
00119         uart->Int_Table = &UART_Int_Table[0];
00120 
00121     uart_iadd_addr ((VDevice *)uart, addr, name, 0, NULL);
00122     return uart;
00123 }
00124 
00125 /** \brief Constructor for uart interrupt object. */
00126 
00127 void
00128 uart_intr_construct (UARTIntr_T *uart, int addr, char *name)
00129 {
00130     if (uart == NULL)
00131         avr_error ("passed null ptr");
00132 
00133     vdev_construct ((VDevice *)uart, uart_intr_read, uart_intr_write,
00134                     uart_intr_reset, uart_iadd_addr);
00135 
00136     uart_intr_reset ((VDevice *)uart);
00137 }
00138 
00139 static void
00140 uart_iadd_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
00141 {
00142     UARTIntr_T *uart = (UARTIntr_T *)vdev;
00143 
00144     if (strncmp ("UBRRH", name, 5) == 0)
00145     {
00146         uart->ubrrh_addr = addr;
00147     }
00148 
00149     else if ((strncmp ("UBRR", name, 4) == 0)
00150              || (strncmp ("UBRR0", name, 5) == 0)
00151              || (strncmp ("UBRR1", name, 5) == 0))
00152     {
00153         uart->ubrrl_addr = addr;
00154     }
00155 
00156     else if ((strncmp ("USR", name, 3) == 0)
00157              || (strncmp ("UCSR0A", name, 6) == 0)
00158              || (strncmp ("UCSR1A", name, 6) == 0))
00159     {
00160         uart->usr_addr = addr;
00161     }
00162 
00163     else if ((strncmp ("UCR", name, 3) == 0)
00164              || (strncmp ("UCSR0B", name, 6) == 0)
00165              || (strncmp ("UCSR1B", name, 6) == 0))
00166     {
00167         uart->ucr_addr = addr;
00168     }
00169 
00170     else
00171     {
00172         avr_error ("invalid UART register name: '%s' @ 0x%04x", name, addr);
00173     }
00174 }
00175 
00176 /** \brief Destructor for uart interrupt object. */
00177 
00178 void
00179 uart_intr_destroy (void *uart)
00180 {
00181     if (uart == NULL)
00182         return;
00183 
00184     vdev_destroy (uart);
00185 }
00186 
00187 static uint8_t
00188 uart_intr_read (VDevice *dev, int addr)
00189 {
00190     UARTIntr_T *uart = (UARTIntr_T *)dev;
00191 
00192     if (addr == uart->ubrrl_addr)
00193     {
00194         return (uart->ubrr & 0xff);
00195     }
00196 
00197     else if (addr == uart->ubrrh_addr)
00198     {
00199         return (uart->ubrr >> 8);
00200     }
00201 
00202     else if (addr == uart->ucr_addr)
00203     {
00204         return (uart->ucr);
00205     }
00206 
00207     else if (addr == uart->usr_addr)
00208     {
00209         return (uart->usr);
00210     }
00211 
00212     else
00213     {
00214         avr_error ("Bad address: 0x%04x", addr);
00215     }
00216 
00217     return 0;                   /* will never get here */
00218 }
00219 
00220 static void
00221 uart_intr_write (VDevice *dev, int addr, uint8_t val)
00222 {
00223     UARTIntr_T *uart = (UARTIntr_T *)dev;
00224     CallBack *cb;
00225 
00226     if (addr == uart->ubrrl_addr)
00227     {
00228         uart->ubrr = val + (uart->ubrr_temp << 8);
00229     }
00230 
00231     else if (addr == uart->ubrrh_addr)
00232     {
00233         uart->ubrr_temp = val;
00234     }
00235 
00236     else if (addr == uart->usr)
00237     {
00238         if (val & mask_TXC)
00239             uart->usr &= ~mask_TXC;
00240     }
00241 
00242     else if (addr == uart->ucr_addr)
00243     {
00244         (uart->ucr = val);      /* look for interrupt enables */
00245 
00246         if (((uart->ucr & mask_TXEN) && (uart->ucr & mask_TXCIE))
00247             || ((uart->ucr & mask_RXEN) && (uart->ucr & mask_RXCIE))
00248             || (uart->ucr & mask_UDRIE))
00249         {
00250             if (uart->intr_cb == NULL)
00251             {
00252                 /* we need to install the intr_cb function */
00253                 cb = callback_new (uart_intr_cb, (AvrClass *)uart);
00254                 uart->intr_cb = cb;
00255                 avr_core_async_cb_add ((AvrCore *)vdev_get_core (dev), cb);
00256             }
00257         }
00258         else
00259         {
00260             uart->intr_cb = NULL;
00261             /* no interrupt are enabled, remove the callback */
00262         }
00263     }
00264 
00265     else
00266     {
00267         avr_error ("Bad address: 0x%04x", addr);
00268     }
00269 }
00270 
00271 static void
00272 uart_intr_reset (VDevice *dev)
00273 {
00274     UARTIntr_T *uart = (UARTIntr_T *)dev;
00275 
00276     uart->intr_cb = NULL;
00277 
00278     uart->ubrr = 0;
00279     uart->usr = 0;
00280     uart->ucr = 0;
00281     uart->usr_shadow = 0;
00282 }
00283 
00284 static int
00285 uart_intr_cb (uint64_t time, AvrClass *data)
00286 {
00287     UARTIntr_T *uart = (UARTIntr_T *)data;
00288 
00289     if (uart->intr_cb == NULL)
00290         return CB_RET_REMOVE;
00291 
00292     if ((uart->ucr & mask_RXCIE) && (uart->usr & mask_RXC))
00293         /* an enabled interrupt occured */
00294     {
00295         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
00296         avr_core_irq_raise (core, (uart->Int_Table[URX]));
00297     }
00298 
00299     if ((uart->ucr & mask_TXCIE) && (uart->usr & mask_TXC))
00300         /* an enabled interrupt occured */
00301     {
00302         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
00303         avr_core_irq_raise (core, (uart->Int_Table[UTX]));
00304         uart->usr &= ~mask_TXC;
00305     }
00306 
00307     if ((uart->ucr & mask_UDRIE) && (uart->usr & mask_UDRE)
00308         && (uart->usr_shadow & mask_UDRE))
00309         /* an enabled interrupt occured */
00310     {
00311         AvrCore *core = (AvrCore *)vdev_get_core ((VDevice *)uart);
00312         avr_core_irq_raise (core, (uart->Int_Table[UUDRE]));
00313         uart->usr_shadow &= ~mask_UDRE; /* only issue one interrupt / udre */
00314     }
00315 
00316     return CB_RET_RETAIN;
00317 }
00318 
00319 /****************************************************************************\
00320  *
00321  * uart  
00322  *
00323 \****************************************************************************/
00324 
00325 static void uart_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00326                            void *data);
00327 static uint8_t uart_read (VDevice *dev, int addr);
00328 static void uart_write (VDevice *dev, int addr, uint8_t val);
00329 static void uart_reset (VDevice *dev);
00330 static int uart_clk_incr_cb (uint64_t ck, AvrClass *data);
00331 
00332 /** \brief Allocate a new uart structure. */
00333 
00334 VDevice *
00335 uart_create (int addr, char *name, int rel_addr, void *data)
00336 {
00337     return (VDevice *)uart_new (addr, name, rel_addr);
00338 }
00339 
00340 UART_T *
00341 uart_new (int addr, char *name, int rel_addr)
00342 {
00343     UART_T *uart;
00344 
00345     uart = avr_new (UART_T, 1);
00346     uart_construct (uart, addr, name, rel_addr);
00347 
00348     class_overload_destroy ((AvrClass *)uart, uart_destroy);
00349 
00350     return uart;
00351 }
00352 
00353 /** \brief Constructor for uart object. */
00354 
00355 void
00356 uart_construct (UART_T *uart, int addr, char *name, int rel_addr)
00357 {
00358     if (uart == NULL)
00359         avr_error ("passed null ptr");
00360 
00361     vdev_construct ((VDevice *)uart, uart_read, uart_write, uart_reset,
00362                     uart_add_addr);
00363 
00364     uart_add_addr ((VDevice *)uart, addr, name, 0, NULL);
00365     if (rel_addr)
00366         uart->related_addr = rel_addr;
00367     uart_reset ((VDevice *)uart);
00368 }
00369 
00370 static void
00371 uart_add_addr (VDevice *vdev, int addr, char *name, int ref_addr, void *data)
00372 {
00373     UART_T *uart = (UART_T *)vdev;
00374 
00375     if (strncmp ("UDR", name, 3) == 0)
00376     {
00377         uart->udr_addr = addr;
00378     }
00379 
00380     else
00381     {
00382         avr_error ("invalid SPI register name: '%s' @ 0x%04x", name, addr);
00383     }
00384 }
00385 
00386 /** \brief Destructor for uart object. */
00387 
00388 void
00389 uart_destroy (void *uart)
00390 {
00391     if (uart == NULL)
00392         return;
00393 
00394     vdev_destroy (uart);
00395 }
00396 
00397 static uint8_t
00398 uart_read (VDevice *dev, int addr)
00399 {
00400     UART_T *uart = (UART_T *)dev;
00401     UARTIntr_T *uart_t;
00402     uint16_t udr_temp;
00403 
00404     uart_t =
00405         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
00406                                                  vdev_get_core ((VDevice *)
00407                                                                 uart),
00408                                                  uart->related_addr);
00409 
00410     if (addr == uart->udr_addr)
00411     {
00412         uart_t->usr &= ~mask_RXC; /* clear RXC bit in USR */
00413         if (uart->clk_cb)       /* call back already installed */
00414         {
00415             udr_temp = uart_port_rd (addr);
00416             uart->udr_rx = (uint8_t) udr_temp; /* lower 8 bits */
00417             if ((uart_t->ucr & mask_CHR9) && /* 9 bits rec'd */
00418                 (udr_temp & (1 << 8))) /* hi bit set */
00419                 uart_t->ucr |= mask_RXB8;
00420             else
00421                 uart_t->ucr &= ~mask_RXB8;
00422         }
00423         return uart->udr_rx;
00424     }
00425 
00426     else
00427     {
00428         avr_error ("Bad address: 0x%04x", addr);
00429     }
00430 
00431     return 0;                   /* will never get here */
00432 }
00433 
00434 static void
00435 uart_write (VDevice *dev, int addr, uint8_t val)
00436 {
00437     UART_T *uart = (UART_T *)dev;
00438     UARTIntr_T *uart_t;
00439     CallBack *cb;
00440 
00441     uart_t =
00442         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
00443                                                  vdev_get_core ((VDevice *)
00444                                                                 uart),
00445                                                  uart->related_addr);
00446 
00447     if (addr == uart->udr_addr)
00448     {
00449         if (uart_t->usr & mask_UDRE)
00450         {
00451             uart_t->usr &= ~mask_UDRE;
00452             uart_t->usr_shadow &= ~mask_UDRE;
00453         }
00454         else
00455         {
00456             uart_t->usr |= mask_UDRE;
00457             uart_t->usr_shadow |= mask_UDRE;
00458         }
00459         uart->udr_tx = val;
00460 
00461         /*
00462          * When the user writes to UDR, a callback is installed for 
00463          * clock generated increments. 
00464          */
00465 
00466         uart->divisor = (uart_t->ubrr + 1) * 16;
00467 
00468         /* install the clock incrementor callback (with flair!) */
00469 
00470         if (uart->clk_cb == NULL)
00471         {
00472             cb = callback_new (uart_clk_incr_cb, (AvrClass *)uart);
00473             uart->clk_cb = cb;
00474             avr_core_clk_cb_add ((AvrCore *)vdev_get_core ((VDevice *)uart),
00475                                  cb);
00476         }
00477 
00478         /* set up timer for 8 or 9 clocks based on ucr 
00479            (includes start and stop bits) */
00480 
00481         uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
00482     }
00483 
00484     else
00485     {
00486         avr_error ("Bad address: 0x%04x", addr);
00487     }
00488 }
00489 
00490 static void
00491 uart_reset (VDevice *dev)
00492 {
00493     UART_T *uart = (UART_T *)dev;
00494 
00495     uart->clk_cb = NULL;
00496 
00497     uart->udr_rx = 0;
00498     uart->udr_tx = 0;
00499     uart->tcnt = 0;
00500     uart->divisor = 0;
00501 }
00502 
00503 static int
00504 uart_clk_incr_cb (uint64_t ck, AvrClass *data)
00505 {
00506     UART_T *uart = (UART_T *)data;
00507     UARTIntr_T *uart_t;
00508     uint8_t last = uart->tcnt;
00509 
00510     uart_t =
00511         (UARTIntr_T *)avr_core_get_vdev_by_addr ((AvrCore *)
00512                                                  vdev_get_core ((VDevice *)
00513                                                                 uart),
00514                                                  uart->related_addr);
00515 
00516     if (uart->clk_cb == NULL)
00517         return CB_RET_REMOVE;
00518 
00519     if (uart->divisor <= 0)
00520         avr_error ("Bad divisor value: %d", uart->divisor);
00521 
00522     /* decrement clock if ck is a mutliple of divisor */
00523 
00524     uart->tcnt -= ((ck % uart->divisor) == 0);
00525 
00526     if (uart->tcnt != last)     /* we've changed the counter */
00527     {
00528         if (uart->tcnt == 0)
00529         {
00530             if (uart_t->usr & mask_UDRE) /* data register empty */
00531             {
00532                 uart_t->usr |= mask_TXC;
00533                 uart->clk_cb = NULL;
00534                 return CB_RET_REMOVE;
00535             }
00536             else                /* there's a byte waiting to go */
00537             {
00538                 uart_t->usr |= mask_UDRE;
00539                 uart_t->usr_shadow |= mask_UDRE; /* also write shadow */
00540 
00541                 /* set up timer for 8 or 9 clocks based on ucr,
00542                    (includes start and stop bits) */
00543 
00544                 uart->tcnt = (uart_t->ucr & mask_CHR9) ? 11 : 10;
00545             }
00546         }
00547     }
00548 
00549     return CB_RET_RETAIN;
00550 }
00551 
00552 uint16_t
00553 uart_port_rd (int addr)
00554 {
00555     int data;
00556     char line[80];
00557 
00558     while (1)
00559     {
00560         fprintf (stderr,
00561                  "\nEnter 9 bits of hex data to read into the uart at "
00562                  "address 0x%04x: ", addr);
00563 
00564         /* try to read in a line of input */
00565         if (fgets (line, sizeof (line), stdin) == NULL)
00566             continue;
00567 
00568         /* try to parse the line for a byte of data */
00569         if (sscanf (line, "%x\n", &data) != 1)
00570             continue;
00571 
00572         break;
00573     }
00574 
00575     return (uint16_t) (data & 0x1ff);
00576 }
00577 
00578 void
00579 uart_port_wr (uint8_t val)
00580 {
00581     fprintf (stderr, "wrote 0x%02x to uart\n", val);
00582 }

Automatically generated by Doxygen 1.5.2 on 14 Feb 2008.