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.clock.Clock;
  import avrora.sim.*;
  import avrora.sim.output.SimPrinter;
  import cck.util.Arithmetic;
  import cck.text.StringUtil;
  
  /**
   * The <code>RegisterUtil</code> class implements a number of utilities for
   * constructing new views of register state. For example, a view of a bit as
   * a boolean, a view of a subrange of bits, a stacked view of multiple registers,
   * etc.
   *
   * @author Ben L. Titzer
   */
  public class RegisterUtil {
  
      public static class Buffer {
          protected final Register r1;
          protected final Register r2;
  
          public Buffer(Register a, Register b) {
              r1 = a;
              r2 = b;
          }
  
          public void flush() {
              r2.write(r1.getValue());
          }
      }
  
      public static class BoolView implements BooleanView, RegisterView.RegisterValueSetListener {
          protected final RegisterView reg;
          protected final byte low;
          protected BooleanView.ValueSetListener listener; 
  
          public BoolView(RegisterView r, byte l) {
              reg = r;
              low = l;
              r.registerValueSetListener(this);
          }
  
          public boolean getValue() {
              return (reg.getValue() >> low & 1) == 1;
          }
  
          public void setValue(boolean v) {
              if ( v ) reg.setValue(reg.getValue() | 1 << low);
              else reg.setValue(reg.getValue() & ~(1 << low));
          }
          
          public void onValueSet(RegisterView view, int oldValue, int newValue) {
              if (listener != null && ((oldValue ^ newValue) & (1 << low)) != 0) {
                  listener.onValueSet(this, getValue());
              }
          }
  
          public void setValueSetListener(ValueSetListener listener) {
              this.listener = listener;
          }
      }
  
      public static class ByteArrayView extends AbstractRegisterView implements RegisterView {
          protected final byte[] values;
          protected final int index;
  
          /** 
           * @param v Array which is viewed. If used in conjunction with listeners, caller has to guarantee not to 
           * modify the affected array value, but use .setValue instead.
           */
          public ByteArrayView(byte[] v, int i) {
              values = v;
              index = i;
          }
          public int getWidth() {
              return 8;
          }
          public int getValue() {
              return values[index];
          }
  
          public void setValue(int val) {
              int oldVal = getValue();
              values[index] = (byte)val;
              notify(oldVal, val);
          }
      }
  
      public static class CharArrayView extends AbstractRegisterView implements RegisterView {
          protected final char[] values;
          protected final int index;
  
          /** 
           * @param v Array which is viewed. If used in conjunction with listeners, caller has to guarantee not to 
           * modify the affected array value, but use .setValue instead.
           */
          public CharArrayView(char[] v, int i) {
              values = v;
              index = i;
          }
          public int getWidth() {
              return 16;
          }
          public int getValue() {
              return values[index];
          }
  
          public void setValue(int val) {
              int oldVal = getValue();
              values[index] = (char)val;
              notify(oldVal, val);
          }
      }
  
      public static class BitRangeView extends AbstractRegisterView implements RegisterView, RegisterView.RegisterValueSetListener {
          protected final RegisterView reg;
          protected final byte low;
          protected final byte width;
          protected final int mask;
  
          public BitRangeView(RegisterView r, byte l, byte h) {
              low = l;
              mask = Arithmetic.getBitRangeMask(l, h);
              width = (byte)(h - l + 1);
              reg = r;
              r.registerValueSetListener(this);
          }
  
          public int getWidth() {
              return width;
          }
  
          public int getValue() {
              return (reg.getValue() & mask) >> low;
          }
  
          public void setValue(int val) {
              reg.setValue(reg.getValue() & ~mask | ((val << low) & mask));
          }
  
          public void onValueSet(RegisterView view, int oldValue, int newValue) {
              oldValue &= mask;
              newValue &= mask;
              if (oldValue != newValue) {
                  notify(oldValue >> low, newValue >> low);
              }
          }
      }
  
      public static class PermutedView implements RegisterView {
          protected final RegisterView reg;
          protected final byte[] bits;
  
          public PermutedView(RegisterView r, byte[] b) {
              bits = b;
              reg = r;
          }
  
          public int getWidth() {
              return bits.length;
          }
  
          public int getValue() {
              int val = reg.getValue();
              int res = 0;
              for ( int cntr = 0; cntr < bits.length; cntr++ ) {
                  int bit = (val >> bits[cntr]) & 1;
                  res = res | bit << cntr;
              }
              return res;
          }
  
          public void setValue(int val) {
              int res = reg.getValue();
              for ( int cntr = 0; cntr < bits.length; cntr++ ) {
                  int nbit = (val >> cntr) & 1;
                  res = res & ~(1 << bits[cntr]) | nbit << bits[cntr];
              }
              reg.setValue(res);
          }
  
          public void registerValueSetListener(RegisterValueSetListener listener) {
              throw new UnsupportedOperationException();
          }
      }
  
      public static class StackedView implements RegisterView {
          protected final RegisterView[] regs;
          protected final int width;
  
          public StackedView(RegisterView[] r) {
              regs = r;
              int w = 0;
              for ( int i = 0; i < r.length; i++ ) w += regs[i].getWidth();
              width = w;
          }
  
          public int getWidth() {
              return width;
          }
  
          public int getValue() {
              int val = 0;
              for ( int i = 0, p = 0; i < regs.length; i++ ) {
                  RegisterView r = regs[i];
                  val = val | r.getValue() << p;
                  p += r.getWidth();
              }
              return val;
          }
  
          public void setValue(int val) {
              for ( int i = 0, p = 0; i < regs.length; i++ ) {
                  RegisterView r = regs[i];
                  r.setValue(val); // by design, setValue() will ignore high-order bitss
                  p += r.getWidth();
                  val = val >> p;
              }
          }
          
          public void registerValueSetListener(RegisterValueSetListener listener) {
              throw new UnsupportedOperationException();
          }
      }
  
      /**
       * The <code>TimedBuffer</code> class implements a buffer for writes from one register
       * to another. Each write to the first register will be intercepted and forwarded to
       * the second register after a specified number of ticks of the specified clock.
       * This class implements the notifications and events necessary to accomplish the
       * functionality.
       */
      public static class TimedBuffer implements Register.Watch, Simulator.Event {
          protected final Clock clock;
          protected final Register r1;
          protected final Register r2;
          protected int value;
          protected long delay;
  
          public TimedBuffer(Clock c, Register a, Register b, long d) {
              clock = c;
              r1 = a;
              r2 = b;
              delay = d;
              r1.addWatch(this);
          }
  
          public void fireAfterWrite(Register r, int oldv, int newv) {
              value = newv;
              clock.insertEvent(this, delay);
          }
  
          public void fireAfterRead(Register r, int oldv, int newv) {
              // do nothing.
          }
  
          public void setDelay(long cycles) {
              delay = cycles;
          }
  
          public void fire() {
              r2.write(value);
          }
      }
  
      public static avrora.sim.state.BooleanView booleanView(RegisterView sup, int low) {
          return new BoolView(sup, (byte)low);
      }
  
      public static RegisterView bitView(RegisterView sup, int low) {
          return new BitRangeView(sup, (byte)low, (byte)low);
      }
  
      public static BitRangeView bitRangeView(RegisterView sup, int low, int high) {
          return new BitRangeView(sup, (byte)low, (byte)high);
      }
  
      public static RegisterView permutedView(RegisterView sup, byte[] perm) {
          return new PermutedView(sup, perm);
      }
  
      public static RegisterView stackedView(RegisterView a, RegisterView b) {
          return new StackedView(new RegisterView[] { a, b });
      }
  
      public static RegisterView stackedView(RegisterView[] a) {
          return new StackedView(a);
      }
  
      public static class RegisterPrinter implements Register.Watch {
          protected final SimPrinter printer;
          protected final String name;
  
          public RegisterPrinter(SimPrinter p, String n) {
              printer = p;
              name = n;
          }
          public void fireAfterWrite(Register r, int oldv, int newv) {
              printer.println(name+"    <=   "+ StringUtil.toMultirepString(newv, r.width));
          }
  
          public void fireAfterRead(Register r, int oldv, int newv) {
              printer.println(name+"    ->   "+ StringUtil.toMultirepString(oldv, r.width));
          }
      }
  
      public static void instrumentRegister(SimPrinter sp, Register reg, String name) {
          if (sp != null) reg.addWatch(new RegisterPrinter(sp, name));
      }
  
      public static class ConstantBehavior extends VolatileBehavior {
          public final int value;
          public ConstantBehavior(int val) {
              value = val;
          }
          public int read(int cur) {
              return value;
          }
          public int write(int cur, int nv) {
              return value;
          }
      }
  
      public static class ReadonlyBehavior extends VolatileBehavior {
          public int write(int cur, int nv) {
              return cur;
          }
      }
  }
  