Main Page

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
200 port_ext_disable (Port *p)
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
210 port_ext_enable (Port *p)
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
vdev_destroy
void vdev_destroy(void *dev)
Destructor for a VDevice.
Definition: device.c:105
port_ext_disable
void port_ext_disable(Port *p)
Disable external port functionality.
Definition: ports.c:200
avr_warning
#define avr_warning(fmt, args...)
Print a warning message to stderr.
Definition: avrerror.c:46
vdev_construct
void vdev_construct(VDevice *dev, VDevFP_Read rd, VDevFP_Write wr, VDevFP_Reset reset, VDevFP_AddAddr add_addr)
Constructor for a VDevice.
Definition: device.c:89
port_add_ext_rd_wr
void port_add_ext_rd_wr(Port *p, PortFP_ExtRd ext_rd, PortFP_ExtWr ext_wr)
Attaches read and write functions to a particular port.
Definition: ports.c:231
avr_error
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
port_create
VDevice * port_create(int addr, char *name, int rel_addr, void *data)
Create a new Port instance.
Definition: ports.c:100
class_overload_destroy
void class_overload_destroy(AvrClass *klass, AvrClassFP_Destroy destroy)
Overload the default destroy method.
Definition: avrclass.c:92
port_ext_enable
void port_ext_enable(Port *p)
Enable external port functionality.
Definition: ports.c:210
avr_new0
#define avr_new0(type, count)
Macro for allocating memory and initializing it to zero.
Definition: avrmalloc.c:67

Automatically generated by Doxygen 1.8.12 on Sun Apr 2 2017.