ports.c
Go to the documentation of this file.
1 /*
2  * $Id: ports.c,v 1.17 2004/01/30 07:09:56 troth Exp $
3  *
4  ****************************************************************************
5  *
6  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7  * Copyright (C) 2001, 2002, 2003, 2004 Theodore A. Roth
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 ports.c
28  * \brief Module for accessing simulated I/O ports.
29  *
30  * Defines an abstract Port class as well as subclasses for each individual
31  * port.
32  *
33  * \todo Remove the pins argument and the mask field. That's handled at a
34  * higher level so is obsolete here now.
35  */
36 
37 #include <config.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "avrerror.h"
44 #include "avrmalloc.h"
45 #include "avrclass.h"
46 #include "utils.h"
47 #include "callback.h"
48 #include "op_names.h"
49 
50 #include "storage.h"
51 #include "flash.h"
52 
53 #include "vdevs.h"
54 #include "memory.h"
55 #include "stack.h"
56 #include "register.h"
57 #include "sram.h"
58 #include "eeprom.h"
59 #include "timers.h"
60 #include "ports.h"
61 
62 #include "avrcore.h"
63 
64 /****************************************************************************\
65  *
66  * Local static prototypes.
67  *
68 \****************************************************************************/
69 
70 static Port *port_new (int addr, char *name);
71 static void port_construct (Port *p, int addr, char *name);
72 static void port_destroy (void *p);
73 
74 static uint8_t port_reg_read (VDevice *dev, int addr);
75 static void port_reg_write (VDevice *dev, int addr, uint8_t val);
76 static void port_reset (VDevice *dev);
77 
78 static uint8_t port_read_pin (Port *p, int addr);
79 
80 static void port_write_port (Port *p, int addr, uint8_t val);
81 
82 static void port_write_ddr (Port *p, int addr, uint8_t val);
83 
84 static void port_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
85  void *data);
86 
87 /****************************************************************************\
88  *
89  * Port(VDevice) : I/O Port registers
90  *
91 \****************************************************************************/
92 
93 /**
94  * \brief Create a new Port instance.
95  *
96  * This should only be used in DevSuppDefn initializers.
97  */
98 
99 VDevice *
100 port_create (int addr, char *name, int rel_addr, void *data)
101 {
102  return (VDevice *)port_new (addr, name);
103 }
104 
105 /**
106  * \brief Allocates a new Port object.
107  */
108 
109 static Port *
110 port_new (int addr, char *name)
111 {
112  Port *p;
113 
114  p = avr_new0 (Port, 1);
115  port_construct (p, addr, name);
116  class_overload_destroy ((AvrClass *)p, port_destroy);
117 
118  return p;
119 }
120 
121 /**
122  * \brief Constructor for the Port object.
123  */
124 
125 static void
126 port_construct (Port *p, int addr, char *name)
127 {
128  if (p == NULL)
129  avr_error ("passed null ptr");
130 
131  vdev_construct ((VDevice *)p, port_reg_read, port_reg_write, port_reset,
132  port_add_addr);
133 
134  port_add_addr ((VDevice *)p, addr, name, 0, NULL);
135 
136  p->ext_rd = NULL;
137  p->ext_wr = NULL;
138 
139  port_reset ((VDevice *)p);
140 }
141 
142 static void
143 port_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
144 {
145  Port *p = (Port *)vdev;
146 
147  if (strncmp ("PORT", name, 4) == 0)
148  {
149  p->port_addr = addr;
150  }
151 
152  else if (strncmp ("DDR", name, 3) == 0)
153  {
154  p->ddr_addr = addr;
155  }
156 
157  else if (strncmp ("PIN", name, 3) == 0)
158  {
159  p->pin_addr = addr;
160  }
161 
162  else
163  {
164  avr_error ("invalid port register name: '%s' @ 0x%04x", name, addr);
165  }
166 }
167 
168 static void
169 port_reset (VDevice *dev)
170 {
171  Port *p = (Port *)dev;
172 
173  p->port = 0;
174  p->ddr = 0;
175  p->pin = 0;
176 
177  p->ext_enable = 1;
178 }
179 
180 /**
181  * \brief Destructor for the Port object
182  *
183  * This is a virtual method for higher level port implementations and as such
184  * should not be used directly.
185  */
186 void
187 port_destroy (void *p)
188 {
189  if (p == NULL)
190  return;
191 
192  vdev_destroy (p);
193 }
194 
195 /** \brief Disable external port functionality.
196  *
197  * This is only used when dumping memory to core file. See mem_io_fetch().
198  */
199 void
201 {
202  p->ext_enable = 0;
203 }
204 
205 /** \brief Enable external port functionality.
206  *
207  * This is only used when dumping memory to core file. See mem_io_fetch().
208  */
209 void
211 {
212  p->ext_enable = 1;
213 }
214 
215 /**
216  * \brief Attaches read and write functions to a particular port
217  *
218  * I think I may have this backwards. Having the virtual hardware supply
219  * functions for the core to call on every io read/write, might cause missed
220  * events (like edge triggered). I'm really not too sure how to handle this.
221  *
222  * In the future, it might be better to have the core supply a function for
223  * the virtual hardware to call when data is written to the device. The device
224  * supplied function could then check if an interrupt should be generated or
225  * just simply write to the port data register.
226  *
227  * For now, leave it as is since it's easier to test if you can block when the
228  * device is reading from the virtual hardware.
229  */
230 void
231 port_add_ext_rd_wr (Port *p, PortFP_ExtRd ext_rd, PortFP_ExtWr ext_wr)
232 {
233  p->ext_rd = ext_rd;
234  p->ext_wr = ext_wr;
235 }
236 
237 static uint8_t
238 port_read_pin (Port *p, int addr)
239 {
240  uint8_t data;
241 
242  /* get the data from the external virtual hardware if connected */
243  if (p->ext_rd && p->ext_enable)
244  data = p->ext_rd (addr);
245  else
246  data = 0;
247 
248  /*
249  * For a pin n to be enabled as input, DDRn == 0,
250  * otherwise it will always read 0.
251  */
252  data &= ~(p->ddr);
253 
254  /*
255  * Pass data to alternate read so as to check alternate functions of
256  * pins for that port.
257  */
258 /* if (p->alt_rd) */
259 /* data = p->alt_rd(p, addr, data); */
260 
261  return data;
262 }
263 
264 static void
265 port_write_port (Port *p, int addr, uint8_t val)
266 {
267  /* update port register */
268  p->port = val;
269 
270  /*
271  * Since changing p->port might change what the virtual hardware
272  * sees, we need to call ext_wr() to pass change along.
273  */
274  if (p->ext_wr && p->ext_enable)
275  p->ext_wr (addr, (p->port & p->ddr));
276 }
277 
278 static void
279 port_write_ddr (Port *p, int addr, uint8_t val)
280 {
281  /* update ddr register */
282  p->ddr = val;
283 
284 #if 0
285  /*
286  * Since changing p->ddr might change what the virtual hardware
287  * sees, we need to call ext_wr() to pass change allong.
288  */
289  if (p->ext_wr && p->ext_enable)
290  p->ext_wr (addr, (p->port & p->ddr));
291 #endif
292 }
293 
294 static uint8_t
295 port_reg_read (VDevice *dev, int addr)
296 {
297  Port *p = (Port *)dev;
298 
299  if (addr == p->ddr_addr)
300  return p->ddr;
301 
302  else if (addr == p->pin_addr)
303  return port_read_pin (p, addr);
304 
305  else if (addr == p->port_addr)
306  return p->port;
307 
308  else
309  avr_error ("Invalid Port Address: 0x%02x", addr);
310 
311  return 0;
312 }
313 
314 static void
315 port_reg_write (VDevice *dev, int addr, uint8_t val)
316 {
317  Port *p = (Port *)dev;
318 
319  if (addr == p->pin_addr)
320  {
321  avr_warning ("Attempt to write to readonly PINx register\n");
322  }
323 
324  else if (addr == p->ddr_addr)
325  {
326  port_write_ddr ((Port *)p, addr, val);
327  }
328 
329  else if (addr == p->port_addr)
330  {
331  port_write_port ((Port *)p, addr, val);
332  }
333 
334  else
335  {
336  avr_error ("Invalid Port Address: 0x%02x", addr);
337  }
338 }
339 

Automatically generated by Doxygen 1.8.2 on Tue Aug 13 2013.