Main Page

- Main Page
- Related Pages
- Files

- File List
- Globals

# ports.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: ports.c,v 1.17 2004/01/30 07:09:56 troth Exp $
    00003  *
    00004  ****************************************************************************
    00005  *
    00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
    00007  * Copyright (C) 2001, 2002, 2003, 2004  Theodore A. Roth
    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 ports.c
    00028  * \brief Module for accessing simulated I/O ports.
    00029  *
    00030  * Defines an abstract Port class as well as subclasses for each individual
    00031  * port.
    00032  *
    00033  * \todo Remove the pins argument and the mask field. That's handled at a
    00034  * higher level so is obsolete here now.
    00035  */
    00036
    00037 #include <config.h>
    00038
    00039 #include <stdio.h>
    00040 #include <stdlib.h>
    00041 #include <string.h>
    00042
    00043 #include "avrerror.h"
    00044 #include "avrmalloc.h"
    00045 #include "avrclass.h"
    00046 #include "utils.h"
    00047 #include "callback.h"
    00048 #include "op_names.h"
    00049
    00050 #include "storage.h"
    00051 #include "flash.h"
    00052
    00053 #include "vdevs.h"
    00054 #include "memory.h"
    00055 #include "stack.h"
    00056 #include "register.h"
    00057 #include "sram.h"
    00058 #include "eeprom.h"
    00059 #include "timers.h"
    00060 #include "ports.h"
    00061
    00062 #include "avrcore.h"
    00063
    00064 /****************************************************************************\
    00065  *
    00066  * Local static prototypes.
    00067  *
    00068 \****************************************************************************/
    00069
    00070 static Port *port_new (int addr, char *name);
    00071 static void port_construct (Port *p, int addr, char *name);
    00072 static void port_destroy (void *p);
    00073
    00074 static uint8_t port_reg_read (VDevice *dev, int addr);
    00075 static void port_reg_write (VDevice *dev, int addr, uint8_t val);
    00076 static void port_reset (VDevice *dev);
    00077
    00078 static uint8_t port_read_pin (Port *p, int addr);
    00079
    00080 static void port_write_port (Port *p, int addr, uint8_t val);
    00081
    00082 static void port_write_ddr (Port *p, int addr, uint8_t val);
    00083
    00084 static void port_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
    00085                            void *data);
    00086
    00087 /****************************************************************************\
    00088  *
    00089  * Port(VDevice) : I/O Port registers
    00090  *
    00091 \****************************************************************************/
    00092
    00093 /**
    00094  * \brief Create a new Port instance.
    00095  *
    00096  * This should only be used in DevSuppDefn initializers.
    00097  */
    00098
    00099 VDevice *
    00100 port_create (int addr, char *name, int rel_addr, void *data)
    00101 {
    00102     return (VDevice *)port_new (addr, name);
    00103 }
    00104
    00105 /**
    00106  * \brief Allocates a new Port object.
    00107  */
    00108
    00109 static Port *
    00110 port_new (int addr, char *name)
    00111 {
    00112     Port *p;
    00113
    00114     p = avr_new0 (Port, 1);
    00115     port_construct (p, addr, name);
    00116     class_overload_destroy ((AvrClass *)p, port_destroy);
    00117
    00118     return p;
    00119 }
    00120
    00121 /**
    00122  * \brief Constructor for the Port object.
    00123  */
    00124
    00125 static void
    00126 port_construct (Port *p, int addr, char *name)
    00127 {
    00128     if (p == NULL)
    00129         avr_error ("passed null ptr");
    00130
    00131     vdev_construct ((VDevice *)p, port_reg_read, port_reg_write, port_reset,
    00132                     port_add_addr);
    00133
    00134     port_add_addr ((VDevice *)p, addr, name, 0, NULL);
    00135
    00136     p->ext_rd = NULL;
    00137     p->ext_wr = NULL;
    00138
    00139     port_reset ((VDevice *)p);
    00140 }
    00141
    00142 static void
    00143 port_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
    00144 {
    00145     Port *p = (Port *)vdev;
    00146
    00147     if (strncmp ("PORT", name, 4) == 0)
    00148     {
    00149         p->port_addr = addr;
    00150     }
    00151
    00152     else if (strncmp ("DDR", name, 3) == 0)
    00153     {
    00154         p->ddr_addr = addr;
    00155     }
    00156
    00157     else if (strncmp ("PIN", name, 3) == 0)
    00158     {
    00159         p->pin_addr = addr;
    00160     }
    00161
    00162     else
    00163     {
    00164         avr_error ("invalid port register name: '%s' @ 0x%04x", name, addr);
    00165     }
    00166 }
    00167
    00168 static void
    00169 port_reset (VDevice *dev)
    00170 {
    00171     Port *p = (Port *)dev;
    00172
    00173     p->port = 0;
    00174     p->ddr = 0;
    00175     p->pin = 0;
    00176
    00177     p->ext_enable = 1;
    00178 }
    00179
    00180 /**
    00181  * \brief Destructor for the Port object
    00182  *
    00183  * This is a virtual method for higher level port implementations and as such
    00184  * should not be used directly.
    00185  */
    00186 void
    00187 port_destroy (void *p)
    00188 {
    00189     if (p == NULL)
    00190         return;
    00191
    00192     vdev_destroy (p);
    00193 }
    00194
    00195 /** \brief Disable external port functionality.
    00196  *
    00197  * This is only used when dumping memory to core file. See mem_io_fetch().
    00198  */
    00199 void
    00200 port_ext_disable (Port *p)
    00201 {
    00202     p->ext_enable = 0;
    00203 }
    00204
    00205 /** \brief Enable external port functionality.
    00206  *
    00207  * This is only used when dumping memory to core file. See mem_io_fetch().
    00208  */
    00209 void
    00210 port_ext_enable (Port *p)
    00211 {
    00212     p->ext_enable = 1;
    00213 }
    00214
    00215 /**
    00216  * \brief Attaches read and write functions to a particular port
    00217  *
    00218  * I think I may have this backwards. Having the virtual hardware supply
    00219  * functions for the core to call on every io read/write, might cause missed
    00220  * events (like edge triggered). I'm really not too sure how to handle this.
    00221  *
    00222  * In the future, it might be better to have the core supply a function for
    00223  * the virtual hardware to call when data is written to the device. The device
    00224  * supplied function could then check if an interrupt should be generated or
    00225  * just simply write to the port data register.
    00226  *
    00227  * For now, leave it as is since it's easier to test if you can block when the
    00228  * device is reading from the virtual hardware.
    00229  */
    00230 void
    00231 port_add_ext_rd_wr (Port *p, PortFP_ExtRd ext_rd, PortFP_ExtWr ext_wr)
    00232 {
    00233     p->ext_rd = ext_rd;
    00234     p->ext_wr = ext_wr;
    00235 }
    00236
    00237 static uint8_t
    00238 port_read_pin (Port *p, int addr)
    00239 {
    00240     uint8_t data;
    00241
    00242     /* get the data from the external virtual hardware if connected */
    00243     if (p->ext_rd && p->ext_enable)
    00244         data = p->ext_rd (addr);
    00245     else
    00246         data = 0;
    00247
    00248     /*
    00249      * For a pin n to be enabled as input, DDRn == 0,
    00250      * otherwise it will always read 0.
    00251      */
    00252     data &= ~(p->ddr);
    00253
    00254     /*
    00255      * Pass data to alternate read so as to check alternate functions of
    00256      * pins for that port.
    00257      */
    00258 /*      if (p->alt_rd) */
    00259 /*          data = p->alt_rd(p, addr, data); */
    00260
    00261     return data;
    00262 }
    00263
    00264 static void
    00265 port_write_port (Port *p, int addr, uint8_t val)
    00266 {
    00267     /* update port register */
    00268     p->port = val;
    00269
    00270     /*
    00271      * Since changing p->port might change what the virtual hardware
    00272      * sees, we need to call ext_wr() to pass change along.
    00273      */
    00274     if (p->ext_wr && p->ext_enable)
    00275         p->ext_wr (addr, (p->port & p->ddr));
    00276 }
    00277
    00278 static void
    00279 port_write_ddr (Port *p, int addr, uint8_t val)
    00280 {
    00281     /* update ddr register */
    00282     p->ddr = val;
    00283
    00284 #if 0
    00285     /*
    00286      * Since changing p->ddr might change what the virtual hardware
    00287      * sees, we need to call ext_wr() to pass change allong.
    00288      */
    00289     if (p->ext_wr && p->ext_enable)
    00290         p->ext_wr (addr, (p->port & p->ddr));
    00291 #endif
    00292 }
    00293
    00294 static uint8_t
    00295 port_reg_read (VDevice *dev, int addr)
    00296 {
    00297     Port *p = (Port *)dev;
    00298
    00299     if (addr == p->ddr_addr)
    00300         return p->ddr;
    00301
    00302     else if (addr == p->pin_addr)
    00303         return port_read_pin (p, addr);
    00304
    00305     else if (addr == p->port_addr)
    00306         return p->port;
    00307
    00308     else
    00309         avr_error ("Invalid Port Address: 0x%02x", addr);
    00310
    00311     return 0;
    00312 }
    00313
    00314 static void
    00315 port_reg_write (VDevice *dev, int addr, uint8_t val)
    00316 {
    00317     Port *p = (Port *)dev;
    00318
    00319     if (addr == p->pin_addr)
    00320     {
    00321         avr_warning ("Attempt to write to readonly PINx register\n");
    00322     }
    00323
    00324     else if (addr == p->ddr_addr)
    00325     {
    00326         port_write_ddr ((Port *)p, addr, val);
    00327     }
    00328
    00329     else if (addr == p->port_addr)
    00330     {
    00331         port_write_port ((Port *)p, addr, val);
    00332     }
    00333
    00334     else
    00335     {
    00336         avr_error ("Invalid Port Address: 0x%02x", addr);
    00337     }
    00338 }
    00339

Automatically generated by Doxygen 1.7.2 on Wed Feb 22 2012.