/////////////////////////////////////////////////////////////////////////////


// given
void DirSet(DIORaw *dio,int Num,int asOutput) {
  dio->sub->BitAssign16(dio->sub,4,Num,asOutput);
}
// and knowing that dio->sub is a specific bus with a function:
void BitAssign16(Bus *bus,int offset,int bit,int value) {
  if (value) {
    bus->Poke(bus,offset,bus->Peek(bus,offset) | (1 << bit));
  } else {
    bus->Poke(bus,offset,bus->Peek(bus,offset) & ~(1 << bit));
  }
}

// we can dissolve DirSet into this:
void DirSet(DIORaw *dio,int Num,int asOutput) {
  if (asOutput) {
    dio->sub->Poke(dio->sub,4,bus->Peek(bus,4) | (1 << Num));
  } else {
    dio->sub->Poke(dio->sub,4,bus->Peek(bus,4) & ~(1 << Num));
  }
}

// knowing further that Poke is defined as follows:
void Poke16(MMapBus *bus,int adrs,unsigned short val) {
  ((volatile unsigned short *)(bus->Mem+adrs))[0] = val;
}
// and that Peek is defined as follows:
unsigned short Peek16(MMapBus *bus,int adrs) {
  return ((volatile unsigned short *)(bus->Mem+adrs))[0];
}

// then we can further dissolve DirSet into this:
void DirSet(DIORaw *dio,int Num,int asOutput) {
  if (asOutput) {
    ((volatile unsigned short *)(dio->sub->Mem+4))[0] =
      ((volatile unsigned short *)(dio->sub->Mem+4))[0] | (1 << Num);
  } else {
    ((volatile unsigned short *)(dio->sub->Mem+4))[0] =
      ((volatile unsigned short *)(dio->sub->Mem+4))[0] & ~(1 << Num);
  }
}

// furthermore, we can move the dio->sub->Mem variable directly into
// our DIO to obtain this code:
void DirSet(DIORaw *dio,int Num,int asOutput) {
  if (asOutput) {
    ((volatile unsigned short *)(dio->Mem+4))[0] =
      ((volatile unsigned short *)(dio->Mem+4))[0] | (1 << Num);
  } else {
    ((volatile unsigned short *)(dio->Mem+4))[0] =
      ((volatile unsigned short *)(dio->Mem+4))[0] & ~(1 << Num);
  }
}
/////////////////////////////////////////////////////////////////////////////

// we can sorta do dissolving already automatically using aggressive
// compiler inlining.  however, before this is possible we first must
// call the actual class function instead of through a pointer.  second,
// there is still the matter of how exactly (or what we do) with the
// data structure, as we aren't actually combining objects.  however,
// perhaps this does not matter.
void DirSet(DIORaw *dio,int Num,int asOutput) {
  dio->sub->BitAssign16(dio->sub,4,Num,asOutput);
}
// ==>
void DirSet(DIORaw *dio,int Num,int asOutput) {
     MMapBusBitAssign(dio->sub,4,Num,asOutput);
}
// This leaves the main problem one of identifying all virtual calls
// and replacing them with static calls
// searching for this is not TOO hard, but some knowledge is needed of
// what our actual objects are.  the reason is that we cannot blindly
// apply the technique to every pointer member dereference that ends
// in a function call - or maybe we can.  but we still have to have
// some way to specify what the static function is.  currently we do
// encode this in the arch file, so perhaps if we know where to look for
// it we can decode it - although it seems like this may be complicated.

// Some of this could be done manually
// For instance, AtmelAT91DIORaw.c only ever accesses an MMapBus.
// So we could change all the dio->sub calls to MMapBus calls.
// Still, an automated method is desirable.

// we might be able to devise a simple semi-automatic method.
// for instance,
// ./staticize AtmelAT91DIORaw.c "dio->sub" MMapBus
//
// I think we actually don't even need to do any real C parsing here.
// We can do a strict textual substituion on "dio->sub->" to replace it
// with MMapBus.

// sed 's/dio->sub->/MMapBus/g' AtmelAT91DIORaw.virtual.c > AtmelAT91DIORaw.c

// 1. create a list of these substitutions for each platform
// 2. modify files such as MMapBus so that our direct functions are forcibly
//    inline and our virtual functions are a separate function that calls
//    the inline function and does nothing else. (is the last part really
//    needed?)
// 3. create a script to generate the static versions and make it part of
//    the build process
// 4. create a sample program to toggle a DIO as fast as possible.
// 5. get the scope and measure the difference between the virtual, static,
//    and inline versions.

// unfortunately, this partially obscures the fact that nearly all raw DIO
// objects go through CacheBus!  For performance it would be better to
// separate sync and async DIO.
