code: /**
   * Copyright (c) 2006, 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: Sep 20, 2006
   */
  
  package avrora.sim.state;
  
  import avrora.sim.util.TransactionalList;
  
  /**
   * The <code>Register</code> class represents a register of a certain
   * bit width within a simulated CPU or device. A <code>Register</code>
   * object allows instrumentation to be both state access (reads)
   * and state updates (writes). This allows registers to be instrumented
   * by the user for profiling and debugging purposes, and also by
   * device implementations that may sub ranges of registers.
   *
   * </p>
   * This implementation models registers that can be as wide as 32 bits.
   *
   * @author Ben L. Titzer
   */
  public class Register extends AbstractRegisterView implements RegisterView {
  
      public final int width;
      public final int mask;
  
      protected int value;
  
      protected VolatileBehavior behavior;
      protected TransactionalList watches;
  
      /**
       * The constructor for the <code>Register</code> class creates a new register
       * with the specified width in bits.
       * @param w the width of the register in bits
       */
      public Register(int w) {
          width = w;
          mask = ~(-1 << w);
      }
  
      /**
       * The <code>Watch</code> interface allows clients to add instrumentation
       * to a register. The object implementing the watch is then consulted
       * when reads and writes to the register occur.
       *
       */
      public interface Watch {
          public void fireAfterWrite(Register r, int oldv, int newv);
          public void fireAfterRead(Register r, int oldv, int newv);
  
          public static class Empty implements Watch {
              public void fireAfterWrite(Register r, int oldv, int newv) {
                  // do nothing.
              }
              public void fireAfterRead(Register r, int oldv, int newv) {
                  // do nothing.
              }
          }
      }
  
      protected static class NotifyItem {
          protected final Watch notify;
          protected NotifyItem next;
          protected NotifyItem(Watch n, NotifyItem nx) {
              notify = n;
              next = nx;
          }
      }
  
      /**
       * The <code>write()</code> method writes a value to the register. This method
       * will notify any objects that have been added to the watch list.
       *
       * @param newv the value to write to this register
       */
      public void write(int newv) {
          int oldv = value;
          newv = newv & mask;
          value = (behavior != null ? mask & behavior.write(value, newv) : newv);
          if ( watches != null ) {
              // call instrumentation code.
              watches.beginTransaction();
              for ( TransactionalList.Link n = watches.getHead(); n != null; n = n.next ) {
                  ((Watch)n.object).fireAfterWrite(this, oldv, newv);
              }
              watches.endTransaction();
          }
          notify(oldv, newv);
      }
      /**
       * The <code>read()</code> method reads a value from this register. This method
       * will trigger calls to an objects in the watch list.
       * @return the value in this register
       */
      public int read() {
          int oldv = value;
          int newv = value;
          if ( behavior != null ) value = newv = mask & behavior.read(value);
          if ( watches != null ) {
              // call instrumentation code.
              watches.beginTransaction();
              for ( TransactionalList.Link n = watches.getHead(); n != null; n = n.next ) {
                  ((Watch)n.object).fireAfterRead(this, oldv, newv);
              }
              watches.endTransaction();
          }
          return value;
      }
  
      /**
       * The <code>setBehavior()</code> method sets the behavior of this register.
       * @param b the behavior for this register
       */
      public void setBehavior(VolatileBehavior b) {
          behavior = b;
      }
  
      /**
       * The <code>setValue()</code> method sets the value of this register, without triggering
       * the notification of any objects in the notification list. This interface should not
       * be used by client (user) code, but is intended for subfields and devices using
       * subfields.
       * It will, however, trigger registered ValueSetListeners
       * @param val the value to which to set the register
       */
      public void setValue(int val) {
          int oldVal = value;
          value = val & mask;
          notify(oldVal, value);
      }
  
      /**
       * The <code>getValue()</code> method retrieves the value from this register, without triggering
       * the notification of any objects in the notification list. This interface should be used
       * by client code (if necessary at all) to avoid recursive triggering of notifications.
       * @return the value of this register
       */
      public int getValue() {
          return value;
      }
  
      /**
       * The <code>getWidth()</code> method returns the width of this register (or register view)
       * in bits.
       * @return the width of this view in bits.
       */
      public int getWidth() {
          return width;
      }
  
      public void addWatch(Watch w) {
          if ( watches == null ) {
              watches = new TransactionalList();
          }
          watches.add(w);
      }
  
      public void removeWatch(Watch w) {
          watches.remove(w);
          if ( watches.isEmpty() ) watches = null;
      }
  }
  