OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / sid / include / sidbusutil.h
diff --git a/sid/include/sidbusutil.h b/sid/include/sidbusutil.h
new file mode 100644 (file)
index 0000000..b6e8f0d
--- /dev/null
@@ -0,0 +1,1463 @@
+// sidbusutil.h -*- C++ -*- Different types and sizes of buses.
+
+// Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2007 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef SIDBUSUTIL_H
+#define SIDBUSUTIL_H
+
+#include <sidconfig.h>
+#include <sidtypes.h>
+#include <sidcomputil.h>
+#include <sidschedutil.h>
+#include <sidpinutil.h>
+#include <sidblockingutil.h>
+
+#include <string>
+#include <map>
+#include <vector>
+#include <iostream>
+
+namespace sidutil
+{
+  // The word_bus converts incoming bus access calls to a particular
+  // preferred size & type.  The bus object is addressable as if it
+  // was memory, with no alignment/size restrictions.
+
+  template <typename DataType>
+  class word_bus: public sid::bus
+  {
+  protected:
+    word_bus() {}
+    ~word_bus() {}
+
+    virtual sid::bus::status word_write(sid::host_int_4 addr,
+                                       DataType mask,
+                                       DataType data) = 0;
+
+    virtual sid::bus::status word_read(sid::host_int_4 addr,
+                                      DataType mask,
+                                      DataType& data) = 0;
+
+    virtual void post_access_hook() { }
+
+    // Method writes data at address. AccDataType can be different than
+    // DataType. Method itself takes care to represent data to component
+    // in its required data size.
+    template <typename AccDataType>
+    bus::status
+    writeAny(sid::host_int_4 address, AccDataType data)
+      {
+       unsigned busWidth = sizeof(typename DataType::value_type);
+       unsigned accWidth = sizeof(typename AccDataType::value_type);
+
+       // Make local modifiable copy.
+       sid::host_int_4 a = address;
+
+       unsigned bytesWritten = 0;
+       sid::host_int_2 max_latency = 0;
+       DataType d = 0;
+        DataType mask = 0;
+       sid::bus::status s;
+       while(bytesWritten < accWidth)
+         {
+           sid::host_int_1 byte = data.read_byte(bytesWritten);
+           d.write_byte((bytesWritten + a) % busWidth, byte);
+           mask.write_byte((bytesWritten + a) % busWidth, 0xff);
+
+           if(((bytesWritten + a) % busWidth == (busWidth - 1)) || // last byte in target
+              (bytesWritten == (accWidth - 1))) // last byte in source
+             {
+
+               s = this->word_write(sid::host_int_4(a / busWidth), mask, d);
+               if (s != sid::bus::ok)
+                 {
+                   this->post_access_hook();
+                   return s;
+                 }
+               if (s.latency > max_latency)
+                 max_latency = s.latency;
+
+               a = a + busWidth; // advance address
+               // Clear data.
+               d = 0;
+               // Clear mask.
+               mask = 0;
+             }
+           bytesWritten ++;
+         }
+
+       this->post_access_hook();
+       s.latency = max_latency;
+       return s;
+      }
+    
+
+    // This method is used to read data from address. Like the above
+    // case AccDataType can be different than DataType. Method returns
+    // ok if sucessful.
+    template <typename AccDataType>
+    sid::bus::status
+    readAny(sid::host_int_4 address, AccDataType& data)
+      {
+       unsigned busWidth = sizeof(typename DataType::value_type);
+       unsigned accWidth = sizeof(typename AccDataType::value_type);
+       
+       // Make local modifiable copy.
+       sid::host_int_4 a = address;
+       
+       unsigned bytesRead = 0;
+       unsigned bytesAddressed = 0;
+       sid::host_int_2 max_latency = 0;
+        DataType mask = 0;
+       sid::bus::status s;
+       while(bytesAddressed < accWidth)
+         {
+           mask.write_byte((bytesAddressed + a) % busWidth, 0xff);
+
+           if(((bytesAddressed + a) % busWidth == (busWidth - 1)) || // last byte in target
+              (bytesAddressed == (accWidth - 1))) // last byte in source
+             {
+               DataType d = 0;
+               s = this->word_read(sid::host_int_4(a / busWidth), mask, d);
+               if (s != sid::bus::ok)
+                 {
+                   this->post_access_hook();
+                   return s;
+                 }
+               if (s.latency > max_latency)
+                 max_latency = s.latency;
+
+               // Copy over newly read bytes
+               while (bytesRead <= bytesAddressed)
+                 {
+                   assert (mask.read_byte((bytesRead + a) % busWidth) == 0xff);
+                   sid::host_int_1 byte = d.read_byte((bytesRead + a) % busWidth);
+                   data.write_byte(bytesRead, byte);
+                   bytesRead ++;
+                 }
+
+               a = a + busWidth; // advance address
+               // Clear mask.
+               mask = 0;
+             }
+           
+           bytesAddressed ++;
+         }
+       assert (bytesAddressed == bytesRead);
+
+       this->post_access_hook();
+       s.latency = max_latency;
+       return s;
+      }
+    
+    
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define SID_GB_WRITE(type1,type2) \
+      sid::bus::status write(type1 addr, type2 data) throw () \
+         { return writeAny(addr, data); }
+    
+#define SID_GB_READ(type1,type2) \
+      sid::bus::status read(type1 addr, type2& data) throw () \
+         { return readAny(addr, data); }
+    
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_1)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_1)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_2)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_2)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_4)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_4)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_8)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_8)
+
+    SID_GB_READ(sid::host_int_4, sid::little_int_1)
+    SID_GB_READ(sid::host_int_4, sid::big_int_1)
+    SID_GB_READ(sid::host_int_4, sid::little_int_2)
+    SID_GB_READ(sid::host_int_4, sid::big_int_2)
+    SID_GB_READ(sid::host_int_4, sid::little_int_4)
+    SID_GB_READ(sid::host_int_4, sid::big_int_4)
+    SID_GB_READ(sid::host_int_4, sid::little_int_8)
+    SID_GB_READ(sid::host_int_4, sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+  };
+
+
+
+  template <class Master, class DataType>
+  class callback_word_bus: public word_bus<DataType>
+  {
+  public:
+    typedef sid::bus::status (Master::*ReadFunction) (sid::host_int_4, DataType, DataType&);
+    typedef sid::bus::status (Master::*WriteFunction) (sid::host_int_4, DataType, DataType);
+
+  private:
+    Master* receiver;
+    ReadFunction read_callback;
+    WriteFunction write_callback;
+
+    sid::bus::status word_write(sid::host_int_4 addr,
+                               DataType mask,
+                               DataType data)
+      {
+       return (receiver->*write_callback) (addr, mask, data);
+      }
+
+    sid::bus::status word_read(sid::host_int_4 addr,
+                              DataType mask,
+                              DataType& data)
+      {
+       return (receiver->*read_callback) (addr, mask, data);
+      }
+
+  public:
+    callback_word_bus (Master* m, ReadFunction rf, WriteFunction wf):
+      receiver (m), read_callback (rf), write_callback (wf) {}
+  };
+
+
+
+  // This sort of bus passes accesses through to another, specified
+  // by a meta-pointer.
+  class passthrough_bus: public sid::bus
+  {
+  public:
+    passthrough_bus(sid::bus** t): target(t) 
+      {
+       assert (target != 0);
+      }
+    ~passthrough_bus() {}
+    
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define SID_GB_WRITE(dtype) \
+      sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
+         { if (LIKELY(*target)) return (*target)->write(addr, data); else return sid::bus::unpermitted; }
+
+#define SID_GB_READ(dtype) \
+      sid::bus::status read(sid::host_int_4 addr, dtype& data) throw ()\
+         { if (LIKELY(*target)) return (*target)->read(addr, data); else return sid::bus::unpermitted; }
+
+    SID_GB_WRITE(sid::little_int_1)
+    SID_GB_WRITE(sid::big_int_1)
+    SID_GB_WRITE(sid::little_int_2)
+    SID_GB_WRITE(sid::big_int_2)
+    SID_GB_WRITE(sid::little_int_4)
+    SID_GB_WRITE(sid::big_int_4)
+    SID_GB_WRITE(sid::little_int_8)
+    SID_GB_WRITE(sid::big_int_8)
+
+    SID_GB_READ(sid::little_int_1)
+    SID_GB_READ(sid::big_int_1)
+    SID_GB_READ(sid::little_int_2)
+    SID_GB_READ(sid::big_int_2)
+    SID_GB_READ(sid::little_int_4)
+    SID_GB_READ(sid::big_int_4)
+    SID_GB_READ(sid::little_int_8)
+    SID_GB_READ(sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+
+  protected:
+    sid::bus** target;
+  };
+
+  // This sort of bus passes accesses through to one of two buses which
+  // are specified by meta-pointers.  Access can be switched dynamically.
+  class mux_passthrough_bus: public sid::bus
+  {
+  public:
+    mux_passthrough_bus(sid::bus** t1, sid::bus** t2)
+      {
+       assert (t1 != 0);
+        assert (t2 != 0);
+       this->dummy_target = 0;
+        this->t[0] = t1;
+       this->index = 0;
+       this->target = t1;
+        this->t[1] = t2;
+      }
+    ~mux_passthrough_bus() {}
+    void switch_bus()
+    {
+      // Switch to the next bus if the current one is valid (0 or 1)
+      switch (this->index) 
+       {
+       case 0:
+       case 1:
+         this->index = 1 - this->index;
+         this->target = this->t[this->index];
+         break;
+
+       default:
+         ;
+         // do nothing
+       }
+    }
+    void select_bus (int i)
+    {
+      // Set index to 2 (error) unless i is 0 or 1
+      switch (i)
+       {
+       case 0:
+       case 1:
+         this->index = i;
+         this->target = this->t[i];
+         break;
+
+       default:
+         this->index = 2;
+         this->target = & this->dummy_target;
+       }
+    }
+    
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define SID_GB_WRITE(dtype) \
+      sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
+         { if (LIKELY(*target)) return (*target)->write(addr, data); else return sid::bus::unmapped; }
+
+#define SID_GB_READ(dtype) \
+      sid::bus::status read(sid::host_int_4 addr, dtype& data) throw ()\
+         { if (LIKELY(*target)) return (*target)->read(addr, data); else return sid::bus::unmapped; }
+
+    SID_GB_WRITE(sid::little_int_1)
+    SID_GB_WRITE(sid::big_int_1)
+    SID_GB_WRITE(sid::little_int_2)
+    SID_GB_WRITE(sid::big_int_2)
+    SID_GB_WRITE(sid::little_int_4)
+    SID_GB_WRITE(sid::big_int_4)
+    SID_GB_WRITE(sid::little_int_8)
+    SID_GB_WRITE(sid::big_int_8)
+
+    SID_GB_READ(sid::little_int_1)
+    SID_GB_READ(sid::big_int_1)
+    SID_GB_READ(sid::little_int_2)
+    SID_GB_READ(sid::big_int_2)
+    SID_GB_READ(sid::little_int_4)
+    SID_GB_READ(sid::big_int_4)
+    SID_GB_READ(sid::little_int_8)
+    SID_GB_READ(sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+
+  private:
+    int index;
+    sid::bus* dummy_target;
+    sid::bus** target;
+    sid::bus** t[2];
+  };
+
+  // The passthrough_word_bus maps memory and either directly passes through to the underlying
+  // bus or else converts the incoming bus access call to a particular
+  // preferred size & type.  The bus object is addressable as if it
+  // was memory, with no alignment/size restrictions.
+
+  template <class DataType>
+  class passthrough_word_bus: public word_bus<DataType>
+  {
+
+  protected:
+
+    sid::bus **target;
+
+    passthrough_word_bus(sid::bus **t): target(t) 
+      { 
+       assert (target != 0);
+      }
+    ~passthrough_word_bus() {}
+
+    virtual sid::bus::status word_write(sid::host_int_4 addr,
+                                       DataType mask,
+                                       DataType data) = 0;
+
+    virtual sid::bus::status word_read(sid::host_int_4 addr,
+                                      DataType mask,
+                                      DataType& data) = 0;
+
+    virtual int do_direct_passthrough (sid::host_int_4& addr) { return 0; } 
+
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define SID_GB_WRITE(type1,type2) \
+      sid::bus::status write(type1 addr, type2 data) throw () \
+         { if (do_direct_passthrough (addr)) \
+               return (*target)->write(addr, data); \
+               return word_bus<DataType>::write(addr, data); }
+    
+#define SID_GB_READ(type1,type2) \
+      sid::bus::status read(type1 addr, type2& data) throw () \
+         { if (do_direct_passthrough (addr)) \
+               return (*target)->read(addr, data); \
+            return word_bus<DataType>::read(addr, data); }
+    
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_1)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_1)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_2)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_2)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_4)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_4)
+    SID_GB_WRITE(sid::host_int_4, sid::little_int_8)
+    SID_GB_WRITE(sid::host_int_4, sid::big_int_8)
+
+    SID_GB_READ(sid::host_int_4, sid::little_int_1)
+    SID_GB_READ(sid::host_int_4, sid::big_int_1)
+    SID_GB_READ(sid::host_int_4, sid::little_int_2)
+    SID_GB_READ(sid::host_int_4, sid::big_int_2)
+    SID_GB_READ(sid::host_int_4, sid::little_int_4)
+    SID_GB_READ(sid::host_int_4, sid::big_int_4)
+    SID_GB_READ(sid::host_int_4, sid::little_int_8)
+    SID_GB_READ(sid::host_int_4, sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+  };
+
+  // The harvard bus allows a single virtual memory model to be broken
+  // down into data and insn memory via section numbers (top byte of address).
+  // The sections for data and insn are given in the form of first section number
+  // and last section number.  The bus object is addressable as if it was memory, 
+  // with no alignment/size restrictions.
+
+  class harvard_bus: public sid::bus
+  {
+  protected:
+    sid::bus   **insn_bus;
+    sid::bus   **data_bus;
+    sid::host_int_4 first_data_section;
+    sid::host_int_4 last_data_section;
+    sid::host_int_4 first_insn_section;
+    sid::host_int_4 last_insn_section;
+
+  public:
+    harvard_bus (sid::bus **d_bus, sid::bus **i_bus, 
+                sid::host_int_4 first_data, sid::host_int_4 last_data,
+                 sid::host_int_4 first_insn, sid::host_int_4 last_insn):
+      insn_bus (i_bus),
+      data_bus (d_bus),
+      first_data_section (first_data),
+      last_data_section (last_data),
+      first_insn_section (first_insn),
+      last_insn_section (last_insn)
+      { 
+       assert (insn_bus != 0);
+       assert (data_bus != 0);
+      }
+    ~harvard_bus() {}
+
+    sid::bus *map_addr_to_bus (sid::host_int_4 *addr)
+      {
+       sid::host_int_4 section = *addr >> 24;
+
+       if (section >= first_data_section && section <= last_data_section)
+          {
+            *addr -= first_data_section << 24;
+           return *data_bus;
+          }
+       if (section >= first_insn_section && section <= last_insn_section)
+          {
+            *addr -= first_insn_section << 24;
+           return *insn_bus;
+          }
+       return NULL;
+      }
+
+
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define SID_GB_WRITE(type1) \
+      sid::bus::status write(sid::host_int_4 addr, type1 data) throw () \
+         { sid::bus *bus = this->map_addr_to_bus (&addr); \
+            if (UNLIKELY(bus == NULL)) \
+              return sid::bus::unmapped; \
+            else \
+              return bus->write(addr, data); }
+    
+#define SID_GB_READ(type1) \
+      sid::bus::status read(sid::host_int_4 addr, type1& data) throw () \
+         { sid::bus *bus = this->map_addr_to_bus (&addr); \
+            if (UNLIKELY(bus == NULL)) \
+              return sid::bus::unmapped; \
+            else \
+              return bus->read(addr, data); }
+    
+    SID_GB_WRITE(sid::little_int_1)
+    SID_GB_WRITE(sid::big_int_1)
+    SID_GB_WRITE(sid::little_int_2)
+    SID_GB_WRITE(sid::big_int_2)
+    SID_GB_WRITE(sid::little_int_4)
+    SID_GB_WRITE(sid::big_int_4)
+    SID_GB_WRITE(sid::little_int_8)
+    SID_GB_WRITE(sid::big_int_8)
+
+    SID_GB_READ(sid::little_int_1)
+    SID_GB_READ(sid::big_int_1)
+    SID_GB_READ(sid::little_int_2)
+    SID_GB_READ(sid::big_int_2)
+    SID_GB_READ(sid::little_int_4)
+    SID_GB_READ(sid::big_int_4)
+    SID_GB_READ(sid::little_int_8)
+    SID_GB_READ(sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+  };
+
+
+
+
+  // For byte-wide peripherals - similar to word_bus<host_int_1>.
+  // It accepts only byte-wide accesses.
+  class byte_bus : public sid::bus
+  {
+  protected:
+    byte_bus() {}
+    ~byte_bus() {}
+    
+    virtual sid::bus::status 
+    write_data(sid::host_int_4 addr, sid::host_int_1 data) throw () = 0;
+    
+    virtual sid::bus::status 
+    read_data(sid::host_int_4 addr, sid::host_int_1& data) throw () = 0;
+    
+    // Byte accesses to a byte-wide component are easy.
+    sid::bus::status 
+    write(sid::host_int_4 addr, sid::little_int_1 data) throw () 
+      {
+       return write_data(addr, data.integer_value() );
+      }
+
+    sid::bus::status 
+    write(sid::host_int_4 addr, sid::big_int_1 data) throw () 
+      {
+       return write_data( addr, data.integer_value() );
+      }
+    
+    sid::bus::status 
+    read( sid::host_int_4 addr, sid::little_int_1& data ) throw ()
+      {
+       sid::host_int_1 d;
+       sid::bus::status s = read_data( addr, d );
+       data = d;
+       return s;
+      }
+        
+    sid::bus::status 
+    read( sid::host_int_4 addr, sid::big_int_1& data ) throw ()
+      {
+       sid::host_int_1 d;
+       sid::bus::status s = read_data( addr, d );
+       data = d;
+       return s;
+      }
+
+    // Some macros to make manufacturing of the cartesian-product
+    // calls simpler.
+#define BYTE_BUS_WRITE_A4(dtype) \
+    sid::bus::status write(sid::host_int_4 addr, dtype data ) throw () {\
+          return sid::bus::unmapped; }
+
+#define BYTE_BUS_READ_A4(dtype)\
+    sid::bus::status read(sid::host_int_4 addr, dtype& data ) throw () { \
+          return sid::bus::unmapped; }
+
+    BYTE_BUS_WRITE_A4( sid::little_int_2 )
+    BYTE_BUS_WRITE_A4( sid::big_int_2 )
+    BYTE_BUS_WRITE_A4( sid::little_int_4 )
+    BYTE_BUS_WRITE_A4( sid::big_int_4 )
+    BYTE_BUS_WRITE_A4( sid::little_int_8 )
+    BYTE_BUS_WRITE_A4( sid::big_int_8 )
+    BYTE_BUS_READ_A4 ( sid::little_int_2 )
+    BYTE_BUS_READ_A4 ( sid::big_int_2 )
+    BYTE_BUS_READ_A4 ( sid::little_int_4 )
+    BYTE_BUS_READ_A4 ( sid::big_int_4 )
+    BYTE_BUS_READ_A4 ( sid::little_int_8 )
+    BYTE_BUS_READ_A4 ( sid::big_int_8 )
+
+#undef BYTE_BUS_WRITE_A4
+#undef BYTE_BUS_READ_A4
+  };
+
+
+  // Callback_byte_bus class allows user to have different read/write
+  // methods for each object of this class. User can have one read
+  // and write method on class level for all objects of class
+  // call_back_byte_bus or user can have seperate read and write
+  // methods in class Reciever for each object of class
+  // callback_byte_bus.
+  template <class Receiver>
+  class callback_byte_bus : public byte_bus {
+  public:
+    callback_byte_bus( Receiver* h,
+                      sid::bus::status (Receiver::*r) ( 
+                        sid::host_int_4, sid::host_int_1& ),
+                      sid::bus::status (Receiver::*w) ( 
+                        sid::host_int_4, sid::host_int_1 )
+                     ) : receiver(h), reader(r), writer(w) {}
+
+    ~callback_byte_bus() {}
+
+  protected:
+    Receiver* receiver;
+    sid::bus::status (Receiver::*reader) ( sid::host_int_4 addr, 
+                                          sid::host_int_1& data );
+    sid::bus::status (Receiver::*writer) ( sid::host_int_4 addr, 
+                                          sid::host_int_1 data );
+
+    virtual sid::bus::status 
+    read_data( sid::host_int_4 addr, sid::host_int_1& data ) throw() {
+      return (receiver->*reader) ( addr, data );
+    }
+
+    virtual sid::bus::status 
+    write_data( sid::host_int_4 addr, sid::host_int_1 data ) throw() {
+      return (receiver->*writer) ( addr, data );
+    }
+    
+  };
+
+
+  template <typename DataType>
+  class control_register;
+
+  // This class is used to store different types of component
+  // registers. Types of register storage supported by this class are
+  // read-only, write-only, and read/write only registers.
+  template <typename DataType>
+  class control_register_bank
+  {
+  public:
+    void add_writeonly_register(control_register<DataType>* reg,
+                               sid::host_int_4 address);
+    void add_readonly_register(control_register<DataType>* reg,
+                              sid::host_int_4 address);
+    void add_readwrite_register(control_register<DataType>* reg,
+                               sid::host_int_4 address);
+    ~control_register_bank () { }
+    
+  protected:
+    typedef std::vector<control_register<DataType>*> reg_vector;
+    typedef std::map<sid::host_int_4, reg_vector> reg_map;
+
+    // read- and write- mappings for control registers
+    reg_map read_map, write_map;
+  };
+
+  template <typename DataType>
+  void 
+  control_register_bank<DataType>::add_writeonly_register(control_register<DataType>* reg,
+                                                         sid::host_int_4 address)
+  {
+    write_map[address].push_back(reg);
+  }
+
+
+  template <typename DataType>
+  void 
+  control_register_bank<DataType>::add_readonly_register(control_register<DataType>* reg, 
+                                                         sid::host_int_4 address)
+  {
+    read_map[address].push_back(reg);
+  }
+
+
+  template <typename DataType>
+  void 
+  control_register_bank<DataType>::add_readwrite_register(control_register<DataType>* reg, 
+                                                         sid::host_int_4 address)
+  {
+    this->add_writeonly_register(reg, address);
+    this->add_readonly_register(reg, address);
+  }
+
+
+  // This is a general type of control register whose value is get/set
+  // by a virtual function.
+  template <typename DataType>
+  class control_register
+  {
+  public:
+    virtual void set (DataType set_value, DataType set_mask) = 0;
+    virtual DataType get () = 0;
+    DataType get_mask() const { return this->field_mask; }
+    
+    control_register(control_register_bank<DataType>* bank,
+                    sid::host_int_4 offset,
+                    DataType m,
+                    bool read,
+                    bool write): field_mask(m)
+      {
+       if (read)
+         bank->add_readonly_register(this, offset);
+       if (write)
+         bank->add_writeonly_register(this, offset);
+      }
+  private:
+    DataType field_mask;
+  };
+
+  // streaming ops for following class
+  template <typename DataType> class value_control_register;
+  
+  template <typename DataType>
+  std::ostream& 
+  operator << (std::ostream& o, const value_control_register<DataType>& it)
+  {  
+    sid::host_int_8 v = (sid::host_int_8) it.field_value;
+    o << v;
+    return o;
+  }
+
+
+  template <typename DataType>
+  std::istream& 
+  operator >> (std::istream& i, value_control_register<DataType>& it)
+  {
+    sid::host_int_8 v;
+    i >> v;
+    it.field_value = v;
+    return i;
+  }
+
+
+  // This is a type of control register whose value is stored directly.  It
+  // provides an assignment and conversion operator for use like a variable.
+  template <typename DataType>
+  class value_control_register: public control_register<DataType>
+  {
+  protected:
+    typedef typename DataType::value_type ValueType;
+
+  public:
+    void set (DataType set_value, DataType set_mask)
+      {
+       this->field_value = (this->field_value & ~set_mask) | (set_value & set_mask);
+      }
+
+
+    DataType get ()
+      {
+       return this->field_value; 
+      }
+
+    DataType get () const
+      {
+       return this->field_value; 
+      }
+
+    value_control_register(control_register_bank<DataType>* b,
+                          sid::host_int_4 o,
+                          DataType m,
+                          bool r,
+                          bool w,
+                          DataType v): 
+      control_register<DataType>(b,o,m,r,w),
+      field_value(v) {}
+
+    value_control_register(control_register_bank<DataType>* b,
+                          sid::host_int_4 o,
+                          DataType m,
+                          bool r,
+                          bool w):
+      control_register<DataType>(b,o,m,r,w),
+      field_value(0) {}
+
+    // Some convenience operators for accessing register fields
+    void operator = (const DataType& v)
+      {
+       DataType shifted_v = v << this->shift_amount();
+       this->set (shifted_v, this->get_mask()); 
+      }
+
+
+    void operator = (const ValueType& v)
+      {
+       ValueType shifted_v = v << this->shift_amount();
+       this->set (shifted_v, this->get_mask()); 
+      }
+
+    // conversion operators
+    operator DataType () const
+      {
+       DataType shifted_v = this->get() >> this->shift_amount(); 
+       return shifted_v;
+      }
+
+    operator ValueType () const
+      {
+       ValueType shifted_v = this->get() >> this->shift_amount(); 
+       return shifted_v;
+      }
+
+    friend std::ostream& operator << <> (std::ostream& o, 
+                                        const value_control_register<DataType>& it);
+    friend std::istream& operator >> <> (std::istream& i, 
+                                        value_control_register<DataType>& it);
+    
+  protected:
+    // return index of mask LSB
+    unsigned shift_amount() const
+    {
+      DataType mask = this->get_mask ();
+      for (unsigned i=0; i<sizeof(DataType)*8; i++)
+       if (mask & (1 << i))
+         return i;
+      assert(0);
+    }
+    
+  private:
+    DataType field_value;
+  };
+
+  // This is a read-only value control register.  Its underlying value
+  // may be changed programmatically, but as far as a bus accessor is
+  // concerned, writing to the register has no effect.
+  template <typename DataType>
+  class ro_value_control_register: public value_control_register<DataType>
+  {
+  public:
+    typedef typename value_control_register<DataType>::ValueType ValueType;
+
+    ro_value_control_register(control_register_bank<DataType>* b,
+                             sid::host_int_4 o,
+                             DataType m,
+                             DataType v):
+      value_control_register<DataType>(b,o,m,true,true,v)
+    {}
+    
+    ro_value_control_register(control_register_bank<DataType>* b,
+                             sid::host_int_4 o,
+                             DataType m):
+      value_control_register<DataType>(b,o,m,true,true,0)
+    {}
+
+    // Some convenience operators for accessing register fields
+    void operator = (const DataType& v)
+      {
+       ValueType shifted_v = v << this->shift_amount();
+       value_control_register<DataType>::set (shifted_v, this->get_mask()); 
+      }
+
+  protected:
+    void set (DataType set_value, DataType set_mask)
+    {
+      // do nothing
+    }
+  };
+
+  // This is a type of control register whose value never changes.
+  // One may also use it for reserved fields.
+  // Read only register.
+  template <typename DataType>
+  class fixed_control_register: public value_control_register<DataType>
+  {
+  public:
+    fixed_control_register(control_register_bank<DataType>* b,
+                          sid::host_int_4 o,
+                          DataType m):
+      value_control_register<DataType>(b,o,m,true,true,0)
+    {}
+    
+    fixed_control_register(control_register_bank<DataType>* b,
+                          sid::host_int_4 o,
+                          DataType m,
+                          bool r,
+                          bool w,
+                          DataType v): 
+      value_control_register<DataType>(b,o,m,r,w,v)
+    {}
+
+  protected:
+    void set (DataType set_value, DataType set_mask)
+      {
+       // do nothing
+       // XXX: check for match with field_value?
+      }
+  };
+
+
+  // This is a type of control register whose value is set/get via
+  // a pair of class member functions.
+  template <typename DataType, class Class>
+  class callback_control_register: public control_register<DataType>
+  {
+  public:
+    callback_control_register(control_register_bank<DataType>* b,
+                             sid::host_int_4 o,
+                             DataType m,
+                             bool r,
+                             bool w,
+                             Class* rec, 
+                             void (Class::*s)(DataType, DataType), 
+                             DataType (Class::*g)()): 
+      control_register<DataType>(b,o,m,r,w),
+      receiver(rec),
+      set_callback(s),
+      get_callback(g)
+      {}
+
+    // Read only register
+    callback_control_register(control_register_bank<DataType>* b,
+                             sid::host_int_4 o,
+                             DataType m,
+                             bool r,
+                             bool w,
+                             Class* rec, 
+                             DataType (Class::*g)()): 
+      control_register<DataType>(b,o,m,r,w),
+      receiver(rec),
+      set_callback(0),
+      get_callback(g)
+      {}
+
+    // Write only register
+    callback_control_register(control_register_bank<DataType>* b,
+                             sid::host_int_4 o,
+                             DataType m,
+                             bool r,
+                             bool w,
+                             Class* rec, 
+                             void (Class::*s)(DataType, DataType)):
+      control_register<DataType>(b,o,m,r,w),
+      receiver(rec),
+      set_callback(s),
+      get_callback(0)
+      {}
+
+  private:
+    Class* receiver;
+    void (Class::*set_callback) (DataType, DataType);
+    DataType (Class::*get_callback) ();
+
+    void set (DataType set_value, DataType set_mask)
+      {
+       assert(this->set_callback);
+       (receiver->*set_callback)(set_value, set_mask); 
+      }
+
+    DataType get ()
+      {
+       assert(this->get_callback);
+       return (receiver->*get_callback)(); 
+      }
+  };
+  
+  // This is a bus that acts like a look-up table for control
+  // registers.  Each register may take up a bitfield of a word.
+  // Read/Write accesses are dispatched to all the registers whose
+  // bitfields overlap the accessed word.
+
+  template <typename DataType>
+  class control_register_bus: public control_register_bank<DataType>,
+                             public word_bus <DataType>
+  {
+  protected:
+    sid::bus::status word_write(sid::host_int_4 addr,
+                               DataType mask,
+                               DataType data)
+      {
+       typename control_register_bus<DataType>::reg_map::iterator i = 
+                this->write_map.find(addr);
+       if (i == this->write_map.end())
+         return sid::bus::unmapped; // XXX: or unpermitted?
+       
+       DataType unmatched_mask = mask;
+
+       // scan through all registers at this address
+       for(typename control_register_bus<DataType>::reg_vector::iterator it =
+                      i->second.begin();
+           it != i->second.end();
+           it++)
+         {
+           control_register<DataType>* reg = (*it);
+           DataType reg_mask = reg->get_mask();
+           if (reg_mask & mask) // overlap?
+             {
+               // Assert that no other register took these bits already.
+               assert ((unmatched_mask & reg_mask) == (mask & reg_mask)); 
+               // Take the bits.
+               unmatched_mask = unmatched_mask & ~reg_mask;
+               // Hand over the masked data value.  Use both the
+               // incoming write mask and the control register mask
+               reg->set (data & mask & reg_mask, reg_mask & mask);
+             }
+         }
+
+       // Assert that all bits in this word have been taken by control registers.
+       assert (unmatched_mask == 0); 
+       return sid::bus::ok;
+      }
+
+
+    sid::bus::status word_read(sid::host_int_4 addr,
+                              DataType mask,
+                              DataType& data_out)
+      {
+       typename control_register_bus<DataType>::reg_map::iterator i =
+                this->read_map.find(addr);
+       if (i == this->read_map.end())
+         return sid::bus::unmapped; // XXX: or unpermitted?
+
+       DataType data = 0;
+       DataType unmatched_mask = mask;
+
+       // scan through all registers at this address
+       for(typename control_register_bus<DataType>::reg_vector::iterator it =
+                       i->second.begin();
+           it != i->second.end();
+           it++)
+         {
+           control_register<DataType>* reg = (*it);
+           DataType reg_mask = reg->get_mask();
+           if (reg_mask & mask) // overlap?
+             {
+               // Assert that no other register took these bits already.
+               assert ((unmatched_mask & reg_mask) == (mask & reg_mask)); 
+               // Take the bits.
+               unmatched_mask = unmatched_mask & ~reg_mask;
+               // Hand over the masked data value.  Use both the
+               // incoming read mask and the control register mask
+               DataType d = reg->get ();
+               data = data | (d & reg_mask & mask);
+             }
+         }
+
+       // Assert that all bits in this word have been taken by control registers.
+       assert (unmatched_mask == 0); 
+       // Return the data.  (Caller will use the read mask.)
+       data_out = data;
+       return sid::bus::ok;
+      }
+  };
+
+
+  // Following class is used to overwrite access supervisory
+  // interface methods declared in class sid::component.
+  
+  class fixed_accessor_map_component: public virtual sid::component
+  {
+  public:
+
+    ~fixed_accessor_map_component() {}
+
+    // Returns vector of accessor names to components.
+    std::vector<std::string>
+    accessor_names() throw ()
+      {
+       std::vector<std::string> names;
+       for(accessor_map_t::const_iterator it = this->accessor_map.begin();
+           it != this->accessor_map.end();
+           it++)
+         {
+           names.push_back(it->first);
+         }
+       return names;
+      }
+
+
+    // Returns pointer to accessor bus corresponding to string name.
+    sid::bus*
+    connected_bus(const std::string& name) throw ()
+      {
+       accessor_map_t::iterator it = this->accessor_map.find(name);
+       if (it == this->accessor_map.end())
+         return 0;
+       else
+         return * it->second;
+      }
+
+
+    // Sets accessor represented by string name to bus pointed by argument.
+    sid::component::status
+    connect_accessor(const std::string& name, sid::bus* bus) throw ()
+      {
+       accessor_map_t::iterator it = this->accessor_map.find(name);
+       if (it != this->accessor_map.end()) 
+         {
+           // Only allow setting if unset
+           if (*it->second == 0)
+             {
+               *it->second = bus;
+               return sid::component::ok;
+             }
+           else
+             return sid::component::bad_value;
+         }
+
+       return sid::component::not_found;
+      }
+
+    // Disassociate a named accessor from a bus.
+    sid::component::status
+    disconnect_accessor(const std::string& name, sid::bus* bus) throw ()
+      {
+       accessor_map_t::iterator it = this->accessor_map.find(name);
+       if (it != this->accessor_map.end()) 
+         {
+           // Only allow setting if set to given prior value
+           if (*it->second == bus)
+             {
+               *it->second = 0;
+               return sid::component::ok;
+             }
+           else
+             return sid::component::bad_value;
+         }
+
+       return sid::component::not_found;
+      }
+
+  protected:
+    // add accessor to component
+    void
+    add_accessor(const std::string& name, sid::bus** accessor_address)
+      {
+       assert(accessor_address);
+       accessor_map[name] = accessor_address;
+      }
+
+  private:
+    typedef std::map<std::string,sid::bus**> accessor_map_t;
+    mutable accessor_map_t accessor_map;
+    
+  };
+
+  
+  // Class fixed_bus_map_component overwrites bus supervisory
+  // interface declared in class sid::component.
+  class fixed_bus_map_component: public virtual sid::component
+  {
+  public:
+    ~fixed_bus_map_component() {}
+
+    std::vector<std::string>
+    bus_names() throw ()
+      {
+       std::vector<std::string> names;
+       for(bus_map_t::const_iterator it = this->bus_map.begin();
+           it != this->bus_map.end();
+           it++)
+         {
+           names.push_back(it->first);
+         }
+       return names;
+      }
+    
+    // Returns pointer to bus that corresponds to string name.
+    sid::bus*
+    find_bus(const std::string& name) throw ()
+      {
+       bus_map_t::iterator it = this->bus_map.find(name);
+       if (it == this->bus_map.end())
+         return 0;
+       else
+         return it->second;
+      }
+
+  protected:
+    void
+    add_bus(const std::string& name, sid::bus* bus)
+      {
+       assert(bus);
+       bus_map[name] = bus;
+      }
+
+    // Disassociate a named bus
+    sid::component::status
+    disconnect_bus(const std::string& name, sid::bus* bus) throw ()
+      {
+       bus_map_t::iterator it = this->bus_map.find(name);
+       if (it != this->bus_map.end()) 
+         {
+           // Only allow setting if set to given prior value
+           if (it->second == bus)
+             {
+               it->second = 0;
+               return sid::component::ok;
+             }
+           else
+             return sid::component::bad_value;
+         }
+
+       return sid::component::not_found;
+      }
+
+  private:
+    typedef std::map<std::string,sid::bus*> bus_map_t;
+    mutable bus_map_t bus_map;
+  };
+
+  // Following class is a virtual base class used for implementing bus
+  // arbitrators.
+  class bus_arbitrator: public virtual sid::component,
+                       protected fixed_bus_map_component,
+                       protected virtual fixed_pin_map_component,
+                       protected fixed_accessor_map_component,
+                       protected no_relation_component,
+                       public fixed_attribute_map_with_logging_component
+  {
+  public:
+    bus_arbitrator () :
+      sched ("step", this, & bus_arbitrator::step_cycle)
+      {
+       // Attributes
+       add_attribute ("name", &name);
+       // Control pins
+       //
+       add_pin ("running", & running_pin);
+       running_pin.set_active_high ();
+       add_pin ("active", & active_pin);
+       active_pin.set_active_high ();
+      }
+    ~bus_arbitrator () { }
+
+  protected:
+    // A bus for requests from the input interfaces.
+    // 
+    class input_interface : public sid::bus
+    { 
+    public:
+      input_interface (bus_arbitrator *h, int us) : host (h), upstream (us) { }
+
+#define SID_GB_WRITE(dtype) \
+      sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
+         { return host->write(upstream, addr, data); }
+
+#define SID_GB_READ(dtype) \
+      sid::bus::status read(sid::host_int_4 addr, dtype& data) throw ()\
+         { return host->read(upstream, addr, data); }
+
+      SID_GB_WRITE(sid::little_int_1)
+      SID_GB_WRITE(sid::big_int_1)
+      SID_GB_WRITE(sid::little_int_2)
+      SID_GB_WRITE(sid::big_int_2)
+      SID_GB_WRITE(sid::little_int_4)
+      SID_GB_WRITE(sid::big_int_4)
+      SID_GB_WRITE(sid::little_int_8)
+      SID_GB_WRITE(sid::big_int_8)
+
+      SID_GB_READ(sid::little_int_1)
+      SID_GB_READ(sid::big_int_1)
+      SID_GB_READ(sid::little_int_2)
+      SID_GB_READ(sid::big_int_2)
+      SID_GB_READ(sid::little_int_4)
+      SID_GB_READ(sid::big_int_4)
+      SID_GB_READ(sid::little_int_8)
+      SID_GB_READ(sid::big_int_8)
+
+#undef SID_GB_WRITE
+#undef SID_GB_READ
+    private:
+      bus_arbitrator *host;
+      int upstream;
+    };
+    friend class input_interface;
+
+    // A struct representing a bus request
+    struct bus_request
+    {
+      bus_request () {}
+      bus_request (bool r, int us, int ds, sid::host_int_4 a, unsigned s)
+       : is_read(r), upstream(us), downstream(ds), addr(a), size(s)
+        { }
+      bool operator== (const bus_request &r)
+        {
+         return is_read == r.is_read
+           && upstream == r.upstream
+           && downstream == r.downstream
+           && addr == r.addr
+           && size == r.size;
+        }
+      bool is_read;
+      int upstream;
+      int downstream;
+      sid::host_int_4 addr;
+      unsigned size;
+    };
+
+  protected:
+    // Handlers for input interfaces
+    //
+    template<class DataType>
+    sid::bus::status
+    write(int upstream, sid::host_int_4 addr, DataType data)
+      {
+       if (ulog_level >= 8 || ! check_passthrough (upstream))
+         log (5, "%s: received write request from %s interface at 0x%x\n",
+              name.c_str (), up2str(upstream), addr);
+       return arbitrate_write (upstream, downstream_for_address (addr), addr, data);
+      }
+
+    template<class DataType>
+    sid::bus::status
+    read(int upstream, sid::host_int_4 addr, DataType& data)
+      {
+       if (ulog_level >= 8 || ! check_passthrough (upstream))
+         log (5, "%s: received read request from %s interface at 0x%x\n",
+              name.c_str (), up2str(upstream), addr);
+       return arbitrate_read (upstream, downstream_for_address (addr), addr, data);
+      }
+
+    virtual const char *up2str (int upstream) = 0;
+    virtual int downstream_for_address (sid::host_int_4 address) = 0;
+
+  protected:
+    // Advance time
+    //
+    virtual void step_cycle ()
+      {
+       log (5, "%s: Stepping\n", name.c_str());
+       update_busy_routes ();
+      }
+
+    virtual void reschedule (sid::host_int_2 latency)
+      {
+        if (latency)
+         {
+           log (5, "%s: rescheduling (%d)\n", name.c_str (), latency);
+           sched.schedule_irregular (1);
+         }
+      }
+
+    // Methods for arbitration
+    //
+    template<class DataType>
+    sid::bus::status arbitrate_read (int upstream,
+                                    int downstream,
+                                    sid::host_int_4 addr,
+                                    DataType& data)
+      {
+       // Check for direct passthrough
+       if (check_passthrough (upstream))
+         return downstream_bus (downstream)->read (addr, data);
+
+       // Prioritize the request
+       // Execute it if it's ready
+       bus_request r (true, upstream, downstream, addr, sizeof (data));
+       if (prioritize_request (r))
+         return perform_read (r, data);
+
+       return busy_status ();
+      }
+
+    template<class DataType>
+    sid::bus::status arbitrate_write (int upstream,
+                                     int downstream,
+                                     sid::host_int_4 addr,
+                                     DataType data)
+      {
+       // Check for direct passthrough
+       if (check_passthrough (upstream))
+         return downstream_bus (downstream)->write(addr, data);
+
+       // Prioritize the request
+       // Execute it if it's ready
+       bus_request r (false, upstream, downstream, addr, sizeof (data));
+       if (prioritize_request (r))
+         return perform_write (r, data);
+
+       return busy_status ();
+      }
+
+    // Provide a default implementation which does no prioritization and
+    // handles the requests right away as they arrive.
+    virtual bool prioritize_request (bus_request &r) { return true; }
+
+    // Methods for downstream accessors
+    //
+    template<class DataType>
+    sid::bus::status perform_read (bus_request &r, DataType &data)
+      {
+       // See if the route is available
+       if (check_route_busy (r.upstream, r.downstream))
+         return busy_status ();
+
+       // Propagate any locked pin from upstream
+       lock_downstream (r.upstream, r.downstream);
+
+       // Perform the read
+       sid::bus::status s = downstream_bus (r.downstream)->read (r.addr, data);
+
+       // Update status
+       if (s == sid::bus::ok)
+         s = set_route_busy (r, s);
+       return s;
+      }
+
+    template<class DataType>
+    sid::bus::status perform_write (bus_request &r, DataType data)
+      {
+       // See if the route is available
+       if (check_route_busy (r.upstream, r.downstream))
+         return busy_status ();
+  
+       // Propogate any locked pin from upstream
+       lock_downstream (r.upstream, r.downstream);
+
+       // Perform the write
+       sid::bus::status s = downstream_bus (r.downstream)->write (r.addr, data);
+
+       // Update status
+       if (s == sid::bus::ok)
+         s = set_route_busy (r, s);
+       return s;
+      }
+
+    virtual bool check_passthrough (int = 0)
+      {
+       if (running_pin.state () != binary_pin_active
+           || active_pin.state () != binary_pin_active)
+         {
+           log (8, "%s: system is idle -- passthrough\n", name.c_str ());
+           return true;
+         }
+       return false;
+      }
+
+  protected:
+    // Methods for timing
+    //
+    // Default to no latency
+    virtual sid::host_int_2 access_latency (bus_request &r) { return 0; }
+
+  protected:
+    // Route locking
+    //
+    virtual void lock_downstream (int upstream, int downstream) { }
+
+    virtual bool check_route_busy (int upstream, int downstream) { return false; }
+
+    virtual sid::bus::status set_route_busy (bus_request &r, sid::bus::status s) { return s; }
+    virtual void update_busy_routes () {}
+    virtual sid::bus::status busy_status ()
+      {
+       // Default - busy for 1 cycle
+       sid::bus::status s (sid::bus::busy, 1);
+       return s;
+      }
+
+    virtual sid::bus *downstream_bus (int downstream) = 0;
+
+  protected:
+    scheduler_event_subscription<bus_arbitrator> sched;
+    // This class must be a friend of scheduler_event_subscription<T>.
+    friend class scheduler_event_subscription<bus_arbitrator>;
+
+    // Attributes
+    string name;
+
+    // Control pins
+    //
+    binary_input_pin running_pin;
+    binary_input_pin active_pin;
+  };
+}
+
+
+
+#endif // H_SIDBUSUTIL_H