stack.c
Go to the documentation of this file.
00001 /*
00002  * $Id: stack.c,v 1.15 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 /** \file stack.c
00027     \brief Module for the definition of the stack. 
00028 
00029     Defines the classes stack, hw_stack, and mem_stack.
00030 
00031     FIXME: Ted, I would really really really love to put in a description of
00032     what is the difference between these three classes and how they're used,
00033     but I don't understand it myself. */
00034 
00035 #include <config.h>
00036 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 
00041 #include "avrerror.h"
00042 #include "avrmalloc.h"
00043 #include "avrclass.h"
00044 #include "utils.h"
00045 #include "callback.h"
00046 #include "op_names.h"
00047 
00048 #include "storage.h"
00049 #include "flash.h"
00050 
00051 #include "vdevs.h"
00052 #include "memory.h"
00053 #include "stack.h"
00054 #include "register.h"
00055 #include "sram.h"
00056 #include "eeprom.h"
00057 #include "timers.h"
00058 #include "ports.h"
00059 
00060 #include "avrcore.h"
00061 
00062 #include "display.h"
00063 
00064 static uint32_t hw_pop (Stack *stack, int bytes);
00065 static void hw_push (Stack *stack, int bytes, uint32_t val);
00066 
00067 static uint32_t mem_pop (Stack *stack, int bytes);
00068 static void mem_push (Stack *stack, int bytes, uint32_t val);
00069 
00070 /****************************************************************************\
00071  *
00072  * Stack(AvrClass) Definition. 
00073  *
00074 \****************************************************************************/
00075 
00076 /** \brief Allocates memory for a new Stack object
00077 
00078     This is a virtual method for higher level stack implementations and as
00079     such should not be used directly. */
00080 
00081 Stack *
00082 stack_new (StackFP_Pop pop, StackFP_Push push)
00083 {
00084     Stack *st;
00085 
00086     st = avr_new (Stack, 1);
00087     stack_construct (st, pop, push);
00088     class_overload_destroy ((AvrClass *)st, stack_destroy);
00089 
00090     return st;
00091 }
00092 
00093 /** \brief Constructor for the Stack class.
00094 
00095     This is a virtual method for higher level stack implementations and as
00096     such should not be used directly. */
00097 
00098 void
00099 stack_construct (Stack *stack, StackFP_Pop pop, StackFP_Push push)
00100 {
00101     if (stack == NULL)
00102         avr_error ("passed null ptr");
00103 
00104     class_construct ((AvrClass *)stack);
00105 
00106     stack->pop = pop;
00107     stack->push = push;
00108 }
00109 
00110 /** \brief Destructor for the Stack class.
00111 
00112     This is a virtual method for higher level stack implementations and as
00113     such should not be used directly. */
00114 
00115 void
00116 stack_destroy (void *stack)
00117 {
00118     if (stack == NULL)
00119         return;
00120 
00121     class_destroy (stack);
00122 }
00123 
00124 /** \brief Pops a byte or a word off the stack and returns it.
00125     \param stack A pointer to the Stack object from which to pop
00126     \param bytes Number of bytes to pop off the stack (1 to 4 bytes).
00127 
00128     \return The 1 to 4 bytes value popped from the stack. 
00129 
00130     This method provides access to the derived class's pop() method. */
00131 
00132 uint32_t
00133 stack_pop (Stack *stack, int bytes)
00134 {
00135     return stack->pop (stack, bytes);
00136 }
00137 
00138 /** \brief Pushes a byte or a word of data onto the stack.
00139     \param stack A pointer to the Stack object from which to pop.
00140     \param bytes Size of the value being pushed onto the stack (1 to 4 bytes).
00141     \param val The value to be pushed.
00142 
00143     This method provides access to the derived class's push() method. */
00144 
00145 void
00146 stack_push (Stack *stack, int bytes, uint32_t val)
00147 {
00148     stack->push (stack, bytes, val);
00149 }
00150 
00151 /****************************************************************************\
00152  *
00153  * HWStack(Stack) Definition.
00154  *
00155 \****************************************************************************/
00156 
00157 /** \brief Allocate a new HWStack object
00158 
00159     This is the stack implementation used by devices which lack SRAM and only
00160     have a fixed size hardware stack (e.i., the at90s1200) */
00161 
00162 HWStack *
00163 hwstack_new (int depth)
00164 {
00165     HWStack *st;
00166 
00167     st = avr_new (HWStack, 1);
00168     hwstack_construct (st, depth);
00169     class_overload_destroy ((AvrClass *)st, hwstack_destroy);
00170 
00171     return st;
00172 }
00173 
00174 /** \brief Constructor for HWStack object */
00175 
00176 void
00177 hwstack_construct (HWStack *stack, int depth)
00178 {
00179     if (stack == NULL)
00180         avr_error ("passed null ptr");
00181 
00182     stack_construct ((Stack *)stack, hw_pop, hw_push);
00183 
00184     stack->depth = depth;
00185     stack->stack = avr_new0 (uint32_t, depth);
00186 }
00187 
00188 /** \brief Destructor for HWStack object */
00189 
00190 void
00191 hwstack_destroy (void *stack)
00192 {
00193     if (stack == NULL)
00194         return;
00195 
00196     avr_free (((HWStack *)stack)->stack);
00197     stack_destroy (stack);
00198 }
00199 
00200 /* The HWStack pop method. */
00201 
00202 static uint32_t
00203 hw_pop (Stack *stack, int bytes)
00204 {
00205     HWStack *hwst = (HWStack *)stack;
00206     int i;
00207     uint32_t val = hwst->stack[0];
00208 
00209     for (i = 0; i < (hwst->depth - 1); i++)
00210     {
00211         hwst->stack[i] = hwst->stack[i + 1];
00212     }
00213 
00214     return val;
00215 }
00216 
00217 /* The HWStack push method. */
00218 
00219 static void
00220 hw_push (Stack *stack, int bytes, uint32_t val)
00221 {
00222     HWStack *hwst = (HWStack *)stack;
00223     int i;
00224 
00225     for (i = (hwst->depth - 1); i; i--)
00226     {
00227         hwst->stack[i - 1] = hwst->stack[i];
00228     }
00229 
00230     hwst->stack[0] = val;
00231 }
00232 
00233 /****************************************************************************\
00234  *
00235  * StackPointer(VDevice) Definition.
00236  *
00237 \****************************************************************************/
00238 
00239 #ifndef DOXYGEN                 /* don't expose to doxygen */
00240 
00241 typedef struct _StackPointer StackPointer;
00242 struct _StackPointer
00243 {
00244     VDevice parent;
00245 
00246     uint16_t SPL_addr;          /* Since some devices don't have a SPH, we
00247                                    only track SPL address and assume the SPH
00248                                    address is SPL_addr + 1. */
00249 
00250     uint8_t SPL;                /* Low byte of stack pointer */
00251     uint8_t SPH;                /* High byte of stack pointer */
00252 };
00253 
00254 #endif
00255 
00256 static StackPointer *sp_new (int addr, char *name);
00257 static void sp_construct (StackPointer *sp, int addr, char *name);
00258 static void sp_destroy (void *sp);
00259 static uint8_t sp_read (VDevice *dev, int addr);
00260 static void sp_write (VDevice *dev, int addr, uint8_t val);
00261 static void sp_reset (VDevice *dev);
00262 static uint16_t sp_get (VDevice *sp);
00263 static void sp_set (VDevice *sp, uint16_t val);
00264 static void sp_add_addr (VDevice *vdev, int addr, char *name, int rel_addr,
00265                          void *data);
00266 
00267 /** \brief Create the Stack Pointer VDevice.
00268 
00269     This should only be used in the DevSuppDefn io reg init structure. */
00270 
00271 VDevice *
00272 sp_create (int addr, char *name, int rel_addr, void *data)
00273 {
00274     return (VDevice *)sp_new (addr, name);
00275 }
00276 
00277 static StackPointer *
00278 sp_new (int addr, char *name)
00279 {
00280     StackPointer *sp;
00281 
00282     sp = avr_new (StackPointer, 1);
00283     sp_construct (sp, addr, name);
00284     class_overload_destroy ((AvrClass *)sp, sp_destroy);
00285 
00286     return sp;
00287 }
00288 
00289 static void
00290 sp_construct (StackPointer *sp, int addr, char *name)
00291 {
00292     if (sp == NULL)
00293         avr_error ("passed null ptr");
00294 
00295     vdev_construct ((VDevice *)sp, sp_read, sp_write, sp_reset, sp_add_addr);
00296 
00297     sp_add_addr ((VDevice *)sp, addr, name, 0, NULL);
00298 
00299     sp_reset ((VDevice *)sp);
00300 }
00301 
00302 static void
00303 sp_destroy (void *sp)
00304 {
00305     if (sp == NULL)
00306         return;
00307 
00308     vdev_destroy (sp);
00309 }
00310 
00311 static uint8_t
00312 sp_read (VDevice *dev, int addr)
00313 {
00314     StackPointer *sp = (StackPointer *)dev;
00315 
00316     if (addr == sp->SPL_addr)
00317         return sp->SPL;
00318     else if (addr == (sp->SPL_addr + 1))
00319         return sp->SPH;
00320     else
00321         avr_error ("Bad address: 0x%04x", addr);
00322 
00323     return 0;
00324 }
00325 
00326 static void
00327 sp_write (VDevice *dev, int addr, uint8_t val)
00328 {
00329     /* Don't need display_io_reg() here since it's called higher up in mem
00330        chain. */
00331 
00332     StackPointer *sp = (StackPointer *)dev;
00333 
00334     if (addr == sp->SPL_addr)
00335         sp->SPL = val;
00336     else if (addr == (sp->SPL_addr + 1))
00337         sp->SPH = val;
00338     else
00339         avr_error ("Bad address: 0x%04x", addr);
00340 }
00341 
00342 static void
00343 sp_reset (VDevice *dev)
00344 {
00345     StackPointer *sp = (StackPointer *)dev;
00346 
00347     display_io_reg (SPL_IO_REG, sp->SPL = 0);
00348     display_io_reg (SPH_IO_REG, sp->SPH = 0);
00349 }
00350 
00351 static uint16_t
00352 sp_get (VDevice *sp)
00353 {
00354     return (((StackPointer *)sp)->SPH << 8) + ((StackPointer *)sp)->SPL;
00355 }
00356 
00357 static void
00358 sp_set (VDevice *sp, uint16_t val)
00359 {
00360     display_io_reg (SPL_IO_REG, ((StackPointer *)sp)->SPL = val & 0xff);
00361     display_io_reg (SPH_IO_REG, ((StackPointer *)sp)->SPH = val >> 8);
00362 }
00363 
00364 static void
00365 sp_add_addr (VDevice *vdev, int addr, char *name, int rel_addr, void *data)
00366 {
00367     StackPointer *sp = (StackPointer *)vdev;
00368 
00369     if (strncmp ("SPL", name, 3) == 0)
00370         sp->SPL_addr = addr;
00371 
00372     else if (strncmp ("SPH", name, 3) == 0)
00373         ;
00374 
00375     else
00376         avr_error ("Bad address: 0x%04x", addr);
00377 }
00378 
00379 /****************************************************************************\
00380  *
00381  * MemStack(Stack) Definition.
00382  *
00383 \****************************************************************************/
00384 
00385 /** \brief Allocate a new MemStack object */
00386 
00387 MemStack *
00388 memstack_new (Memory *mem, int spl_addr)
00389 {
00390     MemStack *st;
00391 
00392     st = avr_new (MemStack, 1);
00393     memstack_construct (st, mem, spl_addr);
00394     class_overload_destroy ((AvrClass *)st, memstack_destroy);
00395 
00396     return st;
00397 }
00398 
00399 /** \brief Constructor for MemStack object */
00400 
00401 void
00402 memstack_construct (MemStack *stack, Memory *mem, int spl_addr)
00403 {
00404     if (stack == NULL)
00405         avr_error ("passed null ptr");
00406 
00407     stack_construct ((Stack *)stack, mem_pop, mem_push);
00408 
00409     class_ref ((AvrClass *)mem);
00410     stack->mem = mem;
00411 
00412     stack->SP = mem_get_vdevice_by_addr (mem, spl_addr);
00413     if (stack->SP == NULL)
00414     {
00415         avr_error ("attempt to attach non-extistant SPL register");
00416     }
00417     class_ref ((AvrClass *)stack->SP);
00418 }
00419 
00420 /** \brief Destructor for MemStack object */
00421 
00422 void
00423 memstack_destroy (void *stack)
00424 {
00425     MemStack *_stack = (MemStack *)stack;
00426 
00427     if (stack == NULL)
00428         return;
00429 
00430     class_unref ((AvrClass *)_stack->SP);
00431     class_unref ((AvrClass *)_stack->mem);
00432 
00433     stack_destroy (stack);
00434 }
00435 
00436 /* The MemStack pop method */
00437 
00438 static uint32_t
00439 mem_pop (Stack *stack, int bytes)
00440 {
00441     MemStack *mst = (MemStack *)stack;
00442     int i;
00443     uint32_t val = 0;
00444     uint16_t sp = sp_get (mst->SP);
00445 
00446     if ((bytes < 0) || (bytes >= sizeof (uint32_t)))
00447         avr_error ("bytes out of bounds: %d", bytes);
00448 
00449     for (i = bytes - 1; i >= 0; i--)
00450     {
00451         sp++;
00452         val |= (mem_read (mst->mem, sp) << (i * 8));
00453     }
00454 
00455     sp_set (mst->SP, sp);
00456 
00457     return val;
00458 }
00459 
00460 /* The MemStack push method. */
00461 
00462 static void
00463 mem_push (Stack *stack, int bytes, uint32_t val)
00464 {
00465     MemStack *mst = (MemStack *)stack;
00466     int i;
00467     uint16_t sp = sp_get (mst->SP);
00468 
00469     if ((bytes < 0) || (bytes >= sizeof (uint32_t)))
00470         avr_error ("bytes out of bounds: %d", bytes);
00471 
00472     for (i = 0; i < bytes; i++)
00473     {
00474         mem_write (mst->mem, sp, val & 0xff);
00475         val >>= 8;
00476         sp--;
00477     }
00478 
00479     sp_set (mst->SP, sp);
00480 }