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.sim.ActiveRegister;
  import avrora.sim.RWRegister;
  import cck.text.StringUtil;
  import cck.util.Util;
  import java.util.HashMap;
  import java.util.Iterator;
  
  /**
   * The <code>RegisterSet</code> class is a utility that simplifies the implementation
   * of certain IO registers that contain many types of fields whose bits may be spread
   * out and mixed up over multiple IO registers. For example, a 5 bit field used to
   * configure a device might be spread among multiple 1, 2, 3, or 4 bit fields across
   * multiple registers. This class allows a set of those registers to be created,
   * and collects together writes and reads easily.
   *
   * @author Ben L. Titzer
   */
  public class RegisterSet {
  
      /**
       * The <code>Field</code> class represents a collection of bits that represent
       * a quantity used by a device. The bits that make up this quantity might be spread
       * over multiple IO registers or mixed up among one IO register. Also, a field might
       * be in different IO registers depending on the microcontroller model. For this reason,
       * the <code>Field</code> class offers convenience to the device implementer by collecting
       * all of the individual bit updates in different registers into one coherent, contiguous
       * value.
       *
       * <p>
       * Device implementations can simply get a reference to the <code>Field</code> object
       * (such as a timer mode, prescaler value, etc) by calling <code>getField()</code>
       * in <code>RegisterSet</code>.
       */
      public static class Field {
          public int value;
  
          public void write(int nval, int wmask) {
              value = value & ~wmask | nval;
              update();
          }
  
          public void write(int nval) {
              value = nval;
              update();
          }
  
          public void set(int nval) {
              throw Util.unimplemented();
          }
  
          public void update() {
              // do nothing.
          }
      }
  
      static class FieldWriter {
          int value;
          int writtenMask;
          Field fobject;
  
          void commit() {
              fobject.write(value, writtenMask);
              value = 0;
              writtenMask = 0;
          }
      }
  
      abstract static class SubRegWriter {
          final int ior_low_bit;
          final int mask;
          final int length;
  
          SubRegWriter(RegisterLayout.SubField sf) {
              ior_low_bit = sf.ior_low_bit;
              mask = sf.mask;
              length = sf.length;
          }
  
          abstract void write(byte val);
      }
  
      static class SubFieldWriter extends SubRegWriter {
          final FieldWriter fieldWriter;
          final RegisterLayout.SubField subField;
  
          SubFieldWriter(RegisterLayout.SubField sf, FieldWriter fw) {
              super(sf);
              subField = sf;
              fieldWriter = fw;
          }
  
          void write(byte val) {
              int wval = (val >> ior_low_bit) & mask;
              fieldWriter.value |= wval << subField.field_low_bit;
              fieldWriter.writtenMask |= mask << subField.field_low_bit;
              if ( subField.commit ) fieldWriter.commit();
          }
      }
  
      static class TotalFieldWriter extends SubRegWriter {
          final FieldWriter fieldWriter;
  
          TotalFieldWriter(RegisterLayout.SubField sf, FieldWriter fw) {
              super(sf);
              fieldWriter = fw;
          }
  
          void write(byte val) {
              int value = (val >> ior_low_bit) & mask;
              fieldWriter.fobject.write(value);
          }
      }
  
      static class ReservedWriter extends SubRegWriter {
  
          ReservedWriter(RegisterLayout.SubField sf) {
              super(sf);
          }
  
          void write(byte val) {
              // TODO: check that all writes are zeroes
          }
      }
  
      static class UnusedWriter extends SubRegWriter {
  
          UnusedWriter(RegisterLayout.SubField sf) {
              super(sf);
          }
  
          void write(byte val) {
              // do nothing.
          }
      }
  
      /**
       * The <code>MultiFieldRegister</code> class implements an IO register that is
       * directly read and written by the program. This IO register implements writes
       * that alter multiple fields and subfields in the register set.
       */
      public class MultiFieldRegister implements ActiveRegister {
  
          byte value;
          final SubRegWriter[] subFields;
  
          MultiFieldRegister(SubRegWriter[] srw) {
              subFields = srw;
          }
  
          public byte read() {
              return value;
          }
  
          public void write(byte nval) {
              this.value = nval;
              for ( int cntr = 0; cntr < subFields.length; cntr++ ) {
                  SubRegWriter sf = subFields[cntr];
                  sf.write(nval);
              }
          }
  
      }
  
      protected final HashMap<String, FieldWriter> fields;
      protected final ActiveRegister[] registers;
      protected final RegisterLayout layout;
  
      /**
       * The constructor for the <code>RegisterSet</code> class creates a new register set with the specified register
       * layout and size.
       * @param rl the layout of all the registers in the set
       */
      public RegisterSet(RegisterLayout rl) {
          fields = new HashMap<String, FieldWriter>();
          registers = new ActiveRegister[rl.ioreg_size];
          layout = rl;
  
          // create the field representations
          for (RegisterLayout.Field f : rl.fields.values()) {
              FieldWriter fw = new FieldWriter();
              fw.fobject = new Field();
              fields.put(f.name, fw);
          }
  
          // create the active registers
          for ( int ior = 0; ior < rl.ioreg_size; ior++ ) {
              RegisterLayout.RegisterInfo ri = rl.info[ior];
              if ( ri == null || ri.subfields == null ) {
                  // no subfields; no special register is necessary
                  registers[ior] = new RWRegister();
              } else {
                  registers[ior] = createMultiFieldRegister(ri);
              }
          }
      }
  
      private MultiFieldRegister createMultiFieldRegister(RegisterLayout.RegisterInfo ri) {
          // there are subfields in this register; create a special ActiveRegister
          SubRegWriter[] srw = new SubRegWriter[ri.subfields.length];
          for ( int cntr = 0; cntr < srw.length; cntr++ ) {
              createSubRegWriter(ri, cntr, srw);
          }
          return new MultiFieldRegister(srw);
      }
  
      private void createSubRegWriter(RegisterLayout.RegisterInfo ri, int cntr, SubRegWriter[] srw) {
          RegisterLayout.SubField sf = ri.subfields[cntr];
          RegisterLayout.Field field = sf.field;
  
          if ( sf.field == RegisterLayout.RESERVED ) {
              srw[cntr] = new ReservedWriter(sf);
          } else if ( sf.field == RegisterLayout.UNUSED ) {
              srw[cntr] = new UnusedWriter(sf);
          } else if ( sf.field.subfields.length == 1) {
              // if the field has only one subfield, write the whole field value at once
              srw[cntr] = new TotalFieldWriter(sf, (FieldWriter)fields.get(field.name));
          } else {
              // otherwise, this subfield is for a field that is fragmented
              srw[cntr] = new SubFieldWriter(sf, (FieldWriter)fields.get(field.name));
          }
      }
  
      /**
       * The <code>getSize()</code> method returns the total number of registers in this register set.
       * @return the number of IO registers in this set
       */
      public int getSize() {
          return registers.length;
      }
  
      /**
       * The <code>getRegisterLayout()</code> method gets a reference to the register layout object for this
       * register set. The register layout describes where each IO register is and what fields it contains.
       * @return a reference to the register layout for this register set
       */
      public RegisterLayout getRegisterLayout() {
          return layout;
      }
  
      /**
       * The <code>share()</code> method is NOT meant for general use. It is used ONLY by the interpreter to
       * share the underlying array representation that maps from register address to an actual register
       * object.
       * @return a reference to the array containing references to the actual register objects
       */
      public ActiveRegister[] share() {
          return registers;
      }
  
      /**
       * The <code>getField()</code> gets an object that represents an entire field which
       * may be stored across multiple registers in multiple bit fields. This object allows
       * access to the field's value without consideration for its underlying representation
       * in the IO register(s).
       * @param fname the name of the fieldWriter to get the fieldWriter representation for
       * @return a reference to the <code>FieldWriter</code> object that represents the field
       */
      public Field getField(String fname) {
          FieldWriter fwriter = getFieldWriter(fname);
          return fwriter.fobject;
      }
  
      private FieldWriter getFieldWriter(String fname) {
          FieldWriter fwriter = ((FieldWriter)fields.get(fname));
          if ( fwriter == null ) {
              throw Util.failure("Field not found in RegisterSet: "+ StringUtil.quote(fname));
          }
          return fwriter;
      }
  
      /**
       * The <code>installField()</code> method allows device implementations to substitute a new field
       * implementation for the named field. The field implementation can then override the appropriate
       * methods of the <code>RegisterSet.Field</code> class to be notified upon writes.
       * @param fname the name of the field
       * @param fo the field object to install for this field
       * @return the new field installed
       */
      public Field installField(String fname, Field fo) {
          FieldWriter fwriter = getFieldWriter(fname);
          fwriter.fobject = fo;
          return fo;
      }
  }
  