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.5.2 on 14 Feb 2008.