/* * $Id: devsupp.c,v 1.12 2003/09/12 21:16:33 troth Exp $ * **************************************************************************** * * simulavr - A simulator for the Atmel AVR family of microcontrollers. * Copyright (C) 2001, 2002 Theodore A. Roth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * **************************************************************************** */ /** * \file devsupp.c * \brief Contains definitions for device types (i.e. at90s8515, at90s2313, etc.) * * This module is used to define the attributes for each device in the AVR * family. A generic constructor is used to create a new AvrCore object with the * proper ports, built-in peripherals, memory layout, registers, and interrupt * vectors, etc. */ #include #include #include #include #include "avrerror.h" #include "avrmalloc.h" #include "avrclass.h" #include "utils.h" #include "callback.h" #include "op_names.h" #include "storage.h" #include "flash.h" #include "vdevs.h" #include "memory.h" #include "stack.h" #include "register.h" #include "sram.h" #include "eeprom.h" #include "timers.h" #include "ports.h" #include "avrcore.h" #ifndef DOXYGEN /* don't expose to doxygen */ /* * Used to select which vector table the device uses. * The value is an index into the global_vtable_list[] array * defined in intvects.c. */ enum _vector_table_select { VTAB_AT90S1200 = 0, VTAB_AT90S2313, VTAB_AT90S4414, VTAB_ATMEGA8, VTAB_ATMEGA16, VTAB_ATMEGA103, VTAB_ATMEGA128, }; /* Structure for defining a supported device */ typedef struct _DevSuppDefn DevSuppDefn; struct _DevSuppDefn { char *name; /* name of device type */ StackType stack_type; /* STACK_HARDWARE or STACK_MEMORY */ int sram_base; /* base addr of sram */ int irq_vect_idx; /* interrupt vector table index */ /* Ports is a string with two characters used to specify each port. The first char is the port id and the second is the width of the port. For example, the at90s1200 has two ports, 'b' and 'd' which are 8 and 7 bits wide respectively, would be specified with a string as such: "b8d7". */ char *ports; struct { int pc; /* width of program counter (usually 2, maybe 3) */ int stack; /* depth of stack (only used by hardware stack) */ int flash; /* bytes of flash memory */ int sram; /* bytes of sram memory */ int eeprom; /* bytes of eeprom memory */ } size; struct { /* io register function masks */ uint8_t eecr; uint8_t mcucr; uint8_t acsr; uint8_t wdtcr; uint8_t timsk; } mask; }; #endif /* DOXYGEN */ /* * Device Definitions */ static DevSuppDefn defn_at90s1200 = { /* name */ "at90s1200", /* stack_type */ STACK_HARDWARE, /* sram_base */ 0, /* irq_vect_idx */ VTAB_AT90S1200, /* ports */ "b8d7", { /* size.pc */ 2, /* size.stack */ 3, /* size.flash */ 1024, /* size.sram */ 0, /* size.eeprom */ 64 }, { /* mask.eecr */ (mask_EERE | mask_EEWE), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE0) } }; static DevSuppDefn defn_at90s2313 = { /* name */ "at90s2313", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT90S2313, /* ports */ "b8d7", { /* size.pc */ 2, /* size.stack */ 0, /* size.flash */ 2*1024, /* size.sram */ 128, /* size.eeprom */ 128 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_at90s4414 = { /* name */ "at90s4414", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT90S4414, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* size.stack */ 0, /* size.flash */ 4*1024, /* size.sram */ 256, /* size.eeprom */ 256 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_at90s8515 = { /* name */ "at90s8515", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT90S4414, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* size.stack */ 0, /* size.flash */ 8*1024, /* size.sram */ 512, /* size.eeprom */ 512 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_atmega8 = { /* name */ "atmega8", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_ATMEGA8, /* ports */ "b8c7d8", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 8*1024, /* size.sram */ 1*1024, /* size.eeprom */ 512 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_atmega16 = { /* name */ "atmega16", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_ATMEGA16, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 16*1024, /* size.sram */ 1*1024, /* size.eeprom */ 512 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_atmega103 = { /* name */ "atmega103", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_ATMEGA103, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* size.stack */ 0, /* size.flash */ 128*1024, /* size.sram */ 4*1024, /* size.eeprom */ 4*1024 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_atmega128 = { /* name */ "atmega128", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_EXTENDED_IO_BASE, /* irq_vect_idx */ VTAB_ATMEGA128, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* size.stack */ 0, /* size.flash */ 128*1024, /* size.sram */ 4*1024, /* size.eeprom */ 4*1024 }, { /* mask.eecr */ (mask_EERE | mask_EEWE | mask_EEMWE), /* mask.mcucr */ (mask_SRE | mask_SRW | mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (mask_ACD | mask_ACO | mask_ACI | mask_ACIE | mask_ACIC | mask_ACIS1 | mask_ACIS0), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } }; static DevSuppDefn defn_at43usb355 = { /* name */ "at43usb355", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT43USB, /* ports */ "a8b8d8e4", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 24*1024, /* size.sram */ 1*1024, /* size.eeprom */ 0 }, { /* mask.eecr */ (), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } static DevSuppDefn defn_at43usb320 = { /* name */ "at43usb320", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT43USB, /* ports */ "a8b8c8d8", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 32*1024, /* size.sram */ 512, /* size.eeprom */ 0 }, { /* mask.eecr */ (), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } static DevSuppDefn defn_at43usb324 = { /* name */ "at43usb324", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT43USB, /* ports */ "a8b8c8d8e2", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 16*1024, /* size.sram */ 512, /* size.eeprom */ 0 }, { /* mask.eecr */ (), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } static DevSuppDefn defn_at43usb325 = { /* name */ "at43usb325", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT43USB, /* ports */ "a8b8c8d8e8f4", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 16*1024, /* size.sram */ 512, /* size.eeprom */ 0 }, { /* mask.eecr */ (), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } static DevSuppDefn defn_at43usb326 = { /* name */ "at43usb326", /* stack_type */ STACK_MEMORY, /* sram_base */ SRAM_BASE, /* irq_vect_idx */ VTAB_AT43USB, /* ports */ "a8b8c8d8e8f4", { /* size.pc */ 2, /* 13 bits */ /* size.stack */ 0, /* size.flash */ 16*1024, /* size.sram */ 512, /* size.eeprom */ 0 }, { /* mask.eecr */ (), /* mask.mcucr */ (mask_SE | mask_SM | mask_ISC11 | mask_ISC10 | mask_ISC01 | mask_ISC00), /* mask.acsr */ (), /* mask.wdtcr */ (mask_WDTOE | mask_WDE | mask_WDP2 | mask_WDP1 | mask_WDP0), /* mask.timsk */ (mask_TOIE1 | mask_OCIE1A | mask_OCIE1B | mask_TICIE1 | mask_TOIE0) } /** \brief List of supported devices. */ static DevSuppDefn *devices_supported[] = { &defn_at90s1200, &defn_at90s2313, &defn_at90s4414, &defn_at90s8515, &defn_atmega8, &defn_atmega16, &defn_atmega103, &defn_atmega128, &defn_at43USB355, &defn_at43USB320, &defn_at43USB324, &defn_at43USB325, &defn_at43USB326, NULL }; /* * Private. * * Look up a device name in support list. * * Returns pointer to DevSuppDefn or NULL if not found. */ static DevSuppDefn *dev_supp_lookup_device( char *dev_name ) { DevSuppDefn **dev = devices_supported; int len; while ( (*dev) ) { len = strlen((*dev)->name); if ( strncmp((*dev)->name, dev_name, len) == 0 ) return (*dev); dev++; } return NULL; } /** \brief Print a list of supported devices to a file pointer. */ void dev_supp_list_devices( FILE *fp ) { DevSuppDefn **dev; for (dev=devices_supported; (*dev); dev++) fprintf(fp, " %s\n", (*dev)->name); } /** * \brief Creates a new core. * * This constructs an AVR CPU with the characteristics of the device * passed in as dev_name. It is sort of the master constructor for a core. * * \return A pointer to an AVR core with properties of dev_name */ AvrCore *dev_supp_create_core( char *dev_name ) { AvrCore *core = NULL; DevSuppDefn *dev = dev_supp_lookup_device( dev_name ); VDevice *vdev; char *pp; if (dev) { fprintf( stderr, "\nSimulating a %s device.\n\n", dev->name ); /* Create the base core object */ core = avr_core_new( dev->size.flash, dev->size.pc, dev->stack_type, dev->size.stack, dev->irq_vect_idx ); /* all devices have a timer/counter 0 */ avr_core_attach_vdev( core, (VDevice *)timer0_new() ); /* Attach device specific vdevs */ if (dev->size.sram > 0) { vdev = (VDevice *)sram_new( dev->sram_base, dev->size.sram ); avr_core_attach_vdev( core, vdev ); } if (dev->size.eeprom > 0) { vdev = (VDevice *)eeprom_new( dev->size.eeprom, dev->mask.eecr ); avr_core_attach_vdev( core, vdev ); } if (dev->mask.mcucr) { vdev = (VDevice *)mcucr_new( dev->mask.mcucr ); avr_core_attach_vdev( core, vdev ); } if (dev->mask.acsr) { vdev = (VDevice *)acsr_new( dev->mask.acsr ); avr_core_attach_vdev( core, vdev ); } if (dev->mask.wdtcr) { vdev = (VDevice *)wdtcr_new( dev->mask.wdtcr ); avr_core_attach_vdev( core, vdev ); } if (dev->mask.timsk) { vdev = (VDevice *)timer_intr_new( dev->mask.timsk ); avr_core_attach_vdev( core, vdev ); } /* Attach device port vdevs */ pp = dev->ports; while (*pp) { VDevice *port = NULL; int width = 0; /* Get the width of the port */ switch (pp[1]) { case '7': width = PORT_7_BIT; break; case '8': width = PORT_8_BIT; break; default: avr_error( "Invalid port width: port=%d, width=0d", pp[0], pp[1] ); } /* Create the port VDevice */ switch (pp[0]) { case 'a': case 'A': port = (VDevice *)porta_new(width); break; case 'b': case 'B': port = (VDevice *)portb_new(width); break; case 'c': case 'C': port = (VDevice *)portc_new(width); break; case 'd': case 'D': port = (VDevice *)portd_new(width); break; default: avr_error( "Invalid port id: port=%d", pp[0] ); } avr_core_attach_vdev( core, port ); pp += 2; } } return core; }