diff --git a/src/THcDetMap.cxx b/src/THcDetMap.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..feb8424ca7818147e153eeecfa0c53a887984a58
--- /dev/null
+++ b/src/THcDetMap.cxx
@@ -0,0 +1,370 @@
+//*-- Author :    Ole Hansen   16/05/00
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THaDetMap
+//
+// The standard detector map for a Hall A detector.
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "THaDetMap.h"
+#include <iostream>
+#include <iomanip>
+#include <cstring>
+#include <cstdlib>
+
+using namespace std;
+
+const int THaDetMap::kDetMapSize;
+
+// FIXME: load from db_cratemap
+struct ModuleType {
+  UInt_t  model;       // model identifier
+  Bool_t  adc;         // true if ADC
+  Bool_t  tdc;         // true if TDC
+};
+
+static const ModuleType module_list[] = {
+  { 1875, 0, 1 },
+  { 1877, 0, 1 },
+  { 1881, 1, 0 },
+  { 1872, 0, 1 },
+  { 3123, 1, 0 },
+  { 1182, 1, 0 },
+  {  792, 1, 0 },
+  {  775, 0, 1 },
+  {  767, 0, 1 },
+  { 3201, 0, 1 },
+  { 6401, 0, 1 },
+  { 1190, 0, 1 },
+  { 0 }
+};
+
+//_____________________________________________________________________________
+void THaDetMap::Module::SetModel( UInt_t m )
+{
+  model = m & kModelMask;
+  const ModuleType* md = module_list;
+  while ( md->model && model != md->model ) md++;
+  if( md->adc ) MakeADC();
+  if( md->tdc ) MakeTDC();
+}
+
+//_____________________________________________________________________________
+void THaDetMap::Module::SetResolution( Double_t res )
+{
+  resolution = res;
+}
+
+//_____________________________________________________________________________
+THaDetMap::THaDetMap() : fNmodules(0), fMap(0), fMaplength(0)
+{
+  // Default constructor. Creates an empty detector map.
+}
+
+//_____________________________________________________________________________
+THaDetMap::THaDetMap( const THaDetMap& rhs )
+{
+  // Copy constructor
+
+  fMaplength = rhs.fMaplength;
+  fNmodules  = rhs.fNmodules;
+  if( fMaplength > 0 ) {
+    fMap = new Module[fMaplength];
+    memcpy(fMap,rhs.fMap,fNmodules*sizeof(Module));
+  }
+}
+
+//_____________________________________________________________________________
+THaDetMap& THaDetMap::operator=( const THaDetMap& rhs )
+{
+  // THaDetMap assignment operator
+
+  if ( this != &rhs ) {
+    if ( fMaplength != rhs.fMaplength ) {
+      delete [] fMap;
+      fMaplength = rhs.fMaplength;
+      if( fMaplength > 0 )
+	fMap = new Module[fMaplength];
+    }
+    fNmodules = rhs.fNmodules;
+    memcpy(fMap,rhs.fMap,fNmodules*sizeof(Module));
+  }
+  return *this;
+}
+
+//_____________________________________________________________________________
+THaDetMap::~THaDetMap()
+{
+  // Destructor
+
+  delete [] fMap;
+}
+
+//_____________________________________________________________________________
+Int_t THaDetMap::AddModule( UShort_t crate, UShort_t slot, 
+			    UShort_t chan_lo, UShort_t chan_hi,
+			    UInt_t first, UInt_t model, Int_t refindex,
+			    Int_t refchan )
+{
+  // Add a module to the map.
+
+  if( fNmodules >= kDetMapSize ) return -1;  //Map is full
+  // Logical channels can run either "with" or "against" the physical channel
+  // numbers:
+  // lo<=hi :    lo -> first
+  //             hi -> first+hi-lo
+  // 
+  // lo>hi  :    hi -> first
+  //             lo -> first+lo-hi
+  // 
+  // To indicate the second case, The flag "reverse" is set to true in the 
+  // module. The fields lo and hi are reversed so that lo<=hi always.
+  // 
+  bool reverse = ( chan_lo > chan_hi );
+
+  if ( fNmodules >= fMaplength ) { // need to expand the Map
+    Int_t oldlen = fMaplength;
+    fMaplength += 10;
+    Module* tmpmap = new Module[fMaplength];   // expand in groups of 10
+    if( oldlen > 0 ) {
+      memcpy(tmpmap,fMap,oldlen*sizeof(Module));
+      delete [] fMap;
+    }
+    fMap = tmpmap;
+  }
+
+  Module& m = fMap[fNmodules];
+  m.crate = crate;
+  m.slot  = slot;
+  if( reverse ) {
+    m.lo = chan_hi;
+    m.hi = chan_lo;
+  } else {
+    m.lo = chan_lo;
+    m.hi = chan_hi;
+  }
+  m.first = first;
+  m.SetModel( model );
+  m.refindex = refindex;
+  m.refchan  = refchan;
+  m.SetResolution( 0.0 );
+  m.reverse = reverse;
+
+  return ++fNmodules;
+}
+
+//_____________________________________________________________________________
+THaDetMap::Module* THaDetMap::Find( UShort_t crate, UShort_t slot,
+				    UShort_t chan )
+{
+  // Return the module containing crate, slot, and channel chan.
+  // If several matching modules exist (which mean the map is misconfigured),
+  // only the first one is returned. If none match, return NULL.
+  // Since the map is usually small and not necessarily sorted, a simple
+  // linear search is done.
+
+  Module* found = NULL;
+  for( UShort_t i = 0; i < fNmodules; ++i ) {
+    Module* d = uGetModule(i);
+    if( d->crate == crate && d->slot == slot && 
+	d->lo <= chan && chan <= d->hi ) {
+      found = d;
+      break;
+    }
+  }
+  return found;
+}
+
+//_____________________________________________________________________________
+Int_t THaDetMap::Fill( const vector<Int_t>& values, UInt_t flags )
+{
+  // Fill the map with 'values'. Depending on 'flags', the values vector
+  // is interpreted as a 4-, 5-, 6- or 7-tuple:
+  //
+  // The first 4 values are interpreted as (crate,slot,start_chan,end_chan)
+  // Each of the following flags causes one more value to be used as part of
+  // the tuple for each module:
+  // 
+  // kFillLogicalChannel - Logical channel number for 'start_chan'.
+  // kFillModel          - The module's hardware model number (see AddModule())
+  // kFillRefChan        - Reference channel (for pipeline TDCs etc.)
+  // kFillRefIndex       - Reference index (for pipeline TDCs etc.)
+  //
+  // If more than one flag is present, the numbers will be interpreted
+  // in the order the flags are listed above. 
+  // Example:
+  //      flags = kFillModel | kFillRefChan
+  // ==>
+  //      the vector is interpreted as a series of 6-tuples in the order
+  //      (crate,slot,start_chan,end_chan,model,refchan).
+  //
+  // If kFillLogicalChannel is not set then the first logical channel numbers
+  // are automatically calculated for each module, assuming the numbers are 
+  // sequential.
+  // 
+  // By default, an existing map is overwritten. If the flag kDoNotClear 
+  // is present, then the data are appended.
+  //
+  // The return value is the number of modules successfully added,
+  // or negative if an error occurred.
+
+  typedef vector<Int_t>::size_type vsiz_t;
+
+  if( (flags & kDoNotClear) == 0 )
+    Clear();
+
+  vsiz_t tuple_size = 4;
+  if( flags & kFillLogicalChannel )
+    tuple_size++;
+  if( flags & kFillModel )
+    tuple_size++;
+  if( flags & kFillRefChan )
+    tuple_size++;
+  if( flags & kFillRefIndex )
+    tuple_size++;
+
+  UInt_t prev_first = 0, prev_nchan = 0;
+  // Defaults for optional values
+  UInt_t first = 0, model = 0;
+  Int_t rchan = -1, ref = -1;
+
+  Int_t ret = 0;
+  for( vsiz_t i = 0; i < values.size(); i += tuple_size ) {
+    // For compatibility with older maps, crate < 0 means end of data
+    if( values[i] < 0 )
+      break;
+    // Now we require a full tuple
+    if( i+tuple_size > values.size() ) {
+      ret = -127;
+      break;
+    }
+
+    vsiz_t k = 4;
+    if( flags & kFillLogicalChannel )
+      first = values[i+k++];
+    else {
+      first = prev_first + prev_nchan;
+    }
+    if( flags & kFillModel )
+      model = values[i+k++];
+    if( flags & kFillRefChan )
+      rchan = values[i+k++];
+    if( flags & kFillRefIndex )
+      ref   = values[i+k++];
+
+    ret = AddModule( values[i], values[i+1], values[i+2], values[i+3],
+		     first, model, ref, rchan );
+    if( ret<=0 )
+      break;
+    prev_first = first;
+    prev_nchan = GetNchan( ret-1 );
+  }
+  
+  return ret;
+}
+
+//_____________________________________________________________________________
+Int_t THaDetMap::GetTotNumChan() const
+{
+  // Get sum of the number of channels of all modules in the map. This is 
+  // typically the total number of hardware channels used by the detector.
+
+  Int_t sum = 0;
+  for( UShort_t i = 0; i < fNmodules; i++ )
+    sum += GetNchan(i);
+    
+  return sum;
+}
+
+
+//_____________________________________________________________________________
+void THaDetMap::GetMinMaxChan( Int_t& min, Int_t& max, ECountMode mode ) const
+{
+  // Put the minimum and maximum logical or reference channel numbers 
+  // into min and max. If refidx is true, check refindex, else check logical
+  // channel numbers.
+
+  min = kMaxInt;
+  max = kMinInt;
+  bool do_ref = ( mode == kRefIndex );
+  for( UShort_t i = 0; i < fNmodules; i++ ) {
+    Module* m = GetModule(i);
+    Int_t m_min = do_ref ? m->refindex : m->first;
+    Int_t m_max = do_ref ? m->refindex : m->first + m->hi - m->lo;
+    if( m_min < min )
+      min = m_min;
+    if( m_max > max )
+      max = m_max;
+  }
+}
+
+
+//_____________________________________________________________________________
+void THaDetMap::Print( Option_t* ) const
+{
+  // Print the contents of the map
+
+  cout << "Size: " << fNmodules << endl;
+  for( UShort_t i=0; i<fNmodules; i++ ) {
+    Module* m = GetModule(i);
+    cout << " " 
+	 << setw(5) << m->crate
+	 << setw(5) << m->slot 
+	 << setw(5) << m->lo 
+	 << setw(5) << m->hi 
+	 << setw(5) << m->first
+	 << setw(5) << GetModel(m);
+    if( IsADC(m) )
+      cout << setw(4) << " ADC";
+    if( IsTDC(m) )
+      cout << setw(4) << " TDC";
+    cout << setw(5) << m->refchan
+	 << setw(5) << m->refindex
+	 << setw(8) << m->resolution
+	 << endl;
+  }
+}
+
+//_____________________________________________________________________________
+void THaDetMap::Reset()
+{
+  // Clear() the map and reset the array size to zero, freeing memory.
+
+  Clear();
+  delete [] fMap;
+  fMap = NULL;
+  fMaplength = 0;
+}
+
+//_____________________________________________________________________________
+static int compare_modules( const void* p1, const void* p2 )
+{
+  // Helper function for sort
+
+  const THaDetMap::Module* lhs = static_cast<const THaDetMap::Module*>(p1);
+  const THaDetMap::Module* rhs = static_cast<const THaDetMap::Module*>(p2);
+  
+  if( lhs->crate < rhs->crate )  return -1;
+  if( lhs->crate > rhs->crate )  return  1;
+  if( lhs->slot < rhs->slot )    return -1;
+  if( lhs->slot > rhs->slot )    return  1;
+  if( lhs->lo < rhs->lo )        return -1;
+  if( lhs->lo > rhs->lo )        return  1;
+  return 0;
+}
+
+//_____________________________________________________________________________
+void THaDetMap::Sort()
+{
+  // Sort the map by crate/slot/low channel
+  
+  if( fMap && fNmodules )
+    qsort( fMap, fNmodules, sizeof(Module), compare_modules );
+
+}
+
+//_____________________________________________________________________________
+ClassImp(THaDetMap)
+
diff --git a/src/THcDetMap.h b/src/THcDetMap.h
new file mode 100644
index 0000000000000000000000000000000000000000..317bc0072e3d7aa9faf52252783fde658aaf133a
--- /dev/null
+++ b/src/THcDetMap.h
@@ -0,0 +1,161 @@
+
+#ifndef ROOT_THaDetMap
+#define ROOT_THaDetMap
+
+//////////////////////////////////////////////////////////////////////////
+//
+// THaDetMap
+//
+// Standard detector map.
+// The detector map defines the hardware channels that correspond to a
+// single detector. Typically, "channels" are Fastbus or VMW addresses 
+// characterized by
+//
+//   Crate, Slot, range of channels
+//
+//////////////////////////////////////////////////////////////////////////
+
+//FIXME: Several things here are duplicates of information that already is
+// (or should be) available from the cratemap:  specifically "model" and
+// "resolution", as well as the "model map" in AddModule. We should get it from
+// there -  to ensure consistency and have one less maintenance headache.
+
+#include "Rtypes.h"
+#include <vector>
+
+class THaDetMap {
+
+protected:
+  static const UInt_t kADCBit = BIT(31);
+  static const UInt_t kTDCBit = BIT(30);
+  // Upper byte of model reserved for property bits
+  static const UInt_t kModelMask = 0x00ffffff;
+  
+public:
+  struct Module {
+    UShort_t crate;
+    UShort_t slot;
+    UShort_t lo;
+    UShort_t hi;
+    UInt_t   first;  // logical number of first channel
+    UInt_t   model;  // model number of module (for ADC/TDC identification).
+    Int_t    refchan;    // for pipeline TDCs: reference channel number
+    Int_t    refindex;   // for pipeline TDCs: index into reference channel map
+    Double_t resolution; // Resolution (s/chan) for TDCs
+    Bool_t   reverse;    // Indicates that "first" corresponds to hi, not lo
+
+    bool   operator==( const Module& rhs ) const
+    { return crate == rhs.crate && slot == rhs.slot; }
+    bool   operator!=( const Module& rhs ) const
+    { return !(*this==rhs); }
+    Int_t  GetNchan() const { return hi-lo+1; }
+    UInt_t GetModel() const { return model & kModelMask; }
+    Bool_t IsTDC()    const { return model & kTDCBit; }
+    Bool_t IsADC()    const { return model & kADCBit; }
+    void   SetModel( UInt_t model );
+    void   SetResolution( Double_t resolution );
+    void   MakeTDC()  { model |= kTDCBit; }
+    void   MakeADC()  { model |= kADCBit; }
+  };
+
+  // Flags for GetMinMaxChan()
+  enum ECountMode {
+    kLogicalChan         = 0,
+    kRefIndex            = 1
+  };
+  // Flags for Fill()
+  enum EFillFlags {
+    kDoNotClear          = BIT(0),    // Don't clear the map first
+    kFillLogicalChannel  = BIT(10),   // Parse the logical channel number
+    kFillModel           = BIT(11),   // Parse the model number
+    kFillRefIndex        = BIT(12),   // Parse the reference index
+    kFillRefChan         = BIT(13)    // Parse the reference channel
+  };
+
+  THaDetMap();
+  THaDetMap( const THaDetMap& );
+  THaDetMap& operator=( const THaDetMap& );
+  virtual ~THaDetMap();
+  
+  virtual Int_t     AddModule( UShort_t crate, UShort_t slot, 
+			       UShort_t chan_lo, UShort_t chan_hi,
+			       UInt_t first=0, UInt_t model=0,
+			       Int_t refindex=-1, Int_t refchan = -1 );
+          void      Clear()  { fNmodules = 0; }
+  virtual Module*   Find( UShort_t crate, UShort_t slot, UShort_t chan );
+  virtual Int_t     Fill( const std::vector<Int_t>& values, UInt_t flags = 0 );
+          void      GetMinMaxChan( Int_t& min, Int_t& max,
+				   ECountMode mode = kLogicalChan ) const;
+          Module*   GetModule( UShort_t i ) const ;
+          Int_t     GetNchan( UShort_t i ) const;
+          Int_t     GetTotNumChan() const;
+          Int_t     GetSize() const { return static_cast<Int_t>(fNmodules); }
+
+          UInt_t    GetModel( UShort_t i ) const;
+          Bool_t    IsADC( UShort_t i ) const;
+          Bool_t    IsTDC( UShort_t i ) const;
+  static  UInt_t    GetModel( Module* d );
+  static  Bool_t    IsADC( Module* d );
+  static  Bool_t    IsTDC( Module* d );
+
+  virtual void      Print( Option_t* opt="" ) const;
+  virtual void      Reset();
+  virtual void      Sort();
+
+  static const int kDetMapSize = (1<<16)-1;  //Sanity limit on map size
+
+protected:
+  UShort_t     fNmodules;  // Number of modules (=crate,slot) in the map
+
+  Module*      fMap;       // Array of modules, each module is a 7-tuple
+                           // (create,slot,chan_lo,chan_hi,first_logical,
+                           // model,refindex)
+
+  Int_t        fMaplength; // current size of the fMap array
+  
+  Module*      uGetModule( UShort_t i ) const { return fMap+i; }
+
+  ClassDef(THaDetMap,0)   //The standard detector map
+};
+
+inline THaDetMap::Module* THaDetMap::GetModule( UShort_t i ) const {
+  return i<fNmodules ? uGetModule(i) : NULL; 
+}
+
+inline Bool_t THaDetMap::IsADC(Module* d) {
+  if( !d ) return kFALSE;
+  return d->IsADC();
+}
+
+inline Bool_t THaDetMap::IsTDC(Module* d) {
+  if( !d ) return kFALSE;
+  return d->IsTDC();
+}
+
+inline UInt_t THaDetMap::GetModel(Module* d) {
+  if( !d ) return 0;
+  return d->GetModel();
+}
+
+inline Bool_t THaDetMap::IsADC( UShort_t i ) const {
+  if( i >= fNmodules ) return kFALSE;
+  return uGetModule(i)->IsADC();
+}
+
+inline Bool_t THaDetMap::IsTDC( UShort_t i ) const {
+  if( i >= fNmodules ) return kFALSE;
+  return uGetModule(i)->IsTDC();
+}
+
+inline UInt_t THaDetMap::GetModel( UShort_t i ) const {
+  if( i >= fNmodules ) return 0;
+  return uGetModule(i)->GetModel();
+}
+
+inline Int_t THaDetMap::GetNchan( UShort_t i ) const {
+  // Return the number of channels of the i-th module
+  if( i >= fNmodules ) return 0;
+  return uGetModule(i)->GetNchan();
+}
+
+#endif