code: /**
   * Copyright (c) 2004-2005, Regents of the University of California
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the University of California, Los Angeles nor the
   * names of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  package avrora.sim.mcu;
  
  import avrora.arch.avr.AVRProperties;
  import avrora.arch.legacy.LegacyInterpreter;
  import avrora.core.Program;
  import avrora.sim.*;
  import avrora.sim.clock.ClockDomain;
  import cck.util.Arithmetic;
  import java.util.HashMap;
  
  /**
   * The <code>ATMegaX8</code> class represents the ATMega8 series microcontrollers from Atmel. These
   * microcontrollers have various amounts of memory, and a host of internal devices such as
   * ADC, SPI, and timers.
   *
   * @author Ben L. Titzer
   * @author Pekka Nikander
   * @author Bastian Schlich
   * @author John F. Schommer
   *
   */
  public abstract class ATMegaX8 extends ATMegaFamilyNew {
  
      public static final int _1kb = 1024;
      public static final int _512b = 512;
  
      public static final int ATMEGAX8_IOREG_SIZE = 256;
      public static final int ATMEGAX8_NUM_PINS = 32; // 28 in PDIP, missing ADC6-7.
      public static final int ATMEGAX8_NUM_INTS = 24;
  
      public static final int MODE_IDLE       = 1;
      public static final int MODE_ADCNRED    = 2;
      public static final int MODE_POWERDOWN  = 3;
      public static final int MODE_POWERSAVE  = 4;
      public static final int MODE_RESERVED1  = 5;
      public static final int MODE_RESERVED2  = 6;
      public static final int MODE_STANDBY    = 7;
      public static final int MODE_RESERVED3  = 8;
  
      protected static final String[] idleModeNames = {
          "Active",
          "Idle",
          "ADC Noise Reduction",
          "Power Down",
          "Power Save",
          "RESERVED 1",
          "RESERVED 2",
          "Standby",
          "RESERVED 3"
      };
  
      protected final ActiveRegister MCUCR_reg;
  
      public static final int pkgPDIP = 0;
      public static final int pkgTQFP = 1;
      public static final int pkgMLF  = 2;
  
      public static int pkg = pkgPDIP;
  
      protected static final HashMap<String, Integer> pinAssignments = new HashMap<String, Integer>(150);
      protected static final RegisterLayout rl = new RegisterLayout(ATMEGAX8_IOREG_SIZE, 8);
      protected static final HashMap<String, Integer> interruptAssignments = new HashMap<String, Integer>(30);
  
      static {
          // statically initialize the pin assignments for this microcontroller
  
  	switch (pkg) {
  	case pkgPDIP:
  	    addPin(pinAssignments, 1, "RESET", "PC6");
  	    addPin(pinAssignments, 2, "RXD", "PD0");
  	    addPin(pinAssignments, 3, "TXD", "PD1");
  	    addPin(pinAssignments, 4, "INT0", "PD2");
  	    addPin(pinAssignments, 5, "INT1", "OC2B", "PD3");
  	    addPin(pinAssignments, 6, "T0", "XCK", "PD4");
  	    addPin(pinAssignments, 7, "VCC");
  	    addPin(pinAssignments, 8, "GND.1");
  	    addPin(pinAssignments, 9, "TOSC1", "XTAL1", "PB6");
  	    addPin(pinAssignments, 10, "TOSC2", "XTAL2", "PB7");
  	    addPin(pinAssignments, 11, "T1", "OC0B", "PD5");
  	    addPin(pinAssignments, 12, "AIN0", "OC0A", "PD6");
  	    addPin(pinAssignments, 13, "AIN1", "PD7");
  	    addPin(pinAssignments, 14, "ICP1", "CLK0", "PB0");
  	    addPin(pinAssignments, 15, "OC1A", "PB1");
  	    addPin(pinAssignments, 16, "SS", "OC1B", "PB2");
  	    addPin(pinAssignments, 17, "MOSI", "OC2A", "PB3");
  	    addPin(pinAssignments, 18, "MISO", "PB4");
  	    addPin(pinAssignments, 19, "SCK", "PB5");
  	    addPin(pinAssignments, 20, "AVCC");
  	    addPin(pinAssignments, 21, "AREF");
  	    addPin(pinAssignments, 22, "GND.2");
  	    addPin(pinAssignments, 23, "ADC0", "PC0");
  	    addPin(pinAssignments, 24, "ADC1", "PC1");
  	    addPin(pinAssignments, 25, "ADC2", "PC2");
  	    addPin(pinAssignments, 26, "ADC3", "PC3");
  	    addPin(pinAssignments, 27, "ADC4", "SDA", "PC4");
  	    addPin(pinAssignments, 28, "ADC5", "SLC", "PC5");
  	    break;
  	case pkgTQFP:
  	case pkgMLF:
  	    addPin(pinAssignments, 1, "INT1", "OC2B", "PD3");
  	    addPin(pinAssignments, 2, "T0", "XCK", "PD4");
  	    addPin(pinAssignments, 3, "GND.1");
  	    addPin(pinAssignments, 4, "VCC.1");
  	    addPin(pinAssignments, 5, "GND.2");
  	    addPin(pinAssignments, 6, "VCC.2");
  	    addPin(pinAssignments, 7, "TOSC1", "XTAL1", "PB6");
  	    addPin(pinAssignments, 8, "TOSC2", "XTAL2", "PB7");
  
  	    addPin(pinAssignments, 9, "T1", "OC0B", "PD5");
  	    addPin(pinAssignments, 10, "AIN0", "OC0A", "PD6");
  	    addPin(pinAssignments, 11, "AIN1", "PD7");
  	    addPin(pinAssignments, 12, "ICP1", "CLK0", "PB0");
  	    addPin(pinAssignments, 13, "OC1A", "PB1");
  	    addPin(pinAssignments, 14, "SS", "OC1B", "PB2");
  	    addPin(pinAssignments, 15, "MOSI", "OC2A", "PB3");
  	    addPin(pinAssignments, 16, "MISO", "PB4");
  
  	    addPin(pinAssignments, 17, "SCK", "PB5");
  	    addPin(pinAssignments, 18, "AVCC");
  	    addPin(pinAssignments, 19, "ADC6");
  	    addPin(pinAssignments, 20, "AREF");
  	    addPin(pinAssignments, 21, "GND.3");
  	    addPin(pinAssignments, 22, "ADC7");
  	    addPin(pinAssignments, 23, "ADC0", "PC0");
  	    addPin(pinAssignments, 24, "ADC1", "PC1");
  
  	    addPin(pinAssignments, 25, "ADC2", "PC2");
  	    addPin(pinAssignments, 26, "ADC3", "PC3");
  	    addPin(pinAssignments, 27, "ADC4", "SDA", "PC4");
  	    addPin(pinAssignments, 28, "ADC5", "SLC", "PC5");
  	    addPin(pinAssignments, 29, "RESET", "PC6");
  	    addPin(pinAssignments, 30, "RXD", "PD0");
  	    addPin(pinAssignments, 31, "TXD", "PD1");
  	    break;
  	}
  
  	// High IO register
  	rl.addIOReg("UDR0",   0xC6);
  	rl.addIOReg("UBRR0H", 0xC5);
  	rl.addIOReg("UBRR0L", 0xC4);
  	rl.addIOReg("UCSR0C", 0xC2);
  	rl.addIOReg("UCSR0B", 0xC1);
  	rl.addIOReg("UCSR0A", 0xC0);
  	rl.addIOReg("TWAMR",  0xBD);
  	rl.addIOReg("TWCR",   0xBC);
  	rl.addIOReg("TWDR",   0xBB);
  	rl.addIOReg("TWAR",   0xBA);
  	rl.addIOReg("TWSR",   0xB9);
  	rl.addIOReg("TWBR",   0xB8);
  	rl.addIOReg("ASSR",   0xB6);
  	rl.addIOReg("OCR2B",  0xB4);
  	rl.addIOReg("OCR2A",  0xB3);
  	rl.addIOReg("TCNT2",  0xB2);
  	rl.addIOReg("TCCR2B", 0xB1, "FOC2A,FOC2B,..,WGM2[2],CS2[2:0]");
  	rl.addIOReg("TCCR2A", 0xB0, "COM2A[1:0],COM2B[1:0],..,WGM2[1:0]");
  
  	rl.addIOReg("OCR1BH", 0x8B);
  	rl.addIOReg("OCR1BL", 0x8A);
  	rl.addIOReg("OCR1AH", 0x89);
  	rl.addIOReg("OCR1AL", 0x88);
  	rl.addIOReg("ICR1H",  0x87);
  	rl.addIOReg("ICR1L",  0x86);
  	rl.addIOReg("TCNT1H", 0x85);
  	rl.addIOReg("TCNT1L", 0x84);
  	rl.addIOReg("TCCR1C", 0x82, "FOC1A,FOC1B");
  	rl.addIOReg("TCCR1B", 0x81, "ICNC1,ICES1,.,WGM1[3:2],CS1[2:0]");
  	rl.addIOReg("TCCR1A", 0x80, "COM1A[1:0],COM1B[1:0],..,WGM1[1:0]");
  	rl.addIOReg("DIDR1",  0x7F);
  	rl.addIOReg("DIDR0",  0x7E);
  	rl.addIOReg("ADMUX",  0x7C);
  	rl.addIOReg("ADCSRB", 0x7B);
  	rl.addIOReg("ADCSRA", 0x7A);
  	rl.addIOReg("ADCH",   0x79);
  	rl.addIOReg("ADCL",   0x78);
  
  	rl.addIOReg("TIMSK2", 0x70, ".....,OCIE2B,OCIE2A,TOIE2");
  	rl.addIOReg("TIMSK1", 0x6F, "..,ICIE1,..,OCIE1B,OCIE1A,TOIE1");
  	rl.addIOReg("TIMSK0", 0x6E, "..,OCIE0B,OCIE0A,TOIE0");
  	rl.addIOReg("PCMSK2", 0x6D);
  	rl.addIOReg("PCMSK1", 0x6C);
  	rl.addIOReg("PCMSK0", 0x6B);
  	rl.addIOReg("EICRA",  0x69);
  	rl.addIOReg("PCICR",  0x68);
  	rl.addIOReg("OSCCAL", 0x66);
  	rl.addIOReg("PRR",    0x64);
  	rl.addIOReg("CLKPR",  0x61);
  	rl.addIOReg("WDTCSR", 0x60);
  
          // Low IO registers
          rl.addIOReg("SREG",   0x3F);
          rl.addIOReg("SPH",    0x3E);
          rl.addIOReg("SPL",    0x3D);
          rl.addIOReg("SPMCSR", 0x37);
          rl.addIOReg("MCUCR",  0x35);
          rl.addIOReg("MCUCSR", 0x34);
          rl.addIOReg("SMCR",   0x33);
          rl.addIOReg("ACSR",   0x30);
  	rl.addIOReg("SPDR",   0x2E);
  	rl.addIOReg("SPSR",   0x2D);
  	rl.addIOReg("SPCR",   0x2C);
  	rl.addIOReg("GPIOR2", 0x2B);
  	rl.addIOReg("GPIOR1", 0x2A);
          rl.addIOReg("OCR0B",  0x28);
          rl.addIOReg("OCR0A",  0x27);
          rl.addIOReg("TCNT0" , 0x26, "FOC0A,FOC0B,..,WGM0[2],CS0[2:0]");
          rl.addIOReg("TCCR0B", 0x25, "COM0A[1:0],COM0B[1:0],..,WGM0[1:0]");
          rl.addIOReg("TCCR0A", 0x24);
          rl.addIOReg("GTCCR",  0x23);
          rl.addIOReg("EEARH",  0x22);
          rl.addIOReg("EEARL",  0x21);
          rl.addIOReg("EEDR",   0x20);
          rl.addIOReg("EECR",   0x1F);
          rl.addIOReg("GPIOR0", 0x1E);
          rl.addIOReg("EIMSK",  0x1D);
          rl.addIOReg("EIFR",   0x1C);
          rl.addIOReg("PCIFR",  0x1B);
          rl.addIOReg("TIFR2",  0x17, ".....,OCF2B,OCF2A,TOV2");
          rl.addIOReg("TIFR1",  0x16, "..,ICF1,..,OCF1B,OCF1A,TOV1");
          rl.addIOReg("TIFR0",  0x15, ".....,OCF0B,OCF0A,TOV0");
  	rl.addIOReg("PORTD",  0x0B);
  	rl.addIOReg("DDRD",   0x0A);
  	rl.addIOReg("PIND",   0x09);
  	rl.addIOReg("PORTC",  0x08);
  	rl.addIOReg("DDRC",   0x07);
  	rl.addIOReg("PINC",   0x06);
  	rl.addIOReg("PORTB",  0x05);
  	rl.addIOReg("DDRB",   0x04);
  	rl.addIOReg("PINB",   0x03);
  
          addInterrupt(interruptAssignments, "RESET", 1);
          addInterrupt(interruptAssignments, "INT0", 2);
          addInterrupt(interruptAssignments, "INT1", 3);
  	addInterrupt(interruptAssignments, "PCINT0", 4);
  	addInterrupt(interruptAssignments, "PCINT1", 5);
  	addInterrupt(interruptAssignments, "PCINT2", 6);
  	addInterrupt(interruptAssignments, "WDT", 7);
          addInterrupt(interruptAssignments, "TIMER2 COMPA", 8);
          addInterrupt(interruptAssignments, "TIMER2 COMPB", 9);
          addInterrupt(interruptAssignments, "TIMER2 OVF", 10);
          addInterrupt(interruptAssignments, "TIMER1 CAPT", 11);
          addInterrupt(interruptAssignments, "TIMER1 COMPA", 12);
          addInterrupt(interruptAssignments, "TIMER1 COMPB", 13);
          addInterrupt(interruptAssignments, "TIMER1 OVF", 14);
          addInterrupt(interruptAssignments, "TIMER0 COMPA", 15);
          addInterrupt(interruptAssignments, "TIMER0 COMPB", 16);
          addInterrupt(interruptAssignments, "TIMER0 OVF", 17);
          addInterrupt(interruptAssignments, "SPI, STC", 18);
          addInterrupt(interruptAssignments, "USART0, RX", 19);
          addInterrupt(interruptAssignments, "USART0, UDRE", 20);
          addInterrupt(interruptAssignments, "USART0, TX", 21);
          addInterrupt(interruptAssignments, "ADC", 22);
          addInterrupt(interruptAssignments, "EE READY", 23);
  
      }
  
      public ATMegaX8(int id, Simulation sim, AVRProperties props, ClockDomain cd, Program p,
                      int[][] transitionTimeMatrix) {
          super(cd, props,
  	      new FiniteStateMachine(cd.getMainClock(), MODE_ACTIVE, idleModeNames, transitionTimeMatrix));
          simulator = sim.createSimulator(id, LegacyInterpreter.FACTORY, this, p);
          interpreter = (AtmelInterpreter)simulator.getInterpreter();
          MCUCR_reg = getIOReg("MCUCR");
          installPins();
          installDevices();
      }
  
      protected void installPins() {
          for (int cntr = 0; cntr < properties.num_pins; cntr++)
              pins[cntr] = new Pin(cntr);
      }
  
      protected FlagRegister TIFR0_reg;
      protected MaskRegister TIMSK0_reg;
  
      protected FlagRegister TIFR1_reg;
      protected MaskRegister TIMSK1_reg;
  
      protected FlagRegister TIFR2_reg;
      protected MaskRegister TIMSK2_reg;
  
      protected void installDevices() {
          // set up the external interrupt mask and flag registers and interrupt range
          EIFR_reg = buildInterruptRange(true, "EIMSK", "EIFR", 2 /* INT0 */, 5 /* INT0-PCINT2 */);
  
          // set up the timer mask and flag registers and interrupt range
  	int[] TIFR0_mapping = { 10, 8, 9, -1, -1, -1, -1, -1, -1 };
          TIFR0_reg = new FlagRegister(interpreter, TIFR0_mapping);
          TIMSK0_reg = new MaskRegister(interpreter, TIFR0_mapping);
  
          installIOReg("TIMSK0", TIMSK0_reg);
          installIOReg("TIFR0",  TIFR0_reg);
  
          int[] TIFR1_mapping = { 14, 12, 13, -1, -1, -1, 11, -1, -1};
          TIFR1_reg = new FlagRegister(interpreter, TIFR1_mapping);
          TIMSK1_reg = new MaskRegister(interpreter, TIFR1_mapping);
  
          installIOReg("TIMSK1", TIMSK1_reg);
          installIOReg("TIFR1", TIFR1_reg);
  
          // set up the timer mask and flag registers and interrupt range
  	int[] TIFR2_mapping = { 17, 15, 16, -1, -1, -1, -1, -1, -1 };
          TIFR2_reg = new FlagRegister(interpreter, TIFR2_mapping);
          TIMSK2_reg = new MaskRegister(interpreter, TIFR2_mapping);
  
          installIOReg("TIMSK2", TIMSK2_reg);
          installIOReg("TIFR2",  TIFR2_reg);
  
  //      addDevice(new Timer0());
  //      addDevice(new Timer1(2));
  //      addDevice(new Timer2());
  
          buildPort('B');
          buildPort('C', 7);
          buildPort('D');
  
          addDevice(new EEPROM(properties.eeprom_size, this));
          addDevice(new USART("0", this));
  
          addDevice(new SPI(this));
          addDevice(new ADC(this, 8));
      }
  
  
      // permutation of sleep mode bits in the register (high order bits first)
      private static final int[] MCUCR_sm_perm = { 2, 4, 3 };
  
      protected int getSleepMode() {
          byte value = MCUCR_reg.read();
          boolean sleepEnable = Arithmetic.getBit(value, 5);
  
          if ( sleepEnable )
              return Arithmetic.getBitField(value, MCUCR_sm_perm) + 1;
          else
              return MODE_IDLE;
      }
  
  }
  