code: /**
   * Copyright (c) 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.
   *
   * Creation date: Nov 22, 2005
   */
  
  package avrora.sim.mcu;
  
  import avrora.sim.FiniteStateMachine;
  import avrora.sim.Simulator;
  import avrora.sim.output.SimPrinter;
  import avrora.sim.clock.Clock;
  import avrora.sim.clock.ClockDomain;
  import avrora.sim.platform.Platform;
  
  /**
   * @author Ben L. Titzer
   */
  public abstract class DefaultMCU implements Microcontroller {
  
      protected final Microcontroller.Pin[] pins;
      protected final RegisterSet registers;
      protected Platform platform;
      protected Simulator simulator;
      protected SimPrinter pinPrinter;
      protected final ClockDomain clockDomain;
      protected final FiniteStateMachine sleepState;
      private boolean pinPrinterInit;
  
      protected DefaultMCU(ClockDomain cd, int np, RegisterSet regs, FiniteStateMachine sleep) {
          clockDomain = cd;
          pins = new Microcontroller.Pin[np];
          sleepState = sleep;
          registers = regs;
      }
  
      /**
       * The <code>getFSM()</code> method gets a reference to the finite state machine that represents
       * the sleep modes of the MCU. The finite state machine allows probing of the sleep mode transitions.
       * @return a reference to the finite state machine representing the sleep mode of the MCU
       */
      public FiniteStateMachine getFSM() {
          return sleepState;
      }
  
      /**
       * The <code>getRegisterSet()</code> method gets a reference to the register set of the microcontroller.
       * The register set contains all of the IO registers for this microcontroller.
       *
       * @return a reference to the register set of this microcontroller instance
       */
      @Override
      public RegisterSet getRegisterSet() {
          return registers;
      }
  
      /**
       * The <code>getPin()</code> method looks up the specified pin by its number and returns a reference to
       * that pin. The intended users of this method are external device implementors which connect their
       * devices to the microcontroller through the pins.
       *
       * @param num the pin number to look up
       * @return a reference to the <code>Pin</code> object corresponding to the named pin if it exists; null
       *         otherwise
       */
      @Override
      public Microcontroller.Pin getPin(int num) {
          if (num < 0 || num > pins.length) return null;
          return pins[num];
      }
  
      /**
       * The <code>getClock()</code> method gets a reference to a specific clock on this device. For example,
       * the external clock, or a specific device's clock can be accessed by specifying its name.
       * @param name the name of the clock to get
       * @return a reference to the <code>Clock</code> instance for the specified clock if it exists
       */
      public Clock getClock(String name) {
          return clockDomain.getClock(name);
      }
  
      /**
       * The <code>getSimulator()</code> method gets a reference to the simulator for this microcontroller instance.
       * @return a reference to the simulator instance for this microcontroller
       */
      @Override
      public Simulator getSimulator() {
          return simulator;
      }
  
      /**
       * The <code>getPlatform()</code> method returns the platform for this microcontroller.
       * @return the platform instance containing this microcontroller
       */
      @Override
      public Platform getPlatform() {
          return platform;
      }
  
      /**
       * The <code>setPlatform()</code> method sets the platform instance for this microcontroller
       * @param p the platform instance associated with this microcontroller
       */
      @Override
      public void setPlatform(Platform p) {
          platform = p;
      }
  
      /**
       * The <code>getClockDomain()</code> method gets a reference to the <code>ClockDomain</code> instance for
       * this node that contains the main clock and any derived clocks for this microcontroller.
       * @return a reference to the clock domain for this microcontroller
       */
      @Override
      public ClockDomain getClockDomain() {
          return clockDomain;
      }
  
      /**
       * The <code>Pin</code> class implements a model of a pin on the ATMegaFamily for the general purpose IO
       * ports.
       */
      protected class Pin implements Microcontroller.Pin {
          protected final int number;
  
          boolean level;
          boolean outputDir;
          boolean pullup;
  
          Input input;
          Output output;
  
          protected Pin(int num) {
              number = num;
          }
  
          @Override
          public void connectOutput(Output o) {
              output = o;
          }
  
          @Override
          public void connectInput(Input i) {
              input = i;
          }
  
          protected void setOutputDir(boolean out) {
              outputDir = out;
              if (out) write(level);
          }
  
          protected void setPullup(boolean pull) {
              pullup = pull;
          }
  
          protected boolean read() {
              boolean result;
              if (!outputDir) {
                  if (input != null)
                      result = input.read();
                  else
                      result = pullup;
  
              } else {
                  result = level;
              }
              // print the result of the read
              printRead(result);
              return result;
          }
  
          private void printRead(boolean result) {
              if ( pinPrinter == null ) {
                  pinPrinter = simulator.getPrinter("mcu.pin");
              }
           //   if ( pinPrinter != null ) {
           //       String dir = getDirection();
           //       pinPrinter.println("READ PIN: " + number + ' ' + dir + "<- " + result);
           //    }
          }
  
          private String getDirection() {
              if (!outputDir) {
                  if (input != null)
                      return "[input] ";
                  else
                      return "[pullup:" + pullup + "] ";
  
              } else {
                  return "[output] ";
              }
          }
  
          protected void write(boolean value) {
              level = value;
              // print the write
              printWrite(value);
              if (outputDir && output != null) output.write(value);
          }
  
          private void printWrite(boolean value) {
              if (pinPrinterInit) {
                  pinPrinter = simulator.getPrinter("mcu.pin");
                  pinPrinterInit = true;
              }
              if (pinPrinter != null) {
                  String dir = getDirection();
           //       if ((number<25) || (number>32)) //dakdebug
           //       pinPrinter.println("WRITE PIN: " + number + ' ' + dir + "-> " + value);
              }
          }
      }
  }
  