Main Page

stack.c
Go to the documentation of this file.
1 /*
2 * $Id: stack.c,v 1.15 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 /** \file stack.c
27 \brief Module for the definition of the stack.
28
29 Defines the classes stack, hw_stack, and mem_stack.
30
31 FIXME: Ted, I would really really really love to put in a description of
32 what is the difference between these three classes and how they're used,
33 but I don't understand it myself. */
34
35 #include <config.h>
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "avrerror.h"
42 #include "avrmalloc.h"
43 #include "avrclass.h"
44 #include "utils.h"
45 #include "callback.h"
46 #include "op_names.h"
47
48 #include "storage.h"
49 #include "flash.h"
50
51 #include "vdevs.h"
52 #include "memory.h"
53 #include "stack.h"
54 #include "register.h"
55 #include "sram.h"
56 #include "eeprom.h"
57 #include "timers.h"
58 #include "ports.h"
59
60 #include "avrcore.h"
61
62 #include "display.h"
63
64 static uint32_t hw_pop (Stack *stack, int bytes);
65 static void hw_push (Stack *stack, int bytes, uint32_t val);
66
67 static uint32_t mem_pop (Stack *stack, int bytes);
68 static void mem_push (Stack *stack, int bytes, uint32_t val);
69
70 /****************************************************************************\
71 *
72 * Stack(AvrClass) Definition.
73 *
74 \****************************************************************************/
75
76 /** \brief Allocates memory for a new Stack object
77
78 This is a virtual method for higher level stack implementations and as
79 such should not be used directly. */
80
81 Stack *
82 stack_new (StackFP_Pop pop, StackFP_Push push)
83 {
84 Stack *st;
85
86 st = avr_new (Stack, 1);
87 stack_construct (st, pop, push);
88 class_overload_destroy ((AvrClass *)st, stack_destroy);
89
90 return st;
91 }
92
93 /** \brief Constructor for the Stack class.
94
95 This is a virtual method for higher level stack implementations and as
96 such should not be used directly. */
97
98 void
99 stack_construct (Stack *stack, StackFP_Pop pop, StackFP_Push push)
100 {
101 if (stack == NULL)
102 avr_error ("passed null ptr");
103
104 class_construct ((AvrClass *)stack);
105
106 stack->pop = pop;
107 stack->push = push;
108 }
109
110 /** \brief Destructor for the Stack class.
111
112 This is a virtual method for higher level stack implementations and as
113 such should not be used directly. */
114
115 void
116 stack_destroy (void *stack)
117 {
118 if (stack == NULL)
119 return;
120
121 class_destroy (stack);
122 }
123
124 /** \brief Pops a byte or a word off the stack and returns it.
125 \param stack A pointer to the Stack object from which to pop
126 \param bytes Number of bytes to pop off the stack (1 to 4 bytes).
127
128 \return The 1 to 4 bytes value popped from the stack.
129
130 This method provides access to the derived class's pop() method. */
131
132 uint32_t
133 stack_pop (Stack *stack, int bytes)
134 {
135 return stack->pop (stack, bytes);
136 }
137
138 /** \brief Pushes a byte or a word of data onto the stack.
139 \param stack A pointer to the Stack object from which to pop.
140 \param bytes Size of the value being pushed onto the stack (1 to 4 bytes).
141 \param val The value to be pushed.
142
143 This method provides access to the derived class's push() method. */
144
145 void
146 stack_push (Stack *stack, int bytes, uint32_t val)
147 {
148 stack->push (stack, bytes, val);
149 }
150
151 /****************************************************************************\
152 *
153 * HWStack(Stack) Definition.
154 *
155 \****************************************************************************/
156
157 /** \brief Allocate a new HWStack object
158
159 This is the stack implementation used by devices which lack SRAM and only
160 have a fixed size hardware stack (e.i., the at90s1200) */
161
162 HWStack *
163 hwstack_new (int depth)
164 {
165 HWStack *st;
166
167 st = avr_new (HWStack, 1);
168 hwstack_construct (st, depth);
169 class_overload_destroy ((AvrClass *)st, hwstack_destroy);
170
171 return st;
172 }
173
174 /** \brief Constructor for HWStack object */
175
176 void
177 hwstack_construct (HWStack *stack, int depth)
178 {
179 if (stack == NULL)
180 avr_error ("passed null ptr");
181
182 stack_construct ((Stack *)stack, hw_pop, hw_push);
183
184 stack->depth = depth;
185 stack->stack = avr_new0 (uint32_t, depth);
186 }
187
188 /** \brief Destructor for HWStack object */
189
190 void
191 hwstack_destroy (void *stack)
192 {
193 if (stack == NULL)
194 return;
195
196 avr_free (((HWStack *)stack)->stack);
197 stack_destroy (stack);
198 }
199
200 /* The HWStack pop method. */
201
202 static uint32_t
203 hw_pop (Stack *stack, int bytes)
204 {
205 HWStack *hwst = (HWStack *)stack;
206 int i;
207 uint32_t val = hwst->stack[0];
208
209 for (i = 0; i < (hwst->depth - 1); i++)
210 {
211 hwst->stack[i] = hwst->stack[i + 1];
212 }
213
214 return val;
215 }
216
217 /* The HWStack push method. */
218
219 static void
220 hw_push (Stack *stack, int bytes, uint32_t val)
221 {
222 HWStack *hwst = (HWStack *)stack;
223 int i;
224
225 for (i = (hwst->depth - 1); i; i--)
226 {
227 hwst->stack[i - 1] = hwst->stack[i];
228 }
229
230 hwst->stack[0] = val;
231 }
232
233 /****************************************************************************\
234 *
235 * StackPointer(VDevice) Definition.
236 *
237 \****************************************************************************/
238
239 #ifndef DOXYGEN /* don't expose to doxygen */
240
241 typedef struct _StackPointer StackPointer;
242 struct _StackPointer
243 {
244 VDevice parent;
245
246 uint16_t SPL_addr; /* Since some devices don't have a SPH, we
247 only track SPL address and assume the SPH
248 address is SPL_addr + 1. */
249
250 uint8_t SPL; /* Low byte of stack pointer */
251 uint8_t SPH; /* High byte of stack pointer */
252 };
253
254 #endif
255
256 static StackPointer *sp_new (int addr, char *name);
257 static void sp_construct (StackPointer *sp, int addr, char *name);
258 static void sp_destroy (void *sp);
259 static uint8_t sp_read (VDevice *dev, int addr);
260 static void sp_write (VDevice *dev, int addr, uint8_t val);
261 static void sp_reset (VDevice *dev);
262 static uint16_t sp_get (VDevice *sp);
263 static void sp_set (VDevice *sp, uint16_t val);
264 static void sp_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
265 void *data);
266
267 /** \brief Create the Stack Pointer VDevice.
268
269 This should only be used in the DevSuppDefn io reg init structure. */
270
271 VDevice *
272 sp_create (int addr, char *name, int rel_addr, void *data)
273 {
274 return (VDevice *)sp_new (addr, name);
275 }
276
277 static StackPointer *
278 sp_new (int addr, char *name)
279 {
280 StackPointer *sp;
281
282 sp = avr_new (StackPointer, 1);
283 sp_construct (sp, addr, name);
284 class_overload_destroy ((AvrClass *)sp, sp_destroy);
285
286 return sp;
287 }
288
289 static void
290 sp_construct (StackPointer *sp, int addr, char *name)
291 {
292 if (sp == NULL)
293 avr_error ("passed null ptr");
294
295 vdev_construct ((VDevice *)sp, sp_read, sp_write, sp_reset, sp_add_addr);
296
297 sp_add_addr ((VDevice *)sp, addr, name, 0, NULL);
298
299 sp_reset ((VDevice *)sp);
300 }
301
302 static void
303 sp_destroy (void *sp)
304 {
305 if (sp == NULL)
306 return;
307
308 vdev_destroy (sp);
309 }
310
311 static uint8_t
312 sp_read (VDevice *dev, int addr)
313 {
314 StackPointer *sp = (StackPointer *)dev;
315
316 if (addr == sp->SPL_addr)
317 return sp->SPL;
318 else if (addr == (sp->SPL_addr + 1))
319 return sp->SPH;
320 else
321 avr_error ("Bad address: 0x%04x", addr);
322
323 return 0;
324 }
325
326 static void
327 sp_write (VDevice *dev, int addr, uint8_t val)
328 {
329 /* Don't need display_io_reg() here since it's called higher up in mem
330 chain. */
331
332 StackPointer *sp = (StackPointer *)dev;
333
334 if (addr == sp->SPL_addr)
335 sp->SPL = val;
336 else if (addr == (sp->SPL_addr + 1))
337 sp->SPH = val;
338 else
339 avr_error ("Bad address: 0x%04x", addr);
340 }
341
342 static void
343 sp_reset (VDevice *dev)
344 {
345 StackPointer *sp = (StackPointer *)dev;
346
347 display_io_reg (SPL_IO_REG, sp->SPL = 0);
348 display_io_reg (SPH_IO_REG, sp->SPH = 0);
349 }
350
351 static uint16_t
352 sp_get (VDevice *sp)
353 {
354 return (((StackPointer *)sp)->SPH << 8) + ((StackPointer *)sp)->SPL;
355 }
356
357 static void
358 sp_set (VDevice *sp, uint16_t val)
359 {
360 display_io_reg (SPL_IO_REG, ((StackPointer *)sp)->SPL = val & 0xff);
361 display_io_reg (SPH_IO_REG, ((StackPointer *)sp)->SPH = val >> 8);
362 }
363
364 static void
365 sp_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
366 {
367 StackPointer *sp = (StackPointer *)vdev;
368
369 if (strncmp ("SPL", name, 3) == 0)
370 sp->SPL_addr = addr;
371
372 else if (strncmp ("SPH", name, 3) == 0)
373 ;
374
375 else
376 avr_error ("Bad address: 0x%04x", addr);
377 }
378
379 /****************************************************************************\
380 *
381 * MemStack(Stack) Definition.
382 *
383 \****************************************************************************/
384
385 /** \brief Allocate a new MemStack object */
386
387 MemStack *
388 memstack_new (Memory *mem, int spl_addr)
389 {
390 MemStack *st;
391
392 st = avr_new (MemStack, 1);
393 memstack_construct (st, mem, spl_addr);
394 class_overload_destroy ((AvrClass *)st, memstack_destroy);
395
396 return st;
397 }
398
399 /** \brief Constructor for MemStack object */
400
401 void
402 memstack_construct (MemStack *stack, Memory *mem, int spl_addr)
403 {
404 if (stack == NULL)
405 avr_error ("passed null ptr");
406
407 stack_construct ((Stack *)stack, mem_pop, mem_push);
408
409 class_ref ((AvrClass *)mem);
410 stack->mem = mem;
411
412 stack->SP = mem_get_vdevice_by_addr (mem, spl_addr);
413 if (stack->SP == NULL)
414 {
415 avr_error ("attempt to attach non-extistant SPL register");
416 }
417 class_ref ((AvrClass *)stack->SP);
418 }
419
420 /** \brief Destructor for MemStack object */
421
422 void
423 memstack_destroy (void *stack)
424 {
425 MemStack *_stack = (MemStack *)stack;
426
427 if (stack == NULL)
428 return;
429
430 class_unref ((AvrClass *)_stack->SP);
431 class_unref ((AvrClass *)_stack->mem);
432
433 stack_destroy (stack);
434 }
435
436 /* The MemStack pop method */
437
438 static uint32_t
439 mem_pop (Stack *stack, int bytes)
440 {
441 MemStack *mst = (MemStack *)stack;
442 int i;
443 uint32_t val = 0;
444 uint16_t sp = sp_get (mst->SP);
445
446 if ((bytes < 0) || (bytes >= sizeof (uint32_t)))
447 avr_error ("bytes out of bounds: %d", bytes);
448
449 for (i = bytes - 1; i >= 0; i--)
450 {
451 sp++;
452 val |= (mem_read (mst->mem, sp) << (i * 8));
453 }
454
455 sp_set (mst->SP, sp);
456
457 return val;
458 }
459
460 /* The MemStack push method. */
461
462 static void
463 mem_push (Stack *stack, int bytes, uint32_t val)
464 {
465 MemStack *mst = (MemStack *)stack;
466 int i;
467 uint16_t sp = sp_get (mst->SP);
468
469 if ((bytes < 0) || (bytes >= sizeof (uint32_t)))
470 avr_error ("bytes out of bounds: %d", bytes);
471
472 for (i = 0; i < bytes; i++)
473 {
474 mem_write (mst->mem, sp, val & 0xff);
475 val >>= 8;
476 sp--;
477 }
478
479 sp_set (mst->SP, sp);
480 }
avr_new
#define avr_new(type, count)
Macro for allocating memory.
Definition: avrmalloc.c:57
memstack_construct
void memstack_construct(MemStack *stack, Memory *mem, int spl_addr)
Constructor for MemStack object.
Definition: stack.c:402
hwstack_construct
void hwstack_construct(HWStack *stack, int depth)
Constructor for HWStack object.
Definition: stack.c:177
stack_new
Stack * stack_new(StackFP_Pop pop, StackFP_Push push)
Allocates memory for a new Stack object.
Definition: stack.c:82
stack_destroy
void stack_destroy(void *stack)
Destructor for the Stack class.
Definition: stack.c:116
mem_write
void mem_write(Memory *mem, int addr, uint8_t val)
Writes byte to memory and updates display for io registers.
Definition: memory.c:255
vdev_destroy
void vdev_destroy(void *dev)
Destructor for a VDevice.
Definition: device.c:105
class_ref
void class_ref(AvrClass *klass)
Increments the reference count for the klass object.
Definition: avrclass.c:106
hwstack_new
HWStack * hwstack_new(int depth)
Allocate a new HWStack object.
Definition: stack.c:163
mem_get_vdevice_by_addr
VDevice * mem_get_vdevice_by_addr(Memory *mem, int addr)
Find the VDevice associated with the given address.
Definition: memory.c:159
stack_pop
uint32_t stack_pop(Stack *stack, int bytes)
Pops a byte or a word off the stack and returns it.
Definition: stack.c:133
avr_free
void avr_free(void *ptr)
Free malloc&#39;d memory.
Definition: avrmalloc.c:187
class_destroy
void class_destroy(void *klass)
Releases resources allocated by class&#39;s <klass>_new() function.
Definition: avrclass.c:78
mem_read
uint8_t mem_read(Memory *mem, int addr)
Reads byte from memory and sanity-checks for valid address.
Definition: memory.c:220
stack_push
void stack_push(Stack *stack, int bytes, uint32_t val)
Pushes a byte or a word of data onto the stack.
Definition: stack.c:146
class_unref
void class_unref(AvrClass *klass)
Decrements the reference count for the klass object.
Definition: avrclass.c:120
sp_create
VDevice * sp_create(int addr, char *name, int rel_addr, void *data)
Create the Stack Pointer VDevice.
Definition: stack.c:272
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
avr_error
#define avr_error(fmt, args...)
Print an error message to stderr and terminate program.
Definition: avrerror.c:50
memstack_destroy
void memstack_destroy(void *stack)
Destructor for MemStack object.
Definition: stack.c:423
display_io_reg
void display_io_reg(int reg, uint8_t val)
Update an IO register in the display.
Definition: display.c:299
class_overload_destroy
void class_overload_destroy(AvrClass *klass, AvrClassFP_Destroy destroy)
Overload the default destroy method.
Definition: avrclass.c:92
hwstack_destroy
void hwstack_destroy(void *stack)
Destructor for HWStack object.
Definition: stack.c:191
memstack_new
MemStack * memstack_new(Memory *mem, int spl_addr)
Allocate a new MemStack object.
Definition: stack.c:388
class_construct
void class_construct(AvrClass *klass)
Initializes the AvrClass data structure.
Definition: avrclass.c:61
stack_construct
void stack_construct(Stack *stack, StackFP_Pop pop, StackFP_Push push)
Constructor for the Stack class.
Definition: stack.c:99
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.