From 23e0ca1b1fc2d92d534201d9b2899de6f9fd5967 Mon Sep 17 00:00:00 2001
From: "Jake.Stine" <Jake.Stine@96395faa-99c1-11dd-bbfe-3dabce05a288>
Date: Fri, 6 Mar 2009 01:11:17 +0000
Subject: [PATCH] Added googlecode's sparsehash / densehash classes, which may
 or may not be useful in the future.

Removed various instances of legacy VM code that is no longer needed for reference purposes.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@695 96395faa-99c1-11dd-bbfe-3dabce05a288
---
 3rdparty/google/dense_hash_map               |  261 +++
 3rdparty/google/dense_hash_set               |  245 ++
 3rdparty/google/sparse_hash_map              |  246 ++
 3rdparty/google/sparse_hash_set              |  231 ++
 3rdparty/google/sparsehash/densehashtable.h  |  986 ++++++++
 3rdparty/google/sparsehash/sparseconfig.h    |   74 +
 3rdparty/google/sparsehash/sparsehashtable.h |  941 ++++++++
 3rdparty/google/sparsetable                  | 1451 ++++++++++++
 3rdparty/google/type_traits.h                |  250 ++
 pcsx2/Hw.cpp                                 |    6 +-
 pcsx2/MemoryVM.cpp                           | 2140 ------------------
 pcsx2/SPR.cpp                                |    4 +-
 pcsx2/windows/VCprojects/pcsx2_2008.vcproj   |   52 +-
 pcsx2/windows/WinVM.cpp                      |  470 ----
 pcsx2/x86/iGS.cpp                            |  298 ---
 pcsx2/x86/iHw.cpp                            | 1145 ----------
 pcsx2/x86/iIPU.cpp                           |  203 --
 pcsx2/x86/iPsxHw.cpp                         | 1179 ----------
 pcsx2/x86/iR5900CoissuedLoadStore.cpp        | 1738 --------------
 19 files changed, 4698 insertions(+), 7222 deletions(-)
 create mode 100644 3rdparty/google/dense_hash_map
 create mode 100644 3rdparty/google/dense_hash_set
 create mode 100644 3rdparty/google/sparse_hash_map
 create mode 100644 3rdparty/google/sparse_hash_set
 create mode 100644 3rdparty/google/sparsehash/densehashtable.h
 create mode 100644 3rdparty/google/sparsehash/sparseconfig.h
 create mode 100644 3rdparty/google/sparsehash/sparsehashtable.h
 create mode 100644 3rdparty/google/sparsetable
 create mode 100644 3rdparty/google/type_traits.h
 delete mode 100644 pcsx2/MemoryVM.cpp
 delete mode 100644 pcsx2/windows/WinVM.cpp
 delete mode 100644 pcsx2/x86/iGS.cpp
 delete mode 100644 pcsx2/x86/iHw.cpp
 delete mode 100644 pcsx2/x86/iIPU.cpp
 delete mode 100644 pcsx2/x86/iPsxHw.cpp
 delete mode 100644 pcsx2/x86/iR5900CoissuedLoadStore.cpp

diff --git a/3rdparty/google/dense_hash_map b/3rdparty/google/dense_hash_map
new file mode 100644
index 0000000000..41a749a493
--- /dev/null
+++ b/3rdparty/google/dense_hash_map
@@ -0,0 +1,261 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ----
+// Author: Craig Silverstein
+//
+// This is just a very thin wrapper over densehashtable.h, just
+// like sgi stl's stl_hash_map is a very thin wrapper over
+// stl_hashtable.  The major thing we define is operator[], because
+// we have a concept of a data_type which stl_hashtable doesn't
+// (it only has a key and a value).
+//
+// NOTE: this is exactly like sparse_hash_map.h, with the word
+// "sparse" replaced by "dense", except for the addition of
+// set_empty_key().
+//
+//   YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
+//
+// Otherwise your program will die in mysterious ways.
+//
+// In other respects, we adhere mostly to the STL semantics for
+// hash-map.  One important exception is that insert() invalidates
+// iterators entirely.  On the plus side, though, erase() doesn't
+// invalidate iterators at all, or even change the ordering of elements.
+//
+// Here are a few "power user" tips:
+//
+//    1) set_deleted_key():
+//         If you want to use erase() you must call set_deleted_key(),
+//         in addition to set_empty_key(), after construction.
+//         The deleted and empty keys must differ.
+//
+//    2) resize(0):
+//         When an item is deleted, its memory isn't freed right
+//         away.  This allows you to iterate over a hashtable,
+//         and call erase(), without invalidating the iterator.
+//         To force the memory to be freed, call resize(0).
+//
+//    3) set_resizing_parameters(0.0, 0.8):
+//         Setting the shrink_resize_percent to 0.0 guarantees
+//         that the hash table will never shrink.
+//
+// Guide to what kind of hash_map to use:
+//   (1) dense_hash_map: fastest, uses the most memory
+//   (2) sparse_hash_map: slowest, uses the least memory
+//   (3) hash_map (STL): in the middle
+// Typically I use sparse_hash_map when I care about space and/or when
+// I need to save the hashtable on disk.  I use hash_map otherwise.  I
+// don't personally use dense_hash_map ever; the only use of
+// dense_hash_map I know of is to work around malloc() bugs in some
+// systems (dense_hash_map has a particularly simple allocation scheme).
+//
+// - dense_hash_map has, typically, a factor of 2 memory overhead (if your
+//   data takes up X bytes, the hash_map uses X more bytes in overhead).
+// - sparse_hash_map has about 2 bits overhead per entry.
+// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
+//   especially, inserts.  See time_hash_map.cc for details.
+//
+// See /usr/(local/)?doc/sparsehash-0.1/dense_hash_map.html
+// for information about how to use this class.
+
+#ifndef _DENSE_HASH_MAP_H_
+#define _DENSE_HASH_MAP_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <stdio.h>                   // for FILE * in read()/write()
+#include <algorithm>                 // for the default template args
+#include <functional>                // for equal_to
+#include <memory>                    // for alloc<>
+#include <utility>                   // for pair<>
+#include HASH_FUN_H                  // defined in config.h
+#include <google/sparsehash/densehashtable.h>
+
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+template <class Key, class T,
+          class HashFcn = SPARSEHASH_HASH<Key>,   // defined in sparseconfig.h
+          class EqualKey = STL_NAMESPACE::equal_to<Key>,
+          class Alloc = STL_NAMESPACE::allocator<T> >
+class dense_hash_map {
+ private:
+  // Apparently select1st is not stl-standard, so we define our own
+  struct SelectKey {
+    const Key& operator()(const pair<const Key, T>& p) const {
+      return p.first;
+    }
+  };
+
+  // The actual data
+  typedef dense_hashtable<pair<const Key, T>, Key, HashFcn,
+                          SelectKey, EqualKey, Alloc> ht;
+  ht rep;
+
+ public:
+  typedef typename ht::key_type key_type;
+  typedef T data_type;
+  typedef T mapped_type;
+  typedef typename ht::value_type value_type;
+  typedef typename ht::hasher hasher;
+  typedef typename ht::key_equal key_equal;
+
+  typedef typename ht::size_type size_type;
+  typedef typename ht::difference_type difference_type;
+  typedef typename ht::pointer pointer;
+  typedef typename ht::const_pointer const_pointer;
+  typedef typename ht::reference reference;
+  typedef typename ht::const_reference const_reference;
+
+  typedef typename ht::iterator iterator;
+  typedef typename ht::const_iterator const_iterator;
+
+  // Iterator functions
+  iterator begin()                    { return rep.begin(); }
+  iterator end()                      { return rep.end(); }
+  const_iterator begin() const        { return rep.begin(); }
+  const_iterator end() const          { return rep.end(); }
+
+
+  // Accessor functions
+  hasher hash_funct() const { return rep.hash_funct(); }
+  key_equal key_eq() const  { return rep.key_eq(); }
+
+
+  // Constructors
+  explicit dense_hash_map(size_type expected_max_items_in_table = 0,
+                          const hasher& hf = hasher(),
+                          const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) { }
+
+  template <class InputIterator>
+  dense_hash_map(InputIterator f, InputIterator l,
+                 size_type expected_max_items_in_table = 0,
+                 const hasher& hf = hasher(),
+                 const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) {
+    rep.insert(f, l);
+  }
+  // We use the default copy constructor
+  // We use the default operator=()
+  // We use the default destructor
+
+  void clear()                        { rep.clear(); }
+  // This clears the hash map without resizing it down to the minimum
+  // bucket count, but rather keeps the number of buckets constant
+  void clear_no_resize()              { rep.clear_no_resize(); }
+  void swap(dense_hash_map& hs)       { rep.swap(hs.rep); }
+
+
+  // Functions concerning size
+  size_type size() const              { return rep.size(); }
+  size_type max_size() const          { return rep.max_size(); }
+  bool empty() const                  { return rep.empty(); }
+  size_type bucket_count() const      { return rep.bucket_count(); }
+  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
+
+  void resize(size_type hint)         { rep.resize(hint); }
+
+  void set_resizing_parameters(float shrink, float grow) {
+    return rep.set_resizing_parameters(shrink, grow);
+  }
+
+  // Lookup routines
+  iterator find(const key_type& key)                 { return rep.find(key); }
+  const_iterator find(const key_type& key) const     { return rep.find(key); }
+
+  data_type& operator[](const key_type& key) {       // This is our value-add!
+    iterator it = find(key);
+    if (it != end()) {
+      return it->second;
+    } else {
+      return insert(value_type(key, data_type())).first->second;
+    }
+  }
+
+  size_type count(const key_type& key) const         { return rep.count(key); }
+
+  pair<iterator, iterator> equal_range(const key_type& key) {
+    return rep.equal_range(key);
+  }
+  pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
+    return rep.equal_range(key);
+  }
+
+  // Insertion routines
+  pair<iterator, bool> insert(const value_type& obj) { return rep.insert(obj); }
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l)      { rep.insert(f, l); }
+  void insert(const_iterator f, const_iterator l)    { rep.insert(f, l); }
+  // required for std::insert_iterator; the passed-in iterator is ignored
+  iterator insert(iterator, const value_type& obj)   { return insert(obj).first; }
+
+
+  // Deletion and empty routines
+  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
+  // value to identify deleted and empty buckets.  You can change the
+  // deleted key as time goes on, or get rid of it entirely to be insert-only.
+  void set_empty_key(const key_type& key)   {           // YOU MUST CALL THIS!
+    rep.set_empty_key(value_type(key, data_type()));    // rep wants a value
+  }
+  void set_deleted_key(const key_type& key)   {
+    rep.set_deleted_key(value_type(key, data_type()));  // rep wants a value
+  }
+  void clear_deleted_key()                    { rep.clear_deleted_key(); }
+
+  // These are standard
+  size_type erase(const key_type& key)               { return rep.erase(key); }
+  void erase(iterator it)                            { rep.erase(it); }
+  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
+
+
+  // Comparison
+  bool operator==(const dense_hash_map& hs) const    { return rep == hs.rep; }
+  bool operator!=(const dense_hash_map& hs) const    { return rep != hs.rep; }
+
+
+  // I/O -- this is an add-on for writing metainformation to disk
+  bool write_metadata(FILE *fp)       { return rep.write_metadata(fp); }
+  bool read_metadata(FILE *fp)        { return rep.read_metadata(fp); }
+  bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
+  bool read_nopointer_data(FILE *fp)  { return rep.read_nopointer_data(fp); }
+};
+
+// We need a global swap as well
+template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+inline void swap(dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
+                 dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
+  hm1.swap(hm2);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _DENSE_HASH_MAP_H_ */
diff --git a/3rdparty/google/dense_hash_set b/3rdparty/google/dense_hash_set
new file mode 100644
index 0000000000..30e2c64065
--- /dev/null
+++ b/3rdparty/google/dense_hash_set
@@ -0,0 +1,245 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// This is just a very thin wrapper over densehashtable.h, just
+// like sgi stl's stl_hash_set is a very thin wrapper over
+// stl_hashtable.  The major thing we define is operator[], because
+// we have a concept of a data_type which stl_hashtable doesn't
+// (it only has a key and a value).
+//
+// This is more different from dense_hash_map than you might think,
+// because all iterators for sets are const (you obviously can't
+// change the key, and for sets there is no value).
+//
+// NOTE: this is exactly like sparse_hash_set.h, with the word
+// "sparse" replaced by "dense", except for the addition of
+// set_empty_key().
+//
+//   YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
+//
+// Otherwise your program will die in mysterious ways.
+//
+// In other respects, we adhere mostly to the STL semantics for
+// hash-set.  One important exception is that insert() invalidates
+// iterators entirely.  On the plus side, though, erase() doesn't
+// invalidate iterators at all, or even change the ordering of elements.
+//
+// Here are a few "power user" tips:
+//
+//    1) set_deleted_key():
+//         If you want to use erase() you must call set_deleted_key(),
+//         in addition to set_empty_key(), after construction.
+//         The deleted and empty keys must differ.
+//
+//    2) resize(0):
+//         When an item is deleted, its memory isn't freed right
+//         away.  This allows you to iterate over a hashtable,
+//         and call erase(), without invalidating the iterator.
+//         To force the memory to be freed, call resize(0).
+//
+//    3) set_resizing_parameters(0.0, 0.8):
+//         Setting the shrink_resize_percent to 0.0 guarantees
+//         that the hash table will never shrink.
+//
+// Guide to what kind of hash_set to use:
+//   (1) dense_hash_set: fastest, uses the most memory
+//   (2) sparse_hash_set: slowest, uses the least memory
+//   (3) hash_set (STL): in the middle
+// Typically I use sparse_hash_set when I care about space and/or when
+// I need to save the hashtable on disk.  I use hash_set otherwise.  I
+// don't personally use dense_hash_set ever; the only use of
+// dense_hash_set I know of is to work around malloc() bugs in some
+// systems (dense_hash_set has a particularly simple allocation scheme).
+//
+// - dense_hash_set has, typically, a factor of 2 memory overhead (if your
+//   data takes up X bytes, the hash_set uses X more bytes in overhead).
+// - sparse_hash_set has about 2 bits overhead per entry.
+// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
+//   especially, inserts.  See time_hash_map.cc for details.
+//
+// See /usr/(local/)?doc/sparsehash-0.1/dense_hash_set.html
+// for information about how to use this class.
+
+#ifndef _DENSE_HASH_SET_H_
+#define _DENSE_HASH_SET_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <stdio.h>                   // for FILE * in read()/write()
+#include <algorithm>                 // for the default template args
+#include <functional>                // for equal_to
+#include <memory>                    // for alloc<>
+#include <utility>                   // for pair<>
+#include HASH_FUN_H                  // defined in config.h
+#include <google/sparsehash/densehashtable.h>
+
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+template <class Value,
+          class HashFcn = SPARSEHASH_HASH<Value>,  // defined in sparseconfig.h
+          class EqualKey = STL_NAMESPACE::equal_to<Value>, 
+          class Alloc = STL_NAMESPACE::allocator<Value> >
+class dense_hash_set {
+ private:
+  // Apparently identity is not stl-standard, so we define our own
+  struct Identity {
+    Value& operator()(Value& v) const { return v; }
+    const Value& operator()(const Value& v) const { return v; }
+  };
+
+  // The actual data
+  typedef dense_hashtable<Value, Value, HashFcn, Identity, EqualKey, Alloc> ht;
+  ht rep;
+
+ public:
+  typedef typename ht::key_type key_type;
+  typedef typename ht::value_type value_type;
+  typedef typename ht::hasher hasher;
+  typedef typename ht::key_equal key_equal;
+
+  typedef typename ht::size_type size_type;
+  typedef typename ht::difference_type difference_type;
+  typedef typename ht::const_pointer pointer;
+  typedef typename ht::const_pointer const_pointer;
+  typedef typename ht::const_reference reference;
+  typedef typename ht::const_reference const_reference;
+
+  typedef typename ht::const_iterator iterator;
+  typedef typename ht::const_iterator const_iterator;
+
+
+  // Iterator functions -- recall all iterators are const
+  iterator begin() const              { return rep.begin(); }
+  iterator end() const                { return rep.end(); }
+
+
+  // Accessor functions
+  hasher hash_funct() const { return rep.hash_funct(); }
+  key_equal key_eq() const  { return rep.key_eq(); }
+
+
+  // Constructors
+  explicit dense_hash_set(size_type expected_max_items_in_table = 0,
+                          const hasher& hf = hasher(),
+                          const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) { }
+
+  template <class InputIterator>
+  dense_hash_set(InputIterator f, InputIterator l,
+                 size_type expected_max_items_in_table = 0,
+                 const hasher& hf = hasher(),
+                 const key_equal& eql = key_equal())
+      : rep(expected_max_items_in_table, hf, eql) {
+    rep.insert(f, l);
+  }
+  // We use the default copy constructor
+  // We use the default operator=()
+  // We use the default destructor
+
+  void clear()                        { rep.clear(); }
+  // This clears the hash set without resizing it down to the minimum
+  // bucket count, but rather keeps the number of buckets constant
+  void clear_no_resize()              { rep.clear_no_resize(); }
+  void swap(dense_hash_set& hs)       { rep.swap(hs.rep); }
+
+
+  // Functions concerning size
+  size_type size() const              { return rep.size(); }
+  size_type max_size() const          { return rep.max_size(); }
+  bool empty() const                  { return rep.empty(); }
+  size_type bucket_count() const      { return rep.bucket_count(); }
+  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
+
+  void resize(size_type hint)         { rep.resize(hint); }
+
+  void set_resizing_parameters(float shrink, float grow) {
+    return rep.set_resizing_parameters(shrink, grow);
+  }
+
+  // Lookup routines
+  iterator find(const key_type& key) const           { return rep.find(key); }
+
+  size_type count(const key_type& key) const         { return rep.count(key); }
+
+  pair<iterator, iterator> equal_range(const key_type& key) const {
+    return rep.equal_range(key);
+  }
+
+  // Insertion routines
+  pair<iterator, bool> insert(const value_type& obj) {
+    pair<typename ht::iterator, bool> p = rep.insert(obj);
+    return pair<iterator, bool>(p.first, p.second);   // const to non-const
+  }
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l)      { rep.insert(f, l); }
+  void insert(const_iterator f, const_iterator l)    { rep.insert(f, l); }
+  // required for std::insert_iterator; the passed-in iterator is ignored
+  iterator insert(iterator, const value_type& obj)   { return insert(obj).first; }
+
+
+  // Deletion and empty routines
+  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
+  // value to identify deleted and empty buckets.  You can change the
+  // deleted key as time goes on, or get rid of it entirely to be insert-only.
+  void set_empty_key(const key_type& key)     { rep.set_empty_key(key); }
+  void set_deleted_key(const key_type& key)   { rep.set_deleted_key(key); }
+  void clear_deleted_key()                    { rep.clear_deleted_key(); }
+
+  // These are standard
+  size_type erase(const key_type& key)               { return rep.erase(key); }
+  void erase(iterator it)                            { rep.erase(it); }
+  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
+
+
+  // Comparison
+  bool operator==(const dense_hash_set& hs) const    { return rep == hs.rep; }
+  bool operator!=(const dense_hash_set& hs) const    { return rep != hs.rep; }
+
+
+  // I/O -- this is an add-on for writing metainformation to disk
+  bool write_metadata(FILE *fp)       { return rep.write_metadata(fp); }
+  bool read_metadata(FILE *fp)        { return rep.read_metadata(fp); }
+  bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
+  bool read_nopointer_data(FILE *fp)  { return rep.read_nopointer_data(fp); }
+};
+
+template <class Val, class HashFcn, class EqualKey, class Alloc>
+inline void swap(dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
+                 dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
+  hs1.swap(hs2);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _DENSE_HASH_SET_H_ */
diff --git a/3rdparty/google/sparse_hash_map b/3rdparty/google/sparse_hash_map
new file mode 100644
index 0000000000..18f699218e
--- /dev/null
+++ b/3rdparty/google/sparse_hash_map
@@ -0,0 +1,246 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// This is just a very thin wrapper over sparsehashtable.h, just
+// like sgi stl's stl_hash_map is a very thin wrapper over
+// stl_hashtable.  The major thing we define is operator[], because
+// we have a concept of a data_type which stl_hashtable doesn't
+// (it only has a key and a value).
+//
+// We adhere mostly to the STL semantics for hash-map.  One important
+// exception is that insert() invalidates iterators entirely.  On the
+// plus side, though, delete() doesn't invalidate iterators at all, or
+// even change the ordering of elements.
+//
+// Here are a few "power user" tips:
+//
+//    1) set_deleted_key():
+//         Unlike STL's hash_map, if you want to use erase() you
+//         must call set_deleted_key() after construction.
+//
+//    2) resize(0):
+//         When an item is deleted, its memory isn't freed right
+//         away.  This is what allows you to iterate over a hashtable
+//         and call erase() without invalidating the iterator.
+//         To force the memory to be freed, call resize(0).
+//
+//    3) set_resizing_parameters(0.0, 0.8):
+//         Setting the shrink_resize_percent to 0.0 guarantees
+//         that the hash table will never shrink.
+//
+// Guide to what kind of hash_map to use:
+//   (1) dense_hash_map: fastest, uses the most memory
+//   (2) sparse_hash_map: slowest, uses the least memory
+//   (3) hash_map (STL): in the middle
+// Typically I use sparse_hash_map when I care about space and/or when
+// I need to save the hashtable on disk.  I use hash_map otherwise.  I
+// don't personally use dense_hash_map ever; the only use of
+// dense_hash_map I know of is to work around malloc() bugs in some
+// systems (dense_hash_map has a particularly simple allocation scheme).
+//
+// - dense_hash_map has, typically, a factor of 2 memory overhead (if your
+//   data takes up X bytes, the hash_map uses X more bytes in overhead).
+// - sparse_hash_map has about 2 bits overhead per entry.
+// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
+//   especially, inserts.  See time_hash_map.cc for details.
+//
+// See /usr/(local/)?doc/sparsehash-0.1/sparse_hash_map.html
+// for information about how to use this class.
+
+#ifndef _SPARSE_HASH_MAP_H_
+#define _SPARSE_HASH_MAP_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <stdio.h>                   // for FILE * in read()/write()
+#include <algorithm>                 // for the default template args
+#include <functional>                // for equal_to
+#include <memory>                    // for alloc<>
+#include <utility>                   // for pair<>
+#include HASH_FUN_H                  // defined in config.h
+#include <google/sparsehash/sparsehashtable.h>
+
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+template <class Key, class T,
+          class HashFcn = SPARSEHASH_HASH<Key>,   // defined in sparseconfig.h
+          class EqualKey = STL_NAMESPACE::equal_to<Key>,
+          class Alloc = STL_NAMESPACE::allocator<T> >
+class sparse_hash_map {
+ private:
+  // Apparently select1st is not stl-standard, so we define our own
+  struct SelectKey {
+    const Key& operator()(const pair<const Key, T>& p) const {
+      return p.first;
+    }
+  };
+
+  // The actual data
+  typedef sparse_hashtable<pair<const Key, T>, Key, HashFcn,
+                           SelectKey, EqualKey, Alloc> ht;
+  ht rep;
+
+ public:
+  typedef typename ht::key_type key_type;
+  typedef T data_type;
+  typedef T mapped_type;
+  typedef typename ht::value_type value_type;
+  typedef typename ht::hasher hasher;
+  typedef typename ht::key_equal key_equal;
+
+  typedef typename ht::size_type size_type;
+  typedef typename ht::difference_type difference_type;
+  typedef typename ht::pointer pointer;
+  typedef typename ht::const_pointer const_pointer;
+  typedef typename ht::reference reference;
+  typedef typename ht::const_reference const_reference;
+
+  typedef typename ht::iterator iterator;
+  typedef typename ht::const_iterator const_iterator;
+
+  // Iterator functions
+  iterator begin()                    { return rep.begin(); }
+  iterator end()                      { return rep.end(); }
+  const_iterator begin() const        { return rep.begin(); }
+  const_iterator end() const          { return rep.end(); }
+
+
+  // Accessor functions
+  hasher hash_funct() const { return rep.hash_funct(); }
+  key_equal key_eq() const  { return rep.key_eq(); }
+
+
+  // Constructors
+  explicit sparse_hash_map(size_type expected_max_items_in_table = 0,
+                           const hasher& hf = hasher(),
+                           const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) { }
+
+  template <class InputIterator>
+  sparse_hash_map(InputIterator f, InputIterator l,
+                  size_type expected_max_items_in_table = 0,
+                  const hasher& hf = hasher(),
+                  const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) {
+    rep.insert(f, l);
+  }
+  // We use the default copy constructor
+  // We use the default operator=()
+  // We use the default destructor
+
+  void clear()                        { rep.clear(); }
+  void swap(sparse_hash_map& hs)      { rep.swap(hs.rep); }
+
+
+  // Functions concerning size
+  size_type size() const              { return rep.size(); }
+  size_type max_size() const          { return rep.max_size(); }
+  bool empty() const                  { return rep.empty(); }
+  size_type bucket_count() const      { return rep.bucket_count(); }
+  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
+
+  void resize(size_type hint)         { rep.resize(hint); }
+
+  void set_resizing_parameters(float shrink, float grow) {
+    return rep.set_resizing_parameters(shrink, grow);
+  }
+
+  // Lookup routines
+  iterator find(const key_type& key)                 { return rep.find(key); }
+  const_iterator find(const key_type& key) const     { return rep.find(key); }
+
+  data_type& operator[](const key_type& key) {       // This is our value-add!
+    iterator it = find(key);
+    if (it != end()) {
+      return it->second;
+    } else {
+      return insert(value_type(key, data_type())).first->second;
+    }
+  }
+
+  size_type count(const key_type& key) const         { return rep.count(key); }
+
+  pair<iterator, iterator> equal_range(const key_type& key) {
+    return rep.equal_range(key);
+  }
+  pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
+    return rep.equal_range(key);
+  }
+
+  // Insertion routines
+  pair<iterator, bool> insert(const value_type& obj) { return rep.insert(obj); }
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l)      { rep.insert(f, l); }
+  void insert(const_iterator f, const_iterator l)    { rep.insert(f, l); }
+  // required for std::insert_iterator; the passed-in iterator is ignored
+  iterator insert(iterator, const value_type& obj)   { return insert(obj).first; }
+
+
+  // Deletion routines
+  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
+  // value to identify deleted buckets.  You can change the key as
+  // time goes on, or get rid of it entirely to be insert-only.
+  void set_deleted_key(const key_type& key)   {
+    rep.set_deleted_key(value_type(key, data_type()));  // rep wants a value
+  }
+  void clear_deleted_key()                    { rep.clear_deleted_key(); }
+
+  // These are standard
+  size_type erase(const key_type& key)               { return rep.erase(key); }
+  void erase(iterator it)                            { rep.erase(it); }
+  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
+
+
+  // Comparison
+  bool operator==(const sparse_hash_map& hs) const   { return rep == hs.rep; }
+  bool operator!=(const sparse_hash_map& hs) const   { return rep != hs.rep; }
+
+
+  // I/O -- this is an add-on for writing metainformation to disk
+  bool write_metadata(FILE *fp)       { return rep.write_metadata(fp); }
+  bool read_metadata(FILE *fp)        { return rep.read_metadata(fp); }
+  bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
+  bool read_nopointer_data(FILE *fp)  { return rep.read_nopointer_data(fp); }
+};
+
+// We need a global swap as well
+template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+inline void swap(sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
+                 sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
+  hm1.swap(hm2);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _SPARSE_HASH_MAP_H_ */
diff --git a/3rdparty/google/sparse_hash_set b/3rdparty/google/sparse_hash_set
new file mode 100644
index 0000000000..3c268ef564
--- /dev/null
+++ b/3rdparty/google/sparse_hash_set
@@ -0,0 +1,231 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// This is just a very thin wrapper over sparsehashtable.h, just
+// like sgi stl's stl_hash_set is a very thin wrapper over
+// stl_hashtable.  The major thing we define is operator[], because
+// we have a concept of a data_type which stl_hashtable doesn't
+// (it only has a key and a value).
+//
+// This is more different from sparse_hash_map than you might think,
+// because all iterators for sets are const (you obviously can't
+// change the key, and for sets there is no value).
+//
+// We adhere mostly to the STL semantics for hash-set.  One important
+// exception is that insert() invalidates iterators entirely.  On the
+// plus side, though, delete() doesn't invalidate iterators at all, or
+// even change the ordering of elements.
+//
+// Here are a few "power user" tips:
+//
+//    1) set_deleted_key():
+//         Unlike STL's hash_map, if you want to use erase() you
+//         must call set_deleted_key() after construction.
+//
+//    2) resize(0):
+//         When an item is deleted, its memory isn't freed right
+//         away.  This allows you to iterate over a hashtable,
+//         and call erase(), without invalidating the iterator.
+//         To force the memory to be freed, call resize(0).
+//
+//    3) set_resizing_parameters(0.0, 0.8):
+//         Setting the shrink_resize_percent to 0.0 guarantees
+//         that the hash table will never shrink.
+//
+// Guide to what kind of hash_set to use:
+//   (1) dense_hash_set: fastest, uses the most memory
+//   (2) sparse_hash_set: slowest, uses the least memory
+//   (3) hash_set (STL): in the middle
+// Typically I use sparse_hash_set when I care about space and/or when
+// I need to save the hashtable on disk.  I use hash_set otherwise.  I
+// don't personally use dense_hash_set ever; the only use of
+// dense_hash_set I know of is to work around malloc() bugs in some
+// systems (dense_hash_set has a particularly simple allocation scheme).
+//
+// - dense_hash_set has, typically, a factor of 2 memory overhead (if your
+//   data takes up X bytes, the hash_set uses X more bytes in overhead).
+// - sparse_hash_set has about 2 bits overhead per entry.
+// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
+//   especially, inserts.  See time_hash_map.cc for details.
+//
+// See /usr/(local/)?doc/sparsehash-0.1/sparse_hash_set.html
+// for information about how to use this class.
+
+#ifndef _SPARSE_HASH_SET_H_
+#define _SPARSE_HASH_SET_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <stdio.h>                    // for FILE * in read()/write()
+#include <algorithm>                  // for the default template args
+#include <functional>                // for equal_to
+#include <memory>                    // for alloc<>
+#include <utility>                   // for pair<>
+#include HASH_FUN_H                  // defined in config.h
+#include <google/sparsehash/sparsehashtable.h>
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+template <class Value,
+          class HashFcn = SPARSEHASH_HASH<Value>,  // defined in sparseconfig.h
+          class EqualKey = STL_NAMESPACE::equal_to<Value>,
+          class Alloc = STL_NAMESPACE::allocator<Value> >
+class sparse_hash_set {
+ private:
+  // Apparently identity is not stl-standard, so we define our own
+  struct Identity {
+    Value& operator()(Value& v) const { return v; }
+    const Value& operator()(const Value& v) const { return v; }
+  };
+
+  // The actual data
+  typedef sparse_hashtable<Value, Value, HashFcn, Identity, EqualKey, Alloc> ht;
+  ht rep;
+
+ public:
+  typedef typename ht::key_type key_type;
+  typedef typename ht::value_type value_type;
+  typedef typename ht::hasher hasher;
+  typedef typename ht::key_equal key_equal;
+
+  typedef typename ht::size_type size_type;
+  typedef typename ht::difference_type difference_type;
+  typedef typename ht::const_pointer pointer;
+  typedef typename ht::const_pointer const_pointer;
+  typedef typename ht::const_reference reference;
+  typedef typename ht::const_reference const_reference;
+
+  typedef typename ht::const_iterator iterator;
+  typedef typename ht::const_iterator const_iterator;
+
+
+  // Iterator functions -- recall all iterators are const
+  iterator begin() const              { return rep.begin(); }
+  iterator end() const                { return rep.end(); }
+
+
+  // Accessor functions
+  hasher hash_funct() const { return rep.hash_funct(); }
+  key_equal key_eq() const  { return rep.key_eq(); }
+
+
+  // Constructors
+  explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
+                           const hasher& hf = hasher(),
+                           const key_equal& eql = key_equal())
+    : rep(expected_max_items_in_table, hf, eql) { }
+
+  template <class InputIterator>
+  sparse_hash_set(InputIterator f, InputIterator l,
+                  size_type expected_max_items_in_table = 0,
+                  const hasher& hf = hasher(),
+                  const key_equal& eql = key_equal())
+      : rep(expected_max_items_in_table, hf, eql) {
+    rep.insert(f, l);
+  }
+  // We use the default copy constructor
+  // We use the default operator=()
+  // We use the default destructor
+
+  void clear()                        { rep.clear(); }
+  void swap(sparse_hash_set& hs)      { rep.swap(hs.rep); }
+
+
+  // Functions concerning size
+  size_type size() const              { return rep.size(); }
+  size_type max_size() const          { return rep.max_size(); }
+  bool empty() const                  { return rep.empty(); }
+  size_type bucket_count() const      { return rep.bucket_count(); }
+  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
+
+  void resize(size_type hint)         { rep.resize(hint); }
+
+  void set_resizing_parameters(float shrink, float grow) {
+    return rep.set_resizing_parameters(shrink, grow);
+  }
+
+  // Lookup routines
+  iterator find(const key_type& key) const           { return rep.find(key); }
+
+  size_type count(const key_type& key) const         { return rep.count(key); }
+
+  pair<iterator, iterator> equal_range(const key_type& key) const {
+    return rep.equal_range(key);
+  }
+
+  // Insertion routines
+  pair<iterator, bool> insert(const value_type& obj) {
+    pair<typename ht::iterator, bool> p = rep.insert(obj);
+    return pair<iterator, bool>(p.first, p.second);   // const to non-const
+  }
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l)      { rep.insert(f, l); }
+  void insert(const_iterator f, const_iterator l)    { rep.insert(f, l); }
+  // required for std::insert_iterator; the passed-in iterator is ignored
+  iterator insert(iterator, const value_type& obj)   { return insert(obj).first; }
+
+
+  // Deletion routines
+  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
+  // value to identify deleted buckets.  You can change the key as
+  // time goes on, or get rid of it entirely to be insert-only.
+  void set_deleted_key(const key_type& key)   { rep.set_deleted_key(key); }
+  void clear_deleted_key()                    { rep.clear_deleted_key(); }
+
+  // These are standard
+  size_type erase(const key_type& key)               { return rep.erase(key); }
+  void erase(iterator it)                            { rep.erase(it); }
+  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
+
+
+  // Comparison
+  bool operator==(const sparse_hash_set& hs) const   { return rep == hs.rep; }
+  bool operator!=(const sparse_hash_set& hs) const   { return rep != hs.rep; }
+
+
+  // I/O -- this is an add-on for writing metainformation to disk
+  bool write_metadata(FILE *fp)       { return rep.write_metadata(fp); }
+  bool read_metadata(FILE *fp)        { return rep.read_metadata(fp); }
+  bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
+  bool read_nopointer_data(FILE *fp)  { return rep.read_nopointer_data(fp); }
+};
+
+template <class Val, class HashFcn, class EqualKey, class Alloc>
+inline void swap(sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
+                 sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
+  hs1.swap(hs2);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _SPARSE_HASH_SET_H_ */
diff --git a/3rdparty/google/sparsehash/densehashtable.h b/3rdparty/google/sparsehash/densehashtable.h
new file mode 100644
index 0000000000..6ea1edc664
--- /dev/null
+++ b/3rdparty/google/sparsehash/densehashtable.h
@@ -0,0 +1,986 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// A dense hashtable is a particular implementation of
+// a hashtable: one that is meant to minimize memory allocation.
+// It does this by using an array to store all the data.  We
+// steal a value from the key space to indicate "empty" array
+// elements (ie indices where no item lives) and another to indicate
+// "deleted" elements.
+//
+// (Note it is possible to change the value of the delete key
+// on the fly; you can even remove it, though after that point
+// the hashtable is insert_only until you set it again.  The empty
+// value however can't be changed.)
+//
+// To minimize allocation and pointer overhead, we use internal
+// probing, in which the hashtable is a single table, and collisions
+// are resolved by trying to insert again in another bucket.  The
+// most cache-efficient internal probing schemes are linear probing
+// (which suffers, alas, from clumping) and quadratic probing, which
+// is what we implement by default.
+//
+// Type requirements: value_type is required to be Copy Constructible
+// and Default Constructible. It is not required to be (and commonly
+// isn't) Assignable.
+//
+// You probably shouldn't use this code directly.  Use
+// <google/dense_hash_map> or <google/dense_hash_set> instead.
+
+// You can change the following below:
+// HT_OCCUPANCY_FLT      -- how full before we double size
+// HT_EMPTY_FLT          -- how empty before we halve size
+// HT_MIN_BUCKETS        -- default smallest bucket size
+//
+// You can also change enlarge_resize_percent (which defaults to
+// HT_OCCUPANCY_FLT), and shrink_resize_percent (which defaults to
+// HT_EMPTY_FLT) with set_resizing_parameters().
+//
+// How to decide what values to use?
+// shrink_resize_percent's default of .4 * OCCUPANCY_FLT, is probably good.
+// HT_MIN_BUCKETS is probably unnecessary since you can specify
+// (indirectly) the starting number of buckets at construct-time.
+// For enlarge_resize_percent, you can use this chart to try to trade-off
+// expected lookup time to the space taken up.  By default, this
+// code uses quadratic probing, though you can change it to linear
+// via _JUMP below if you really want to.
+//
+// From http://www.augustana.ca/~mohrj/courses/1999.fall/csc210/lecture_notes/hashing.html
+// NUMBER OF PROBES / LOOKUP       Successful            Unsuccessful
+// Quadratic collision resolution   1 - ln(1-L) - L/2    1/(1-L) - L - ln(1-L)
+// Linear collision resolution     [1+1/(1-L)]/2         [1+1/(1-L)2]/2
+//
+// -- enlarge_resize_percent --         0.10  0.50  0.60  0.75  0.80  0.90  0.99
+// QUADRATIC COLLISION RES.
+//    probes/successful lookup    1.05  1.44  1.62  2.01  2.21  2.85  5.11
+//    probes/unsuccessful lookup  1.11  2.19  2.82  4.64  5.81  11.4  103.6
+// LINEAR COLLISION RES.
+//    probes/successful lookup    1.06  1.5   1.75  2.5   3.0   5.5   50.5
+//    probes/unsuccessful lookup  1.12  2.5   3.6   8.5   13.0  50.0  5000.0
+
+#ifndef _DENSEHASHTABLE_H_
+#define _DENSEHASHTABLE_H_
+
+// The probing method
+// Linear probing
+// #define JUMP_(key, num_probes)    ( 1 )
+// Quadratic-ish probing
+#define JUMP_(key, num_probes)    ( num_probes )
+
+
+// Hashtable class, used to implement the hashed associative containers
+// hash_set and hash_map.
+
+#include <google/sparsehash/sparseconfig.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>             // for abort()
+#include <algorithm>            // For swap(), eg
+#include <iostream>             // For cerr
+#include <memory>               // For uninitialized_fill, uninitialized_copy
+#include <utility>              // for pair<>
+#include <iterator>             // for facts about iterator tags
+#include <google/type_traits.h> // for true_type, integral_constant, etc.
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class EqualKey, class Alloc>
+class dense_hashtable;
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct dense_hashtable_iterator;
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct dense_hashtable_const_iterator;
+
+// We're just an array, but we need to skip over empty and deleted elements
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct dense_hashtable_iterator {
+ public:
+  typedef dense_hashtable_iterator<V,K,HF,ExK,EqK,A>       iterator;
+  typedef dense_hashtable_const_iterator<V,K,HF,ExK,EqK,A> const_iterator;
+
+  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
+  typedef V value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef V& reference;                // Value
+  typedef V* pointer;
+
+  // "Real" constructor and default constructor
+  dense_hashtable_iterator(const dense_hashtable<V,K,HF,ExK,EqK,A> *h,
+                           pointer it, pointer it_end, bool advance)
+    : ht(h), pos(it), end(it_end)   {
+    if (advance)  advance_past_empty_and_deleted();
+  }
+  dense_hashtable_iterator() { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on an empty or marked-deleted array element
+  void advance_past_empty_and_deleted() {
+    while ( pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)) )
+      ++pos;
+  }
+  iterator& operator++()   {
+    assert(pos != end); ++pos; advance_past_empty_and_deleted(); return *this;
+  }
+  iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
+
+  // Comparison.
+  bool operator==(const iterator& it) const { return pos == it.pos; }
+  bool operator!=(const iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const dense_hashtable<V,K,HF,ExK,EqK,A> *ht;
+  pointer pos, end;
+};
+
+
+// Now do it all again, but with const-ness!
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct dense_hashtable_const_iterator {
+ public:
+  typedef dense_hashtable_iterator<V,K,HF,ExK,EqK,A>       iterator;
+  typedef dense_hashtable_const_iterator<V,K,HF,ExK,EqK,A> const_iterator;
+
+  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
+  typedef V value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef const V& reference;                // Value
+  typedef const V* pointer;
+
+  // "Real" constructor and default constructor
+  dense_hashtable_const_iterator(const dense_hashtable<V,K,HF,ExK,EqK,A> *h,
+                                 pointer it, pointer it_end, bool advance)
+    : ht(h), pos(it), end(it_end)   {
+    if (advance)  advance_past_empty_and_deleted();
+  }
+  dense_hashtable_const_iterator() { }
+  // This lets us convert regular iterators to const iterators
+  dense_hashtable_const_iterator(const iterator &it)
+    : ht(it.ht), pos(it.pos), end(it.end) { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on an empty or marked-deleted array element
+  void advance_past_empty_and_deleted() {
+    while ( pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)) )
+      ++pos;
+  }
+  const_iterator& operator++()   {
+    assert(pos != end); ++pos; advance_past_empty_and_deleted(); return *this;
+  }
+  const_iterator operator++(int) { const_iterator tmp(*this); ++*this; return tmp; }
+
+  // Comparison.
+  bool operator==(const const_iterator& it) const { return pos == it.pos; }
+  bool operator!=(const const_iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const dense_hashtable<V,K,HF,ExK,EqK,A> *ht;
+  pointer pos, end;
+};
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class EqualKey, class Alloc>
+class dense_hashtable {
+ public:
+  typedef Key key_type;
+  typedef Value value_type;
+  typedef HashFcn hasher;
+  typedef EqualKey key_equal;
+
+  typedef size_t            size_type;
+  typedef ptrdiff_t         difference_type;
+  typedef value_type*       pointer;
+  typedef const value_type* const_pointer;
+  typedef value_type&       reference;
+  typedef const value_type& const_reference;
+  typedef dense_hashtable_iterator<Value, Key, HashFcn,
+                                   ExtractKey, EqualKey, Alloc>
+  iterator;
+
+  typedef dense_hashtable_const_iterator<Value, Key, HashFcn,
+                                          ExtractKey, EqualKey, Alloc>
+  const_iterator;
+
+  // How full we let the table get before we resize.  Knuth says .8 is
+  // good -- higher causes us to probe too much, though saves memory
+  static const float HT_OCCUPANCY_FLT; // = 0.8;
+
+  // How empty we let the table get before we resize lower.
+  // (0.0 means never resize lower.)
+  // It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
+  static const float HT_EMPTY_FLT; // = 0.4 * HT_OCCUPANCY_FLT
+
+  // Minimum size we're willing to let hashtables be.
+  // Must be a power of two, and at least 4.
+  // Note, however, that for a given hashtable, the initial size is a
+  // function of the first constructor arg, and may be >HT_MIN_BUCKETS.
+  static const size_t HT_MIN_BUCKETS = 4;
+
+  // By default, if you don't specify a hashtable size at
+  // construction-time, we use this size.  Must be a power of two, and
+  // at least HT_MIN_BUCKETS.
+  static const size_t HT_DEFAULT_STARTING_BUCKETS = 32;
+
+
+  // ITERATOR FUNCTIONS
+  iterator begin()             { return iterator(this, table,
+                                                 table + num_buckets, true); }
+  iterator end()               { return iterator(this, table + num_buckets,
+                                                 table + num_buckets, true); }
+  const_iterator begin() const { return const_iterator(this, table,
+                                                       table+num_buckets,true);}
+  const_iterator end() const   { return const_iterator(this, table + num_buckets,
+                                                       table+num_buckets,true);}
+
+  // ACCESSOR FUNCTIONS for the things we templatize on, basically
+  hasher hash_funct() const { return hash; }
+  key_equal key_eq() const  { return equals; }
+
+  // Annoyingly, we can't copy values around, because they might have
+  // const components (they're probably pair<const X, Y>).  We use
+  // explicit destructor invocation and placement new to get around
+  // this.  Arg.
+ private:
+  void set_value(value_type* dst, const value_type& src) {
+    dst->~value_type();
+    new(dst) value_type(src);
+  }
+
+  void destroy_buckets(size_type first, size_type last) {
+    for ( ; first != last; ++first)
+      table[first].~value_type();
+  }
+
+  // DELETE HELPER FUNCTIONS
+  // This lets the user describe a key that will indicate deleted
+  // table entries.  This key should be an "impossible" entry --
+  // if you try to insert it for real, you won't be able to retrieve it!
+  // (NB: while you pass in an entire value, only the key part is looked
+  // at.  This is just because I don't know how to assign just a key.)
+ private:
+  void squash_deleted() {           // gets rid of any deleted entries we have
+    if ( num_deleted ) {            // get rid of deleted before writing
+      dense_hashtable tmp(*this);   // copying will get rid of deleted
+      swap(tmp);                    // now we are tmp
+    }
+    assert(num_deleted == 0);
+  }
+
+ public:
+  void set_deleted_key(const value_type &val) {
+    // the empty indicator (if specified) and the deleted indicator
+    // must be different
+    assert(!use_empty || !equals(get_key(val), get_key(emptyval)));
+    // It's only safe to change what "deleted" means if we purge deleted guys
+    squash_deleted();
+    use_deleted = true;
+    set_value(&delval, val);
+  }
+  void clear_deleted_key() {
+    squash_deleted();
+    use_deleted = false;
+  }
+
+  // These are public so the iterators can use them
+  // True if the item at position bucknum is "deleted" marker
+  bool test_deleted(size_type bucknum) const {
+    // The num_deleted test is crucial for read(): after read(), the ht values
+    // are garbage, and we don't want to think some of them are deleted.
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(table[bucknum])));
+  }
+  bool test_deleted(const iterator &it) const {
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(*it)));
+  }
+  bool test_deleted(const const_iterator &it) const {
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(*it)));
+  }
+  // Set it so test_deleted is true.  true if object didn't used to be deleted
+  // See below (at erase()) to explain why we allow const_iterators
+  bool set_deleted(const_iterator &it) {
+    assert(use_deleted);             // bad if set_deleted_key() wasn't called
+    bool retval = !test_deleted(it);
+    // &* converts from iterator to value-type
+    set_value(const_cast<value_type*>(&(*it)), delval);
+    return retval;
+  }
+  // Set it so test_deleted is false.  true if object used to be deleted
+  bool clear_deleted(const_iterator &it) {
+    assert(use_deleted);             // bad if set_deleted_key() wasn't called
+    // happens automatically when we assign something else in its place
+    return test_deleted(it);
+  }
+
+  // EMPTY HELPER FUNCTIONS
+  // This lets the user describe a key that will indicate empty (unused)
+  // table entries.  This key should be an "impossible" entry --
+  // if you try to insert it for real, you won't be able to retrieve it!
+  // (NB: while you pass in an entire value, only the key part is looked
+  // at.  This is just because I don't know how to assign just a key.)
+ public:
+  // These are public so the iterators can use them
+  // True if the item at position bucknum is "empty" marker
+  bool test_empty(size_type bucknum) const {
+    assert(use_empty);              // we always need to know what's empty!
+    return equals(get_key(emptyval), get_key(table[bucknum]));
+  }
+  bool test_empty(const iterator &it) const {
+    assert(use_empty);              // we always need to know what's empty!
+    return equals(get_key(emptyval), get_key(*it));
+  }
+  bool test_empty(const const_iterator &it) const {
+    assert(use_empty);              // we always need to know what's empty!
+    return equals(get_key(emptyval), get_key(*it));
+  }
+
+ private:
+  // You can either set a range empty or an individual element
+  void set_empty(size_type bucknum) {
+    assert(use_empty);
+    set_value(&table[bucknum], emptyval);
+  }
+  void fill_range_with_empty(value_type* table_start, value_type* table_end) {
+    // Like set_empty(range), but doesn't destroy previous contents
+    STL_NAMESPACE::uninitialized_fill(table_start, table_end, emptyval);
+  }
+  void set_empty(size_type buckstart, size_type buckend) {
+    assert(use_empty);
+    destroy_buckets(buckstart, buckend);
+    fill_range_with_empty(table + buckstart, table + buckend);
+  }
+
+ public:
+  // TODO(csilvers): change all callers of this to pass in a key instead,
+  //                 and take a const key_type instead of const value_type.
+  void set_empty_key(const value_type &val) {
+    // Once you set the empty key, you can't change it
+    assert(!use_empty);
+    // The deleted indicator (if specified) and the empty indicator
+    // must be different.
+    assert(!use_deleted || !equals(get_key(val), get_key(delval)));
+    use_empty = true;
+    set_value(&emptyval, val);
+
+    assert(!table);                  // must set before first use
+    // num_buckets was set in constructor even though table was NULL
+    table = (value_type *) malloc(num_buckets * sizeof(*table));
+    assert(table);
+    fill_range_with_empty(table, table + num_buckets);
+  }
+
+  // FUNCTIONS CONCERNING SIZE
+ public:
+  size_type size() const      { return num_elements - num_deleted; }
+  // Buckets are always a power of 2
+  size_type max_size() const  { return (size_type(-1) >> 1U) + 1; }
+  bool empty() const          { return size() == 0; }
+  size_type bucket_count() const      { return num_buckets; }
+  size_type max_bucket_count() const  { return max_size(); }
+  size_type nonempty_bucket_count() const { return num_elements; }
+
+ private:
+  // Because of the above, size_type(-1) is never legal; use it for errors
+  static const size_type ILLEGAL_BUCKET = size_type(-1);
+
+ private:
+  // This is the smallest size a hashtable can be without being too crowded
+  // If you like, you can give a min #buckets as well as a min #elts
+  size_type min_size(size_type num_elts, size_type min_buckets_wanted) {
+    size_type sz = HT_MIN_BUCKETS;             // min buckets allowed
+    while ( sz < min_buckets_wanted || num_elts >= sz * enlarge_resize_percent )
+      sz *= 2;
+    return sz;
+  }
+
+  // Used after a string of deletes
+  void maybe_shrink() {
+    assert(num_elements >= num_deleted);
+    assert((bucket_count() & (bucket_count()-1)) == 0); // is a power of two
+    assert(bucket_count() >= HT_MIN_BUCKETS);
+
+    // If you construct a hashtable with < HT_DEFAULT_STARTING_BUCKETS,
+    // we'll never shrink until you get relatively big, and we'll never
+    // shrink below HT_DEFAULT_STARTING_BUCKETS.  Otherwise, something
+    // like "dense_hash_set<int> x; x.insert(4); x.erase(4);" will
+    // shrink us down to HT_MIN_BUCKETS buckets, which is too small.
+    if (shrink_threshold > 0 &&
+        (num_elements-num_deleted) < shrink_threshold &&
+        bucket_count() > HT_DEFAULT_STARTING_BUCKETS ) {
+      size_type sz = bucket_count() / 2;    // find how much we should shrink
+      while ( sz > HT_DEFAULT_STARTING_BUCKETS &&
+              (num_elements - num_deleted) < sz * shrink_resize_percent )
+        sz /= 2;                            // stay a power of 2
+      dense_hashtable tmp(*this, sz);       // Do the actual resizing
+      swap(tmp);                            // now we are tmp
+    }
+    consider_shrink = false;                // because we just considered it
+  }
+
+  // We'll let you resize a hashtable -- though this makes us copy all!
+  // When you resize, you say, "make it big enough for this many more elements"
+  void resize_delta(size_type delta) {
+    if ( consider_shrink )                   // see if lots of deletes happened
+      maybe_shrink();
+    if ( bucket_count() > HT_MIN_BUCKETS &&
+         (num_elements + delta) <= enlarge_threshold )
+      return;                                // we're ok as we are
+
+    // Sometimes, we need to resize just to get rid of all the
+    // "deleted" buckets that are clogging up the hashtable.  So when
+    // deciding whether to resize, count the deleted buckets (which
+    // are currently taking up room).  But later, when we decide what
+    // size to resize to, *don't* count deleted buckets, since they
+    // get discarded during the resize.
+    const size_type needed_size = min_size(num_elements + delta, 0);
+    if ( needed_size > bucket_count() ) {      // we don't have enough buckets
+      const size_type resize_to = min_size(num_elements - num_deleted + delta,
+                                           0);
+      dense_hashtable tmp(*this, resize_to);
+      swap(tmp);                             // now we are tmp
+    }
+  }
+
+  // Increase number of buckets, assuming value_type has trivial copy
+  // constructor and destructor.  (Really, we want it to have "trivial
+  // move", because that's what realloc does.  But there's no way to
+  // capture that using type_traits, so we pretend that move(x, y) is
+  // equivalent to "x.~T(); new(x) T(y);" which is pretty much
+  // correct, if a bit conservative.)
+  void expand_array(size_t resize_to, true_type) {
+    table = (value_type *) realloc(table, resize_to * sizeof(value_type));
+    assert(table);
+    fill_range_with_empty(table + num_buckets, table + resize_to);
+  }
+
+  // Increase number of buckets, without special assumptions about value_type.
+  // TODO(austern): make this exception safe. Handle exceptions from
+  // value_type's copy constructor.
+  void expand_array(size_t resize_to, false_type) {
+    value_type* new_table =
+      (value_type *) malloc(resize_to * sizeof(value_type));
+    assert(new_table);
+    STL_NAMESPACE::uninitialized_copy(table, table + num_buckets, new_table);
+    fill_range_with_empty(new_table + num_buckets, new_table + resize_to);
+    destroy_buckets(0, num_buckets);
+    free(table);
+    table = new_table;
+  }
+
+  // Used to actually do the rehashing when we grow/shrink a hashtable
+  void copy_from(const dense_hashtable &ht, size_type min_buckets_wanted) {
+    clear();            // clear table, set num_deleted to 0
+
+    // If we need to change the size of our table, do it now
+    const size_type resize_to = min_size(ht.size(), min_buckets_wanted);
+    if ( resize_to > bucket_count() ) { // we don't have enough buckets
+      typedef integral_constant<bool,
+          (has_trivial_copy<value_type>::value &&
+           has_trivial_destructor<value_type>::value)>
+          realloc_ok; // we pretend mv(x,y) == "x.~T(); new(x) T(y)"
+      expand_array(resize_to, realloc_ok());
+      num_buckets = resize_to;
+      reset_thresholds();
+    }
+
+    // We use a normal iterator to get non-deleted bcks from ht
+    // We could use insert() here, but since we know there are
+    // no duplicates and no deleted items, we can be more efficient
+    assert((bucket_count() & (bucket_count()-1)) == 0);      // a power of two
+    for ( const_iterator it = ht.begin(); it != ht.end(); ++it ) {
+      size_type num_probes = 0;              // how many times we've probed
+      size_type bucknum;
+      const size_type bucket_count_minus_one = bucket_count() - 1;
+      for (bucknum = hash(get_key(*it)) & bucket_count_minus_one;
+           !test_empty(bucknum);                               // not empty
+           bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one) {
+        ++num_probes;
+        assert(num_probes < bucket_count()); // or else the hashtable is full
+      }
+      set_value(&table[bucknum], *it);       // copies the value to here
+      num_elements++;
+    }
+  }
+
+  // Required by the spec for hashed associative container
+ public:
+  // Though the docs say this should be num_buckets, I think it's much
+  // more useful as req_elements.  As a special feature, calling with
+  // req_elements==0 will cause us to shrink if we can, saving space.
+  void resize(size_type req_elements) {       // resize to this or larger
+    if ( consider_shrink || req_elements == 0 )
+      maybe_shrink();
+    if ( req_elements > num_elements )
+      return resize_delta(req_elements - num_elements);
+  }
+
+  // Change the value of shrink_resize_percent and
+  // enlarge_resize_percent.  The description at the beginning of this
+  // file explains how to choose the values.  Setting the shrink
+  // parameter to 0.0 ensures that the table never shrinks.
+  void set_resizing_parameters(float shrink, float grow) {
+    assert(shrink >= 0.0);
+    assert(grow <= 1.0);
+    assert(shrink <= grow/2.0);
+    shrink_resize_percent = shrink;
+    enlarge_resize_percent = grow;
+    reset_thresholds();
+  }
+
+  // CONSTRUCTORS -- as required by the specs, we take a size,
+  // but also let you specify a hashfunction, key comparator,
+  // and key extractor.  We also define a copy constructor and =.
+  // DESTRUCTOR -- needs to free the table
+  explicit dense_hashtable(size_type expected_max_items_in_table = 0,
+                           const HashFcn& hf = HashFcn(),
+                           const EqualKey& eql = EqualKey(),
+                           const ExtractKey& ext = ExtractKey())
+    : hash(hf), equals(eql), get_key(ext), num_deleted(0),
+      use_deleted(false), use_empty(false),
+      delval(), emptyval(), enlarge_resize_percent(HT_OCCUPANCY_FLT),
+      shrink_resize_percent(HT_EMPTY_FLT), table(NULL),
+      num_buckets(expected_max_items_in_table == 0
+                  ? HT_DEFAULT_STARTING_BUCKETS
+                  : min_size(expected_max_items_in_table, 0)),
+      num_elements(0) {
+    // table is NULL until emptyval is set.  However, we set num_buckets
+    // here so we know how much space to allocate once emptyval is set
+    reset_thresholds();
+  }
+
+  // As a convenience for resize(), we allow an optional second argument
+  // which lets you make this new hashtable a different size than ht
+  dense_hashtable(const dense_hashtable& ht,
+                  size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
+    : hash(ht.hash), equals(ht.equals), get_key(ht.get_key), num_deleted(0),
+      use_deleted(ht.use_deleted), use_empty(ht.use_empty),
+      delval(ht.delval), emptyval(ht.emptyval),
+      enlarge_resize_percent(ht.enlarge_resize_percent),
+      shrink_resize_percent(ht.shrink_resize_percent), table(NULL),
+      num_buckets(0), num_elements(0) {
+    reset_thresholds();
+    copy_from(ht, min_buckets_wanted);   // copy_from() ignores deleted entries
+  }
+
+  dense_hashtable& operator= (const dense_hashtable& ht) {
+    if (&ht == this)  return *this;        // don't copy onto ourselves
+    clear();
+    hash = ht.hash;
+    equals = ht.equals;
+    get_key = ht.get_key;
+    use_deleted = ht.use_deleted;
+    use_empty = ht.use_empty;
+    set_value(&delval, ht.delval);
+    set_value(&emptyval, ht.emptyval);
+    enlarge_resize_percent = ht.enlarge_resize_percent;
+    shrink_resize_percent = ht.shrink_resize_percent;
+    copy_from(ht, HT_MIN_BUCKETS);         // sets num_deleted to 0 too
+    return *this;
+  }
+
+  ~dense_hashtable() {
+    if (table) {
+      destroy_buckets(0, num_buckets);
+      free(table);
+    }
+  }
+
+  // Many STL algorithms use swap instead of copy constructors
+  void swap(dense_hashtable& ht) {
+    STL_NAMESPACE::swap(hash, ht.hash);
+    STL_NAMESPACE::swap(equals, ht.equals);
+    STL_NAMESPACE::swap(get_key, ht.get_key);
+    STL_NAMESPACE::swap(num_deleted, ht.num_deleted);
+    STL_NAMESPACE::swap(use_deleted, ht.use_deleted);
+    STL_NAMESPACE::swap(use_empty, ht.use_empty);
+    STL_NAMESPACE::swap(enlarge_resize_percent, ht.enlarge_resize_percent);
+    STL_NAMESPACE::swap(shrink_resize_percent, ht.shrink_resize_percent);
+    { value_type tmp;     // for annoying reasons, swap() doesn't work
+      set_value(&tmp, delval);
+      set_value(&delval, ht.delval);
+      set_value(&ht.delval, tmp);
+    }
+    { value_type tmp;     // for annoying reasons, swap() doesn't work
+      set_value(&tmp, emptyval);
+      set_value(&emptyval, ht.emptyval);
+      set_value(&ht.emptyval, tmp);
+    }
+    STL_NAMESPACE::swap(table, ht.table);
+    STL_NAMESPACE::swap(num_buckets, ht.num_buckets);
+    STL_NAMESPACE::swap(num_elements, ht.num_elements);
+    reset_thresholds();
+    ht.reset_thresholds();
+  }
+
+  // It's always nice to be able to clear a table without deallocating it
+  void clear() {
+    if (table)
+      destroy_buckets(0, num_buckets);
+    num_buckets = min_size(0,0);          // our new size
+    reset_thresholds();
+    table = (value_type *) realloc(table, num_buckets * sizeof(*table));
+    assert(table);
+    fill_range_with_empty(table, table + num_buckets);
+    num_elements = 0;
+    num_deleted = 0;
+  }
+
+  // Clear the table without resizing it.
+  // Mimicks the stl_hashtable's behaviour when clear()-ing in that it
+  // does not modify the bucket count
+  void clear_no_resize() {
+    if (table) {
+      set_empty(0, num_buckets);
+    }
+    // don't consider to shrink before another erase()
+    reset_thresholds();
+    num_elements = 0;
+    num_deleted = 0;
+  }
+
+  // LOOKUP ROUTINES
+ private:
+  // Returns a pair of positions: 1st where the object is, 2nd where
+  // it would go if you wanted to insert it.  1st is ILLEGAL_BUCKET
+  // if object is not found; 2nd is ILLEGAL_BUCKET if it is.
+  // Note: because of deletions where-to-insert is not trivial: it's the
+  // first deleted bucket we see, as long as we don't find the key later
+  pair<size_type, size_type> find_position(const key_type &key) const {
+    size_type num_probes = 0;              // how many times we've probed
+    const size_type bucket_count_minus_one = bucket_count() - 1;
+    size_type bucknum = hash(key) & bucket_count_minus_one;
+    size_type insert_pos = ILLEGAL_BUCKET; // where we would insert
+    while ( 1 ) {                          // probe until something happens
+      if ( test_empty(bucknum) ) {         // bucket is empty
+        if ( insert_pos == ILLEGAL_BUCKET )   // found no prior place to insert
+          return pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
+        else
+          return pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
+
+      } else if ( test_deleted(bucknum) ) {// keep searching, but mark to insert
+        if ( insert_pos == ILLEGAL_BUCKET )
+          insert_pos = bucknum;
+
+      } else if ( equals(key, get_key(table[bucknum])) ) {
+        return pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
+      }
+      ++num_probes;                        // we're doing another probe
+      bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
+      assert(num_probes < bucket_count()); // don't probe too many times!
+    }
+  }
+
+ public:
+  iterator find(const key_type& key) {
+    if ( size() == 0 ) return end();
+    pair<size_type, size_type> pos = find_position(key);
+    if ( pos.first == ILLEGAL_BUCKET )     // alas, not there
+      return end();
+    else
+      return iterator(this, table + pos.first, table + num_buckets, false);
+  }
+
+  const_iterator find(const key_type& key) const {
+    if ( size() == 0 ) return end();
+    pair<size_type, size_type> pos = find_position(key);
+    if ( pos.first == ILLEGAL_BUCKET )     // alas, not there
+      return end();
+    else
+      return const_iterator(this, table + pos.first, table+num_buckets, false);
+  }
+
+  // Counts how many elements have key key.  For maps, it's either 0 or 1.
+  size_type count(const key_type &key) const {
+    pair<size_type, size_type> pos = find_position(key);
+    return pos.first == ILLEGAL_BUCKET ? 0 : 1;
+  }
+
+  // Likewise, equal_range doesn't really make sense for us.  Oh well.
+  pair<iterator,iterator> equal_range(const key_type& key) {
+    const iterator pos = find(key);      // either an iterator or end
+    return pair<iterator,iterator>(pos, pos);
+  }
+  pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
+    const const_iterator pos = find(key);      // either an iterator or end
+    return pair<iterator,iterator>(pos, pos);
+  }
+
+
+  // INSERTION ROUTINES
+ private:
+  // If you know *this is big enough to hold obj, use this routine
+  pair<iterator, bool> insert_noresize(const value_type& obj) {
+    // First, double-check we're not inserting delval or emptyval
+    assert(!use_empty || !equals(get_key(obj), get_key(emptyval)));
+    assert(!use_deleted || !equals(get_key(obj), get_key(delval)));
+    const pair<size_type,size_type> pos = find_position(get_key(obj));
+    if ( pos.first != ILLEGAL_BUCKET) {      // object was already there
+      return pair<iterator,bool>(iterator(this, table + pos.first,
+                                          table + num_buckets, false),
+                                 false);          // false: we didn't insert
+    } else {                                 // pos.second says where to put it
+      if ( test_deleted(pos.second) ) {      // just replace if it's been del.
+        const_iterator delpos(this, table + pos.second,              // shrug:
+                              table + num_buckets, false);// shouldn't need const
+        clear_deleted(delpos);
+        assert( num_deleted > 0);
+        --num_deleted;                       // used to be, now it isn't
+      } else {
+        ++num_elements;                      // replacing an empty bucket
+      }
+      set_value(&table[pos.second], obj);
+      return pair<iterator,bool>(iterator(this, table + pos.second,
+                                          table + num_buckets, false),
+                                 true);           // true: we did insert
+    }
+  }
+
+ public:
+  // This is the normal insert routine, used by the outside world
+  pair<iterator, bool> insert(const value_type& obj) {
+    resize_delta(1);                      // adding an object, grow if need be
+    return insert_noresize(obj);
+  }
+
+  // When inserting a lot at a time, we specialize on the type of iterator
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    // specializes on iterator type
+    insert(f, l, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
+  }
+
+  // Iterator supports operator-, resize before inserting
+  template <class ForwardIterator>
+  void insert(ForwardIterator f, ForwardIterator l,
+              STL_NAMESPACE::forward_iterator_tag) {
+    size_type n = STL_NAMESPACE::distance(f, l);   // TODO(csilvers): standard?
+    resize_delta(n);
+    for ( ; n > 0; --n, ++f)
+      insert_noresize(*f);
+  }
+
+  // Arbitrary iterator, can't tell how much to resize
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l,
+              STL_NAMESPACE::input_iterator_tag) {
+    for ( ; f != l; ++f)
+      insert(*f);
+  }
+
+
+  // DELETION ROUTINES
+  size_type erase(const key_type& key) {
+    // First, double-check we're not trying to erase delval or emptyval
+    assert(!use_empty || !equals(key, get_key(emptyval)));
+    assert(!use_deleted || !equals(key, get_key(delval)));
+    const_iterator pos = find(key);   // shrug: shouldn't need to be const
+    if ( pos != end() ) {
+      assert(!test_deleted(pos));  // or find() shouldn't have returned it
+      set_deleted(pos);
+      ++num_deleted;
+      consider_shrink = true;      // will think about shrink after next insert
+      return 1;                    // because we deleted one thing
+    } else {
+      return 0;                    // because we deleted nothing
+    }
+  }
+
+  // This is really evil: really it should be iterator, not const_iterator.
+  // But...the only reason keys are const is to allow lookup.
+  // Since that's a moot issue for deleted keys, we allow const_iterators
+  void erase(const_iterator pos) {
+    if ( pos == end() ) return;    // sanity check
+    if ( set_deleted(pos) ) {      // true if object has been newly deleted
+      ++num_deleted;
+      consider_shrink = true;      // will think about shrink after next insert
+    }
+  }
+
+  void erase(const_iterator f, const_iterator l) {
+    for ( ; f != l; ++f) {
+      if ( set_deleted(f)  )       // should always be true
+        ++num_deleted;
+    }
+    consider_shrink = true;        // will think about shrink after next insert
+  }
+
+
+  // COMPARISON
+  bool operator==(const dense_hashtable& ht) const {
+    if (size() != ht.size()) {
+      return false;
+    } else if (this == &ht) {
+      return true;
+    } else {
+      // Iterate through the elements in "this" and see if the
+      // corresponding element is in ht
+      for ( const_iterator it = begin(); it != end(); ++it ) {
+        const_iterator it2 = ht.find(get_key(*it));
+        if ((it2 == ht.end()) || (*it != *it2)) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  bool operator!=(const dense_hashtable& ht) const {
+    return !(*this == ht);
+  }
+
+
+  // I/O
+  // We support reading and writing hashtables to disk.  Alas, since
+  // I don't know how to write a hasher or key_equal, you have to make
+  // sure everything but the table is the same.  We compact before writing
+  //
+  // NOTE: These functions are currently TODO.  They've not been implemented.
+  bool write_metadata(FILE *fp) {
+    squash_deleted();           // so we don't have to worry about delval
+    return false;               // TODO
+  }
+
+  bool read_metadata(FILE *fp) {
+    num_deleted = 0;            // since we got rid before writing
+    assert(use_empty);          // have to set this before calling us
+    if (table)  free(table);    // we'll make our own
+    // TODO: read magic number
+    // TODO: read num_buckets
+    reset_thresholds();
+    table = (value_type *) malloc(num_buckets * sizeof(*table));
+    assert(table);
+    fill_range_with_empty(table, table + num_buckets);
+    // TODO: read num_elements
+    for ( size_type i = 0; i < num_elements; ++i ) {
+      // TODO: read bucket_num
+      // TODO: set with non-empty, non-deleted value
+    }
+    return false;               // TODO
+  }
+
+  // If your keys and values are simple enough, we can write them to
+  // disk for you.  "simple enough" means value_type is a POD type
+  // that contains no pointers.  However, we don't try to normalize
+  // endianness
+  bool write_nopointer_data(FILE *fp) const {
+    for ( const_iterator it = begin(); it != end(); ++it ) {
+      // TODO: skip empty/deleted values
+      if ( !fwrite(&*it, sizeof(*it), 1, fp) )  return false;
+    }
+    return false;
+  }
+
+  // When reading, we have to override the potential const-ness of *it
+  bool read_nopointer_data(FILE *fp) {
+    for ( iterator it = begin(); it != end(); ++it ) {
+      // TODO: skip empty/deleted values
+      if ( !fread(reinterpret_cast<void*>(&(*it)), sizeof(*it), 1, fp) )
+        return false;
+    }
+    return false;
+  }
+
+ private:
+  // The actual data
+  hasher hash;                      // required by hashed_associative_container
+  key_equal equals;
+  ExtractKey get_key;
+  size_type num_deleted;        // how many occupied buckets are marked deleted
+  bool use_deleted;                          // false until delval has been set
+  bool use_empty;                          // you must do this before you start
+  value_type delval;                         // which key marks deleted entries
+  value_type emptyval;                        // which key marks unused entries
+  float enlarge_resize_percent;                       // how full before resize
+  float shrink_resize_percent;                       // how empty before resize
+  size_type shrink_threshold;            // num_buckets * shrink_resize_percent
+  size_type enlarge_threshold;          // num_buckets * enlarge_resize_percent
+  value_type *table;
+  size_type num_buckets;
+  size_type num_elements;
+  bool consider_shrink;   // true if we should try to shrink before next insert
+
+  void reset_thresholds() {
+    enlarge_threshold = static_cast<size_type>(num_buckets
+                                               * enlarge_resize_percent);
+    shrink_threshold = static_cast<size_type>(num_buckets
+                                              * shrink_resize_percent);
+    consider_shrink = false;   // whatever caused us to reset already considered
+  }
+};
+
+// We need a global swap as well
+template <class V, class K, class HF, class ExK, class EqK, class A>
+inline void swap(dense_hashtable<V,K,HF,ExK,EqK,A> &x,
+                 dense_hashtable<V,K,HF,ExK,EqK,A> &y) {
+  x.swap(y);
+}
+
+#undef JUMP_
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const typename dense_hashtable<V,K,HF,ExK,EqK,A>::size_type
+  dense_hashtable<V,K,HF,ExK,EqK,A>::ILLEGAL_BUCKET;
+
+// How full we let the table get before we resize.  Knuth says .8 is
+// good -- higher causes us to probe too much, though saves memory
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const float dense_hashtable<V,K,HF,ExK,EqK,A>::HT_OCCUPANCY_FLT = 0.5f;
+
+// How empty we let the table get before we resize lower.
+// It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const float dense_hashtable<V,K,HF,ExK,EqK,A>::HT_EMPTY_FLT = 0.4f *
+dense_hashtable<V,K,HF,ExK,EqK,A>::HT_OCCUPANCY_FLT;
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _DENSEHASHTABLE_H_ */
diff --git a/3rdparty/google/sparsehash/sparseconfig.h b/3rdparty/google/sparsehash/sparseconfig.h
new file mode 100644
index 0000000000..0ae597ed5b
--- /dev/null
+++ b/3rdparty/google/sparsehash/sparseconfig.h
@@ -0,0 +1,74 @@
+#ifndef SPARSEHASH_SPARSECONFIG_H__
+#define SPARSEHASH_SPARSECONFIG_H__
+
+// [AIR] : I couldn't make the google "windows" folder concept work.
+// This does, and we only care of GCC and MSVC right now anyway.
+
+#if defined( _MSC_VER )
+
+	#define GOOGLE_NAMESPACE  google
+	#define HASH_NAMESPACE  stdext
+	#define HASH_FUN_H   <hash_map>
+	#define SPARSEHASH_HASH  HASH_NAMESPACE::hash_compare
+	#undef HAVE_UINT16_T
+	#undef HAVE_U_INT16_T
+	#define HAVE___UINT16  1
+	#define HAVE_LONG_LONG  1
+	#define HAVE_SYS_TYPES_H  1
+	#undef HAVE_STDINT_H
+	#undef HAVE_INTTYPES_H
+	#define HAVE_MEMCPY  1
+	#define STL_NAMESPACE  std
+	#define _END_GOOGLE_NAMESPACE_  }
+	#define _START_GOOGLE_NAMESPACE_  namespace GOOGLE_NAMESPACE {
+
+#else    //if defined( GNUC )
+
+	/* Namespace for Google classes */
+	#define GOOGLE_NAMESPACE google
+
+	/* the location of <hash_fun.h>/<stl_hash_fun.h> */
+	#define HASH_FUN_H <ext/hash_fun.h>
+
+	/* the namespace of hash_map/hash_set */
+	#define HASH_NAMESPACE __gnu_cxx
+
+	/* Define to 1 if you have the <inttypes.h> header file. */
+	#define HAVE_INTTYPES_H 1
+
+	/* Define to 1 if the system has the type `long long'. */
+	#define HAVE_LONG_LONG 1
+
+	/* Define to 1 if you have the `memcpy' function. */
+	#define HAVE_MEMCPY 1
+
+	/* Define to 1 if you have the <stdint.h> header file. */
+	#define HAVE_STDINT_H 1
+
+	/* Define to 1 if you have the <sys/types.h> header file. */
+	#define HAVE_SYS_TYPES_H 1
+
+	/* Define to 1 if the system has the type `uint16_t'. */
+	#define HAVE_UINT16_T 1
+
+	/* Define to 1 if the system has the type `u_int16_t'. */
+	#define HAVE_U_INT16_T 1
+
+	/* Define to 1 if the system has the type `__uint16'. */
+	/* #undef HAVE___UINT16 */
+
+	/* The system-provided hash function including the namespace. */
+	#define SPARSEHASH_HASH HASH_NAMESPACE::hash
+
+	/* the namespace where STL code like vector<> is defined */
+	#define STL_NAMESPACE std
+
+	/* Stops putting the code inside the Google namespace */
+	#define _END_GOOGLE_NAMESPACE_ }
+
+	/* Puts following code inside the Google namespace */
+	#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#endif
+
+#endif
diff --git a/3rdparty/google/sparsehash/sparsehashtable.h b/3rdparty/google/sparsehash/sparsehashtable.h
new file mode 100644
index 0000000000..28e8ba7d4f
--- /dev/null
+++ b/3rdparty/google/sparsehash/sparsehashtable.h
@@ -0,0 +1,941 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// A sparse hashtable is a particular implementation of
+// a hashtable: one that is meant to minimize memory use.
+// It does this by using a *sparse table* (cf sparsetable.h),
+// which uses between 1 and 2 bits to store empty buckets
+// (we may need another bit for hashtables that support deletion).
+//
+// When empty buckets are so cheap, an appealing hashtable
+// implementation is internal probing, in which the hashtable
+// is a single table, and collisions are resolved by trying
+// to insert again in another bucket.  The most cache-efficient
+// internal probing schemes are linear probing (which suffers,
+// alas, from clumping) and quadratic probing, which is what
+// we implement by default.
+//
+// Deleted buckets are a bit of a pain.  We have to somehow mark
+// deleted buckets (the probing must distinguish them from empty
+// buckets).  The most principled way is to have another bitmap,
+// but that's annoying and takes up space.  Instead we let the
+// user specify an "impossible" key.  We set deleted buckets
+// to have the impossible key.
+//
+// Note it is possible to change the value of the delete key
+// on the fly; you can even remove it, though after that point
+// the hashtable is insert_only until you set it again.
+//
+// You probably shouldn't use this code directly.  Use
+// <google/sparse_hash_table> or <google/sparse_hash_set> instead.
+//
+// You can modify the following, below:
+// HT_OCCUPANCY_FLT            -- how full before we double size
+// HT_EMPTY_FLT                -- how empty before we halve size
+// HT_MIN_BUCKETS              -- smallest bucket size
+// HT_DEFAULT_STARTING_BUCKETS -- default bucket size at construct-time
+//
+// You can also change enlarge_resize_percent (which defaults to
+// HT_OCCUPANCY_FLT), and shrink_resize_percent (which defaults to
+// HT_EMPTY_FLT) with set_resizing_parameters().
+//
+// How to decide what values to use?
+// shrink_resize_percent's default of .4 * OCCUPANCY_FLT, is probably good.
+// HT_MIN_BUCKETS is probably unnecessary since you can specify
+// (indirectly) the starting number of buckets at construct-time.
+// For enlarge_resize_percent, you can use this chart to try to trade-off
+// expected lookup time to the space taken up.  By default, this
+// code uses quadratic probing, though you can change it to linear
+// via _JUMP below if you really want to.
+//
+// From http://www.augustana.ca/~mohrj/courses/1999.fall/csc210/lecture_notes/hashing.html
+// NUMBER OF PROBES / LOOKUP       Successful            Unsuccessful
+// Quadratic collision resolution   1 - ln(1-L) - L/2    1/(1-L) - L - ln(1-L)
+// Linear collision resolution     [1+1/(1-L)]/2         [1+1/(1-L)2]/2
+//
+// -- enlarge_resize_percent --         0.10  0.50  0.60  0.75  0.80  0.90  0.99
+// QUADRATIC COLLISION RES.
+//    probes/successful lookup    1.05  1.44  1.62  2.01  2.21  2.85  5.11
+//    probes/unsuccessful lookup  1.11  2.19  2.82  4.64  5.81  11.4  103.6
+// LINEAR COLLISION RES.
+//    probes/successful lookup    1.06  1.5   1.75  2.5   3.0   5.5   50.5
+//    probes/unsuccessful lookup  1.12  2.5   3.6   8.5   13.0  50.0  5000.0
+//
+// The value type is required to be copy constructible and default
+// constructible, but it need not be (and commonly isn't) assignable.
+
+#ifndef _SPARSEHASHTABLE_H_
+#define _SPARSEHASHTABLE_H_
+
+#ifndef SPARSEHASH_STAT_UPDATE
+#define SPARSEHASH_STAT_UPDATE(x) ((void) 0)
+#endif
+
+// The probing method
+// Linear probing
+// #define JUMP_(key, num_probes)    ( 1 )
+// Quadratic-ish probing
+#define JUMP_(key, num_probes)    ( num_probes )
+
+
+// Hashtable class, used to implement the hashed associative containers
+// hash_set and hash_map.
+
+#include <google/sparsehash/sparseconfig.h>
+#include <assert.h>
+#include <algorithm>              // For swap(), eg
+#include <iterator>               // for facts about iterator tags
+#include <utility>                // for pair<>
+#include <google/sparsetable>     // Since that's basically what we are
+
+_START_GOOGLE_NAMESPACE_
+
+using STL_NAMESPACE::pair;
+
+// Alloc is completely ignored.  It is present as a template parameter only
+// for the sake of being compatible with the old SGI hashtable interface.
+// TODO(csilvers): is that the right thing to do?
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class EqualKey, class Alloc>
+class sparse_hashtable;
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct sparse_hashtable_iterator;
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct sparse_hashtable_const_iterator;
+
+// As far as iterating, we're basically just a sparsetable
+// that skips over deleted elements.
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct sparse_hashtable_iterator {
+ public:
+  typedef sparse_hashtable_iterator<V,K,HF,ExK,EqK,A>       iterator;
+  typedef sparse_hashtable_const_iterator<V,K,HF,ExK,EqK,A> const_iterator;
+  typedef typename sparsetable<V>::nonempty_iterator        st_iterator;
+
+  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
+  typedef V value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef V& reference;                // Value
+  typedef V* pointer;
+
+  // "Real" constructor and default constructor
+  sparse_hashtable_iterator(const sparse_hashtable<V,K,HF,ExK,EqK,A> *h,
+                            st_iterator it, st_iterator it_end)
+    : ht(h), pos(it), end(it_end)   { advance_past_deleted(); }
+  sparse_hashtable_iterator() { }      // not ever used internally
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on a marked-deleted array element
+  void advance_past_deleted() {
+    while ( pos != end && ht->test_deleted(*this) )
+      ++pos;
+  }
+  iterator& operator++()   {
+    assert(pos != end); ++pos; advance_past_deleted(); return *this;
+  }
+  iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
+
+  // Comparison.
+  bool operator==(const iterator& it) const { return pos == it.pos; }
+  bool operator!=(const iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const sparse_hashtable<V,K,HF,ExK,EqK,A> *ht;
+  st_iterator pos, end;
+};
+
+// Now do it all again, but with const-ness!
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct sparse_hashtable_const_iterator {
+ public:
+  typedef sparse_hashtable_iterator<V,K,HF,ExK,EqK,A>       iterator;
+  typedef sparse_hashtable_const_iterator<V,K,HF,ExK,EqK,A> const_iterator;
+  typedef typename sparsetable<V>::const_nonempty_iterator  st_iterator;
+
+  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
+  typedef V value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef const V& reference;                // Value
+  typedef const V* pointer;
+
+  // "Real" constructor and default constructor
+  sparse_hashtable_const_iterator(const sparse_hashtable<V,K,HF,ExK,EqK,A> *h,
+                                  st_iterator it, st_iterator it_end)
+    : ht(h), pos(it), end(it_end)   { advance_past_deleted(); }
+  // This lets us convert regular iterators to const iterators
+  sparse_hashtable_const_iterator() { }      // never used internally
+  sparse_hashtable_const_iterator(const iterator &it)
+    : ht(it.ht), pos(it.pos), end(it.end) { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on a marked-deleted array element
+  void advance_past_deleted() {
+    while ( pos != end && ht->test_deleted(*this) )
+      ++pos;
+  }
+  const_iterator& operator++() {
+    assert(pos != end); ++pos; advance_past_deleted(); return *this;
+  }
+  const_iterator operator++(int) { const_iterator tmp(*this); ++*this; return tmp; }
+
+  // Comparison.
+  bool operator==(const const_iterator& it) const { return pos == it.pos; }
+  bool operator!=(const const_iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const sparse_hashtable<V,K,HF,ExK,EqK,A> *ht;
+  st_iterator pos, end;
+};
+
+// And once again, but this time freeing up memory as we iterate
+template <class V, class K, class HF, class ExK, class EqK, class A>
+struct sparse_hashtable_destructive_iterator {
+ public:
+  typedef sparse_hashtable_destructive_iterator<V,K,HF,ExK,EqK,A> iterator;
+  typedef typename sparsetable<V>::destructive_iterator     st_iterator;
+
+  typedef STL_NAMESPACE::forward_iterator_tag iterator_category;
+  typedef V value_type;
+  typedef ptrdiff_t difference_type;
+  typedef size_t size_type;
+  typedef V& reference;                // Value
+  typedef V* pointer;
+
+  // "Real" constructor and default constructor
+  sparse_hashtable_destructive_iterator(const
+                                        sparse_hashtable<V,K,HF,ExK,EqK,A> *h,
+                                        st_iterator it, st_iterator it_end)
+    : ht(h), pos(it), end(it_end)   { advance_past_deleted(); }
+  sparse_hashtable_destructive_iterator() { }          // never used internally
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on a marked-deleted array element
+  void advance_past_deleted() {
+    while ( pos != end && ht->test_deleted(*this) )
+      ++pos;
+  }
+  iterator& operator++()   {
+    assert(pos != end); ++pos; advance_past_deleted(); return *this;
+  }
+  iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
+
+  // Comparison.
+  bool operator==(const iterator& it) const { return pos == it.pos; }
+  bool operator!=(const iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const sparse_hashtable<V,K,HF,ExK,EqK,A> *ht;
+  st_iterator pos, end;
+};
+
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class EqualKey, class Alloc>
+class sparse_hashtable {
+ public:
+  typedef Key key_type;
+  typedef Value value_type;
+  typedef HashFcn hasher;
+  typedef EqualKey key_equal;
+
+  typedef size_t            size_type;
+  typedef ptrdiff_t         difference_type;
+  typedef value_type*       pointer;
+  typedef const value_type* const_pointer;
+  typedef value_type&       reference;
+  typedef const value_type& const_reference;
+  typedef sparse_hashtable_iterator<Value, Key, HashFcn,
+                                    ExtractKey, EqualKey, Alloc>
+  iterator;
+
+  typedef sparse_hashtable_const_iterator<Value, Key, HashFcn,
+                                          ExtractKey, EqualKey, Alloc>
+  const_iterator;
+
+  typedef sparse_hashtable_destructive_iterator<Value, Key, HashFcn,
+                                                ExtractKey, EqualKey, Alloc>
+  destructive_iterator;
+
+
+  // How full we let the table get before we resize.  Knuth says .8 is
+  // good -- higher causes us to probe too much, though saves memory
+  static const float HT_OCCUPANCY_FLT; // = 0.8f;
+
+  // How empty we let the table get before we resize lower.
+  // It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
+  static const float HT_EMPTY_FLT; // = 0.4 * HT_OCCUPANCY_FLT;
+
+  // Minimum size we're willing to let hashtables be.
+  // Must be a power of two, and at least 4.
+  // Note, however, that for a given hashtable, the minimum size is
+  // determined by the first constructor arg, and may be >HT_MIN_BUCKETS.
+  static const size_t HT_MIN_BUCKETS = 4;
+
+  // By default, if you don't specify a hashtable size at
+  // construction-time, we use this size.  Must be a power of two, and
+  // at least HT_MIN_BUCKETS.
+  static const size_t HT_DEFAULT_STARTING_BUCKETS = 32;
+
+  // ITERATOR FUNCTIONS
+  iterator begin()             { return iterator(this, table.nonempty_begin(),
+                                                 table.nonempty_end()); }
+  iterator end()               { return iterator(this, table.nonempty_end(),
+                                                 table.nonempty_end()); }
+  const_iterator begin() const { return const_iterator(this,
+                                                       table.nonempty_begin(),
+                                                       table.nonempty_end()); }
+  const_iterator end() const   { return const_iterator(this,
+                                                       table.nonempty_end(),
+                                                       table.nonempty_end()); }
+
+  // This is used when resizing
+  destructive_iterator destructive_begin() {
+    return destructive_iterator(this, table.destructive_begin(),
+                                table.destructive_end());
+  }
+  destructive_iterator destructive_end() {
+    return destructive_iterator(this, table.destructive_end(),
+                                table.destructive_end());
+  }
+
+
+  // ACCESSOR FUNCTIONS for the things we templatize on, basically
+  hasher hash_funct() const { return hash; }
+  key_equal key_eq() const  { return equals; }
+
+  // We need to copy values when we set the special marker for deleted
+  // elements, but, annoyingly, we can't just use the copy assignment
+  // operator because value_type might not be assignable (it's often
+  // pair<const X, Y>).  We use explicit destructor invocation and
+  // placement new to get around this.  Arg.
+ private:
+  void set_value(value_type* dst, const value_type src) {
+    dst->~value_type();   // delete the old value, if any
+    new(dst) value_type(src);
+  }
+
+  // This is used as a tag for the copy constructor, saying to destroy its
+  // arg We have two ways of destructively copying: with potentially growing
+  // the hashtable as we copy, and without.  To make sure the outside world
+  // can't do a destructive copy, we make the typename private.
+  enum MoveDontCopyT {MoveDontCopy, MoveDontGrow};
+
+
+  // DELETE HELPER FUNCTIONS
+  // This lets the user describe a key that will indicate deleted
+  // table entries.  This key should be an "impossible" entry --
+  // if you try to insert it for real, you won't be able to retrieve it!
+  // (NB: while you pass in an entire value, only the key part is looked
+  // at.  This is just because I don't know how to assign just a key.)
+ private:
+  void squash_deleted() {           // gets rid of any deleted entries we have
+    if ( num_deleted ) {            // get rid of deleted before writing
+      sparse_hashtable tmp(MoveDontGrow, *this);
+      swap(tmp);                    // now we are tmp
+    }
+    assert(num_deleted == 0);
+  }
+
+ public:
+  void set_deleted_key(const value_type &val) {
+    // It's only safe to change what "deleted" means if we purge deleted guys
+    squash_deleted();
+    use_deleted = true;
+    set_value(&delval, val);        // save the key (and rest of val too)
+  }
+  void clear_deleted_key() {
+    squash_deleted();
+    use_deleted = false;
+  }
+
+  // These are public so the iterators can use them
+  // True if the item at position bucknum is "deleted" marker
+  bool test_deleted(size_type bucknum) const {
+    // The num_deleted test is crucial for read(): after read(), the ht values
+    // are garbage, and we don't want to think some of them are deleted.
+    return (use_deleted && num_deleted > 0 && table.test(bucknum) &&
+            equals(get_key(delval), get_key(table.get(bucknum))));
+  }
+  bool test_deleted(const iterator &it) const {
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(*it)));
+  }
+  bool test_deleted(const const_iterator &it) const {
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(*it)));
+  }
+  bool test_deleted(const destructive_iterator &it) const {
+    return (use_deleted && num_deleted > 0 &&
+            equals(get_key(delval), get_key(*it)));
+  }
+  // Set it so test_deleted is true.  true if object didn't used to be deleted
+  // See below (at erase()) to explain why we allow const_iterators
+  bool set_deleted(const_iterator &it) {
+    assert(use_deleted);             // bad if set_deleted_key() wasn't called
+    bool retval = !test_deleted(it);
+    // &* converts from iterator to value-type
+    set_value(const_cast<value_type*>(&(*it)), delval);
+    return retval;
+  }
+  // Set it so test_deleted is false.  true if object used to be deleted
+  bool clear_deleted(const_iterator &it) {
+    assert(use_deleted);             // bad if set_deleted_key() wasn't called
+    // happens automatically when we assign something else in its place
+    return test_deleted(it);
+  }
+
+
+  // FUNCTIONS CONCERNING SIZE
+  size_type size() const      { return table.num_nonempty() - num_deleted; }
+  // Buckets are always a power of 2
+  size_type max_size() const  { return (size_type(-1) >> 1U) + 1; }
+  bool empty() const          { return size() == 0; }
+  size_type bucket_count() const      { return table.size(); }
+  size_type max_bucket_count() const  { return max_size(); }
+
+ private:
+  // Because of the above, size_type(-1) is never legal; use it for errors
+  static const size_type ILLEGAL_BUCKET = size_type(-1);
+
+ private:
+  // This is the smallest size a hashtable can be without being too crowded
+  // If you like, you can give a min #buckets as well as a min #elts
+  size_type min_size(size_type num_elts, size_type min_buckets_wanted) {
+    size_type sz = HT_MIN_BUCKETS;
+    while ( sz < min_buckets_wanted || num_elts >= sz * enlarge_resize_percent )
+      sz *= 2;
+    return sz;
+  }
+
+  // Used after a string of deletes
+  void maybe_shrink() {
+    assert(table.num_nonempty() >= num_deleted);
+    assert((bucket_count() & (bucket_count()-1)) == 0); // is a power of two
+    assert(bucket_count() >= HT_MIN_BUCKETS);
+
+    // If you construct a hashtable with < HT_DEFAULT_STARTING_BUCKETS,
+    // we'll never shrink until you get relatively big, and we'll never
+    // shrink below HT_DEFAULT_STARTING_BUCKETS.  Otherwise, something
+    // like "dense_hash_set<int> x; x.insert(4); x.erase(4);" will
+    // shrink us down to HT_MIN_BUCKETS buckets, which is too small.
+    if (shrink_threshold > 0
+        && (table.num_nonempty()-num_deleted) < shrink_threshold &&
+        bucket_count() > HT_DEFAULT_STARTING_BUCKETS ) {
+      size_type sz = bucket_count() / 2;    // find how much we should shrink
+      while ( sz > HT_DEFAULT_STARTING_BUCKETS &&
+              (table.num_nonempty() - num_deleted) <= sz *
+              shrink_resize_percent )
+        sz /= 2;                            // stay a power of 2
+      sparse_hashtable tmp(MoveDontCopy, *this, sz);
+      swap(tmp);                            // now we are tmp
+    }
+    consider_shrink = false;                // because we just considered it
+  }
+
+  // We'll let you resize a hashtable -- though this makes us copy all!
+  // When you resize, you say, "make it big enough for this many more elements"
+  void resize_delta(size_type delta) {
+    if ( consider_shrink )                   // see if lots of deletes happened
+      maybe_shrink();
+    if ( bucket_count() >= HT_MIN_BUCKETS &&
+         (table.num_nonempty() + delta) <= enlarge_threshold )
+      return;                                // we're ok as we are
+
+    // Sometimes, we need to resize just to get rid of all the
+    // "deleted" buckets that are clogging up the hashtable.  So when
+    // deciding whether to resize, count the deleted buckets (which
+    // are currently taking up room).  But later, when we decide what
+    // size to resize to, *don't* count deleted buckets, since they
+    // get discarded during the resize.
+    const size_type needed_size = min_size(table.num_nonempty() + delta, 0);
+    if ( needed_size > bucket_count() ) {      // we don't have enough buckets
+      const size_type resize_to = min_size(table.num_nonempty() - num_deleted
+                                           + delta, 0);
+      sparse_hashtable tmp(MoveDontCopy, *this, resize_to);
+      swap(tmp);                             // now we are tmp
+    }
+  }
+
+  // Used to actually do the rehashing when we grow/shrink a hashtable
+  void copy_from(const sparse_hashtable &ht, size_type min_buckets_wanted) {
+    clear();            // clear table, set num_deleted to 0
+
+    // If we need to change the size of our table, do it now
+    const size_type resize_to = min_size(ht.size(), min_buckets_wanted);
+    if ( resize_to > bucket_count() ) {      // we don't have enough buckets
+      table.resize(resize_to);               // sets the number of buckets
+      reset_thresholds();
+    }
+
+    // We use a normal iterator to get non-deleted bcks from ht
+    // We could use insert() here, but since we know there are
+    // no duplicates and no deleted items, we can be more efficient
+    assert( (bucket_count() & (bucket_count()-1)) == 0);      // a power of two
+    for ( const_iterator it = ht.begin(); it != ht.end(); ++it ) {
+      size_type num_probes = 0;              // how many times we've probed
+      size_type bucknum;
+      const size_type bucket_count_minus_one = bucket_count() - 1;
+      for (bucknum = hash(get_key(*it)) & bucket_count_minus_one;
+           table.test(bucknum);                          // not empty
+           bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one) {
+        ++num_probes;
+        assert(num_probes < bucket_count()); // or else the hashtable is full
+      }
+      table.set(bucknum, *it);               // copies the value to here
+    }
+  }
+
+  // Implementation is like copy_from, but it destroys the table of the
+  // "from" guy by freeing sparsetable memory as we iterate.  This is
+  // useful in resizing, since we're throwing away the "from" guy anyway.
+  void move_from(MoveDontCopyT mover, sparse_hashtable &ht,
+                 size_type min_buckets_wanted) {
+    clear();            // clear table, set num_deleted to 0
+
+    // If we need to change the size of our table, do it now
+    size_t resize_to;
+    if ( mover == MoveDontGrow )
+      resize_to = ht.bucket_count();         // keep same size as old ht
+    else                                     // MoveDontCopy
+      resize_to = min_size(ht.size(), min_buckets_wanted);
+    if ( resize_to > bucket_count() ) {      // we don't have enough buckets
+      table.resize(resize_to);               // sets the number of buckets
+      reset_thresholds();
+    }
+
+    // We use a normal iterator to get non-deleted bcks from ht
+    // We could use insert() here, but since we know there are
+    // no duplicates and no deleted items, we can be more efficient
+    assert( (bucket_count() & (bucket_count()-1)) == 0);      // a power of two
+    // THIS IS THE MAJOR LINE THAT DIFFERS FROM COPY_FROM():
+    for ( destructive_iterator it = ht.destructive_begin();
+          it != ht.destructive_end(); ++it ) {
+      size_type num_probes = 0;              // how many times we've probed
+      size_type bucknum;
+      for ( bucknum = hash(get_key(*it)) & (bucket_count()-1);  // h % buck_cnt
+            table.test(bucknum);                          // not empty
+            bucknum = (bucknum + JUMP_(key, num_probes)) & (bucket_count()-1) ) {
+        ++num_probes;
+        assert(num_probes < bucket_count()); // or else the hashtable is full
+      }
+      table.set(bucknum, *it);               // copies the value to here
+    }
+  }
+
+
+  // Required by the spec for hashed associative container
+ public:
+  // Though the docs say this should be num_buckets, I think it's much
+  // more useful as num_elements.  As a special feature, calling with
+  // req_elements==0 will cause us to shrink if we can, saving space.
+  void resize(size_type req_elements) {       // resize to this or larger
+    if ( consider_shrink || req_elements == 0 )
+      maybe_shrink();
+    if ( req_elements > table.num_nonempty() )    // we only grow
+      resize_delta(req_elements - table.num_nonempty());
+  }
+
+  // Change the value of shrink_resize_percent and
+  // enlarge_resize_percent.  The description at the beginning of this
+  // file explains how to choose the values.  Setting the shrink
+  // parameter to 0.0 ensures that the table never shrinks.
+  void set_resizing_parameters(float shrink, float grow) {
+    assert(shrink >= 0.0);
+    assert(grow <= 1.0);
+    assert(shrink <= grow/2.0);
+    shrink_resize_percent = shrink;
+    enlarge_resize_percent = grow;
+    reset_thresholds();
+  }
+
+  // CONSTRUCTORS -- as required by the specs, we take a size,
+  // but also let you specify a hashfunction, key comparator,
+  // and key extractor.  We also define a copy constructor and =.
+  // DESTRUCTOR -- the default is fine, surprisingly.
+  explicit sparse_hashtable(size_type expected_max_items_in_table = 0,
+                            const HashFcn& hf = HashFcn(),
+                            const EqualKey& eql = EqualKey(),
+                            const ExtractKey& ext = ExtractKey())
+    : hash(hf), equals(eql), get_key(ext), num_deleted(0), use_deleted(false),
+      delval(), enlarge_resize_percent(HT_OCCUPANCY_FLT),
+      shrink_resize_percent(HT_EMPTY_FLT),
+      table(expected_max_items_in_table == 0
+            ? HT_DEFAULT_STARTING_BUCKETS
+            : min_size(expected_max_items_in_table, 0)) {
+    reset_thresholds();
+  }
+
+  // As a convenience for resize(), we allow an optional second argument
+  // which lets you make this new hashtable a different size than ht.
+  // We also provide a mechanism of saying you want to "move" the ht argument
+  // into us instead of copying.
+  sparse_hashtable(const sparse_hashtable& ht,
+                   size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
+    : hash(ht.hash), equals(ht.equals), get_key(ht.get_key),
+      num_deleted(0), use_deleted(ht.use_deleted), delval(ht.delval),
+      enlarge_resize_percent(ht.enlarge_resize_percent),
+      shrink_resize_percent(ht.shrink_resize_percent),
+      table() {
+    reset_thresholds();
+    copy_from(ht, min_buckets_wanted);   // copy_from() ignores deleted entries
+  }
+  sparse_hashtable(MoveDontCopyT mover, sparse_hashtable& ht,
+                   size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
+    : hash(ht.hash), equals(ht.equals), get_key(ht.get_key),
+      num_deleted(0), use_deleted(ht.use_deleted), delval(ht.delval),
+      enlarge_resize_percent(ht.enlarge_resize_percent),
+      shrink_resize_percent(ht.shrink_resize_percent),
+      table() {
+    reset_thresholds();
+    move_from(mover, ht, min_buckets_wanted);  // ignores deleted entries
+  }
+
+  sparse_hashtable& operator= (const sparse_hashtable& ht) {
+    if (&ht == this)  return *this;        // don't copy onto ourselves
+    clear();
+    hash = ht.hash;
+    equals = ht.equals;
+    get_key = ht.get_key;
+    use_deleted = ht.use_deleted;
+    set_value(&delval, ht.delval);
+    copy_from(ht, HT_MIN_BUCKETS);         // sets num_deleted to 0 too
+    return *this;
+  }
+
+  // Many STL algorithms use swap instead of copy constructors
+  void swap(sparse_hashtable& ht) {
+    STL_NAMESPACE::swap(hash, ht.hash);
+    STL_NAMESPACE::swap(equals, ht.equals);
+    STL_NAMESPACE::swap(get_key, ht.get_key);
+    STL_NAMESPACE::swap(num_deleted, ht.num_deleted);
+    STL_NAMESPACE::swap(use_deleted, ht.use_deleted);
+    STL_NAMESPACE::swap(enlarge_resize_percent, ht.enlarge_resize_percent);
+    STL_NAMESPACE::swap(shrink_resize_percent, ht.shrink_resize_percent);
+    { value_type tmp;     // for annoying reasons, swap() doesn't work
+      set_value(&tmp, delval);
+      set_value(&delval, ht.delval);
+      set_value(&ht.delval, tmp);
+    }
+    table.swap(ht.table);
+    reset_thresholds();
+    ht.reset_thresholds();
+  }
+
+  // It's always nice to be able to clear a table without deallocating it
+  void clear() {
+    table.clear();
+    reset_thresholds();
+    num_deleted = 0;
+  }
+
+
+  // LOOKUP ROUTINES
+ private:
+  // Returns a pair of positions: 1st where the object is, 2nd where
+  // it would go if you wanted to insert it.  1st is ILLEGAL_BUCKET
+  // if object is not found; 2nd is ILLEGAL_BUCKET if it is.
+  // Note: because of deletions where-to-insert is not trivial: it's the
+  // first deleted bucket we see, as long as we don't find the key later
+  pair<size_type, size_type> find_position(const key_type &key) const {
+    size_type num_probes = 0;              // how many times we've probed
+    const size_type bucket_count_minus_one = bucket_count() - 1;
+    size_type bucknum = hash(key) & bucket_count_minus_one;
+    size_type insert_pos = ILLEGAL_BUCKET; // where we would insert
+    SPARSEHASH_STAT_UPDATE(total_lookups += 1);
+    while ( 1 ) {                          // probe until something happens
+      if ( !table.test(bucknum) ) {        // bucket is empty
+        SPARSEHASH_STAT_UPDATE(total_probes += num_probes);
+        if ( insert_pos == ILLEGAL_BUCKET )  // found no prior place to insert
+          return pair<size_type,size_type>(ILLEGAL_BUCKET, bucknum);
+        else
+          return pair<size_type,size_type>(ILLEGAL_BUCKET, insert_pos);
+
+      } else if ( test_deleted(bucknum) ) {// keep searching, but mark to insert
+        if ( insert_pos == ILLEGAL_BUCKET )
+          insert_pos = bucknum;
+
+      } else if ( equals(key, get_key(table.get(bucknum))) ) {
+        SPARSEHASH_STAT_UPDATE(total_probes += num_probes);
+        return pair<size_type,size_type>(bucknum, ILLEGAL_BUCKET);
+      }
+      ++num_probes;                        // we're doing another probe
+      bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
+      assert(num_probes < bucket_count()); // don't probe too many times!
+    }
+  }
+
+ public:
+  iterator find(const key_type& key) {
+    if ( size() == 0 ) return end();
+    pair<size_type, size_type> pos = find_position(key);
+    if ( pos.first == ILLEGAL_BUCKET )     // alas, not there
+      return end();
+    else
+      return iterator(this, table.get_iter(pos.first), table.nonempty_end());
+  }
+
+  const_iterator find(const key_type& key) const {
+    if ( size() == 0 ) return end();
+    pair<size_type, size_type> pos = find_position(key);
+    if ( pos.first == ILLEGAL_BUCKET )     // alas, not there
+      return end();
+    else
+      return const_iterator(this,
+                            table.get_iter(pos.first), table.nonempty_end());
+  }
+
+  // Counts how many elements have key key.  For maps, it's either 0 or 1.
+  size_type count(const key_type &key) const {
+    pair<size_type, size_type> pos = find_position(key);
+    return pos.first == ILLEGAL_BUCKET ? 0 : 1;
+  }
+
+  // Likewise, equal_range doesn't really make sense for us.  Oh well.
+  pair<iterator,iterator> equal_range(const key_type& key) {
+    const iterator pos = find(key);      // either an iterator or end
+    return pair<iterator,iterator>(pos, pos);
+  }
+  pair<const_iterator,const_iterator> equal_range(const key_type& key) const {
+    const const_iterator pos = find(key);      // either an iterator or end
+    return pair<iterator,iterator>(pos, pos);
+  }
+
+
+  // INSERTION ROUTINES
+ private:
+  // If you know *this is big enough to hold obj, use this routine
+  pair<iterator, bool> insert_noresize(const value_type& obj) {
+    // First, double-check we're not inserting delval
+    assert(!use_deleted || !equals(get_key(obj), get_key(delval)));
+    const pair<size_type,size_type> pos = find_position(get_key(obj));
+    if ( pos.first != ILLEGAL_BUCKET) {      // object was already there
+      return pair<iterator,bool>(iterator(this, table.get_iter(pos.first),
+                                          table.nonempty_end()),
+                                 false);          // false: we didn't insert
+    } else {                                 // pos.second says where to put it
+      if ( test_deleted(pos.second) ) {      // just replace if it's been del.
+        // The set() below will undelete this object.  We just worry about stats
+        assert(num_deleted > 0);
+        --num_deleted;                       // used to be, now it isn't
+      }
+      table.set(pos.second, obj);
+      return pair<iterator,bool>(iterator(this, table.get_iter(pos.second),
+                                          table.nonempty_end()),
+                                 true);           // true: we did insert
+    }
+  }
+
+ public:
+  // This is the normal insert routine, used by the outside world
+  pair<iterator, bool> insert(const value_type& obj) {
+    resize_delta(1);  // adding an object, grow if need be
+    return insert_noresize(obj);
+  }
+
+  // When inserting a lot at a time, we specialize on the type of iterator
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    // specializes on iterator type
+    insert(f, l, typename STL_NAMESPACE::iterator_traits<InputIterator>::iterator_category());
+  }
+
+  // Iterator supports operator-, resize before inserting
+  template <class ForwardIterator>
+  void insert(ForwardIterator f, ForwardIterator l,
+              STL_NAMESPACE::forward_iterator_tag) {
+    size_type n = STL_NAMESPACE::distance(f, l);   // TODO(csilvers): standard?
+    resize_delta(n);
+    for ( ; n > 0; --n, ++f)
+      insert_noresize(*f);
+  }
+
+  // Arbitrary iterator, can't tell how much to resize
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l,
+              STL_NAMESPACE::input_iterator_tag) {
+    for ( ; f != l; ++f)
+      insert(*f);
+  }
+
+
+  // DELETION ROUTINES
+  size_type erase(const key_type& key) {
+    // First, double-check we're not erasing delval
+    assert(!use_deleted || !equals(key, get_key(delval)));
+    const_iterator pos = find(key);   // shrug: shouldn't need to be const
+    if ( pos != end() ) {
+      assert(!test_deleted(pos));  // or find() shouldn't have returned it
+      set_deleted(pos);
+      ++num_deleted;
+      consider_shrink = true;      // will think about shrink after next insert
+      return 1;                    // because we deleted one thing
+    } else {
+      return 0;                    // because we deleted nothing
+    }
+  }
+
+  // This is really evil: really it should be iterator, not const_iterator.
+  // But...the only reason keys are const is to allow lookup.
+  // Since that's a moot issue for deleted keys, we allow const_iterators
+  void erase(const_iterator pos) {
+    if ( pos == end() ) return;    // sanity check
+    if ( set_deleted(pos) ) {      // true if object has been newly deleted
+      ++num_deleted;
+      consider_shrink = true;      // will think about shrink after next insert
+    }
+  }
+
+  void erase(const_iterator f, const_iterator l) {
+    for ( ; f != l; ++f) {
+      if ( set_deleted(f)  )       // should always be true
+        ++num_deleted;
+    }
+    consider_shrink = true;        // will think about shrink after next insert
+  }
+
+
+  // COMPARISON
+  bool operator==(const sparse_hashtable& ht) const {
+    // We really want to check that the hash functions are the same
+    // but alas there's no way to do this.  We just hope.
+    return ( num_deleted == ht.num_deleted && table == ht.table );
+  }
+  bool operator!=(const sparse_hashtable& ht) const {
+    return !(*this == ht);
+  }
+
+
+  // I/O
+  // We support reading and writing hashtables to disk.  NOTE that
+  // this only stores the hashtable metadata, not the stuff you've
+  // actually put in the hashtable!  Alas, since I don't know how to
+  // write a hasher or key_equal, you have to make sure everything
+  // but the table is the same.  We compact before writing.
+  bool write_metadata(FILE *fp) {
+    squash_deleted();           // so we don't have to worry about delkey
+    return table.write_metadata(fp);
+  }
+
+  bool read_metadata(FILE *fp) {
+    num_deleted = 0;            // since we got rid before writing
+    bool result = table.read_metadata(fp);
+    reset_thresholds();
+    return result;
+  }
+
+  // Only meaningful if value_type is a POD.
+  bool write_nopointer_data(FILE *fp) {
+    return table.write_nopointer_data(fp);
+  }
+
+  // Only meaningful if value_type is a POD.
+  bool read_nopointer_data(FILE *fp) {
+    return table.read_nopointer_data(fp);
+  }
+
+ private:
+  // The actual data
+  hasher hash;                      // required by hashed_associative_container
+  key_equal equals;
+  ExtractKey get_key;
+  size_type num_deleted;        // how many occupied buckets are marked deleted
+  bool use_deleted;                          // false until delval has been set
+  value_type delval;                         // which key marks deleted entries
+  float enlarge_resize_percent;                       // how full before resize
+  float shrink_resize_percent;                       // how empty before resize
+  size_type shrink_threshold;           // table.size() * shrink_resize_percent
+  size_type enlarge_threshold;         // table.size() * enlarge_resize_percent
+  sparsetable<value_type> table;      // holds num_buckets and num_elements too
+  bool consider_shrink;   // true if we should try to shrink before next insert
+
+  void reset_thresholds() {
+    enlarge_threshold = static_cast<size_type>(table.size()
+                                               * enlarge_resize_percent);
+    shrink_threshold = static_cast<size_type>(table.size()
+                                              * shrink_resize_percent);
+    consider_shrink = false;   // whatever caused us to reset already considered
+  }
+};
+
+// We need a global swap as well
+template <class V, class K, class HF, class ExK, class EqK, class A>
+inline void swap(sparse_hashtable<V,K,HF,ExK,EqK,A> &x,
+                 sparse_hashtable<V,K,HF,ExK,EqK,A> &y) {
+  x.swap(y);
+}
+
+#undef JUMP_
+
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const typename sparse_hashtable<V,K,HF,ExK,EqK,A>::size_type
+  sparse_hashtable<V,K,HF,ExK,EqK,A>::ILLEGAL_BUCKET;
+
+// How full we let the table get before we resize.  Knuth says .8 is
+// good -- higher causes us to probe too much, though saves memory
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const float sparse_hashtable<V,K,HF,ExK,EqK,A>::HT_OCCUPANCY_FLT = 0.8f;
+
+// How empty we let the table get before we resize lower.
+// It should be less than OCCUPANCY_FLT / 2 or we thrash resizing
+template <class V, class K, class HF, class ExK, class EqK, class A>
+const float sparse_hashtable<V,K,HF,ExK,EqK,A>::HT_EMPTY_FLT = 0.4f *
+sparse_hashtable<V,K,HF,ExK,EqK,A>::HT_OCCUPANCY_FLT;
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* _SPARSEHASHTABLE_H_ */
diff --git a/3rdparty/google/sparsetable b/3rdparty/google/sparsetable
new file mode 100644
index 0000000000..60f600392d
--- /dev/null
+++ b/3rdparty/google/sparsetable
@@ -0,0 +1,1451 @@
+// Copyright (c) 2005, Google Inc.
+// 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 Google Inc. 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.
+
+// ---
+// Author: Craig Silverstein
+//
+// A sparsetable is a random container that implements a sparse array,
+// that is, an array that uses very little memory to store unassigned
+// indices (in this case, between 1-2 bits per unassigned index).  For
+// instance, if you allocate an array of size 5 and assign a[2] = <big
+// struct>, then a[2] will take up a lot of memory but a[0], a[1],
+// a[3], and a[4] will not.  Array elements that have a value are
+// called "assigned".  Array elements that have no value yet, or have
+// had their value cleared using erase() or clear(), are called
+// "unassigned".
+//
+// Unassigned values seem to have the default value of T (see below).
+// Nevertheless, there is a difference between an unassigned index and
+// one explicitly assigned the value of T().  The latter is considered
+// assigned.
+//
+// Access to an array element is constant time, as is insertion and
+// deletion.  Insertion and deletion may be fairly slow, however:
+// because of this container's memory economy, each insert and delete
+// causes a memory reallocation.
+//
+// See /usr/(local/)?doc/sparsehash-0.1/sparsetable.html
+// for information about how to use this class.
+
+#ifndef _SPARSETABLE_H_
+#define _SPARSETABLE_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <stdlib.h>             // for malloc/free
+#include <stdio.h>              // to read/write tables
+#ifdef HAVE_STDINT_H
+#include <stdint.h>             // the normal place uint16_t is defined
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>          // the normal place u_int16_t is defined
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>           // a third place for uint16_t or u_int16_t
+#endif
+#include <assert.h>             // for bounds checking
+#include <iterator>             // to define reverse_iterator for me
+#include <algorithm>            // equal, lexicographical_compare, swap,...
+#include <memory>               // uninitialized_copy
+#include <vector>               // a sparsetable is a vector of groups
+#include <google/type_traits.h> // for true_type, integral_constant, etc.
+
+#if STDC_HEADERS
+#include <string.h>             // for memcpy
+#else
+#if !HAVE_MEMCPY
+#define memcpy(d, s, n)   bcopy ((s), (d), (n))
+#endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+#ifndef HAVE_U_INT16_T
+# if defined HAVE_UINT16_T
+    typedef uint16_t u_int16_t;    // true on solaris, possibly other C99 libc's
+# elif defined HAVE___UINT16
+    typedef __int16 int16_t;       // true on vc++7
+    typedef unsigned __int16 u_int16_t;
+# else
+    // Cannot find a 16-bit integer type.  Hoping for the best with "short"...
+    typedef short int int16_t;
+    typedef unsigned short int u_int16_t;
+# endif
+#endif
+
+using STL_NAMESPACE::vector;
+using STL_NAMESPACE::uninitialized_copy;
+
+// The smaller this is, the faster lookup is (because the group bitmap is
+// smaller) and the faster insert is, because there's less to move.
+// On the other hand, there are more groups.  Since group::size_type is
+// a short, this number should be of the form 32*x + 16 to avoid waste.
+static const u_int16_t DEFAULT_SPARSEGROUP_SIZE = 48;   // fits in 1.5 words
+
+
+// A NOTE ON ASSIGNING:
+// A sparse table does not actually allocate memory for entries
+// that are not filled.  Because of this, it becomes complicated
+// to have a non-const iterator: we don't know, if the iterator points
+// to a not-filled bucket, whether you plan to fill it with something
+// or whether you plan to read its value (in which case you'll get
+// the default bucket value).  Therefore, while we can define const
+// operations in a pretty 'normal' way, for non-const operations, we
+// define something that returns a helper object with operator= and
+// operator& that allocate a bucket lazily.  We use this for table[]
+// and also for regular table iterators.
+
+template <class tabletype>
+class table_element_adaptor {
+ public:
+  typedef typename tabletype::value_type value_type;
+  typedef typename tabletype::size_type size_type;
+  typedef typename tabletype::reference reference;
+  typedef typename tabletype::pointer pointer;
+
+  table_element_adaptor(tabletype *tbl, size_type p)
+    : table(tbl), pos(p) { }
+  table_element_adaptor& operator= (const value_type &val) {
+    table->set(pos, val);
+    return *this;
+  }
+  operator value_type() { return table->get(pos); }   // we look like a value
+  pointer operator& () { return &table->mutating_get(pos); }
+
+ private:
+  tabletype* table;
+  size_type pos;
+};
+
+// Our iterator as simple as iterators can be: basically it's just
+// the index into our table.  Dereference, the only complicated
+// thing, we punt to the table class.  This just goes to show how
+// much machinery STL requires to do even the most trivial tasks.
+//
+// By templatizing over tabletype, we have one iterator type which
+// we can use for both sparsetables and sparsebins.  In fact it
+// works on any class that allows size() and operator[] (eg vector),
+// as long as it does the standard STL typedefs too (eg value_type).
+
+template <class tabletype>
+class table_iterator {
+ public:
+  typedef table_iterator iterator;
+
+  typedef STL_NAMESPACE::random_access_iterator_tag iterator_category;
+  typedef typename tabletype::value_type value_type;
+  typedef typename tabletype::difference_type difference_type;
+  typedef typename tabletype::size_type size_type;
+  typedef table_element_adaptor<tabletype> reference;
+  typedef table_element_adaptor<tabletype>* pointer;
+
+  // The "real" constructor
+  table_iterator(tabletype *tbl, size_type p)
+    : table(tbl), pos(p) { }
+  // The default constructor, used when I define vars of type table::iterator
+  table_iterator() : table(NULL), pos(0) { }
+  // The copy constructor, for when I say table::iterator foo = tbl.begin()
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // The main thing our iterator does is dereference.  If the table entry
+  // we point to is empty, we return the default value type.
+  // This is the big different function from the const iterator.
+  reference operator*()              {
+    return table_element_adaptor<tabletype>(table, pos);
+  }
+  pointer operator->()               { return &(operator*()); }
+
+  // Helper function to assert things are ok; eg pos is still in range
+  void check() const {
+    assert(table);
+    assert(pos <= table->size());
+  }
+
+  // Arithmetic: we just do arithmetic on pos.  We don't even need to
+  // do bounds checking, since STL doesn't consider that it's job.  :-)
+  iterator& operator+=(size_type t) { pos += t; check(); return *this; }
+  iterator& operator-=(size_type t) { pos -= t; check(); return *this; }
+  iterator& operator++()            { ++pos; check(); return *this; }
+  iterator& operator--()            { --pos; check(); return *this; }
+  iterator operator++(int)          { iterator tmp(*this);     // for x++
+                                      ++pos; check(); return tmp; }
+  iterator operator--(int)          { iterator tmp(*this);     // for x--
+                                      --pos; check(); return tmp; }
+  iterator operator+(difference_type i) const  { iterator tmp(*this);
+                                                 tmp += i; return tmp; }
+  iterator operator-(difference_type i) const  { iterator tmp(*this);
+                                                 tmp -= i; return tmp; }
+  difference_type operator-(iterator it) const {      // for "x = it2 - it"
+    assert(table == it.table);
+    return pos - it.pos;
+  }
+  reference operator[](difference_type n) const {
+    return *(*this + n);            // simple though not totally efficient
+  }
+
+  // Comparisons.
+  bool operator==(const iterator& it) const {
+    return table == it.table && pos == it.pos;
+  }
+  bool operator<(const iterator& it) const {
+    assert(table == it.table);              // life is bad bad bad otherwise
+    return pos < it.pos;
+  }
+  bool operator!=(const iterator& it) const { return !(*this == it); }
+  bool operator<=(const iterator& it) const { return !(it < *this); }
+  bool operator>(const iterator& it) const { return it < *this; }
+  bool operator>=(const iterator& it) const { return !(*this < it); }
+
+  // Here's the info we actually need to be an iterator
+  tabletype *table;              // so we can dereference and bounds-check
+  size_type pos;                 // index into the table
+};
+
+// support for "3 + iterator" has to be defined outside the class, alas
+template<class T>
+table_iterator<T> operator+(typename table_iterator<T>::difference_type i,
+                            table_iterator<T> it) {
+  return it + i;               // so people can say it2 = 3 + it
+}
+
+template <class tabletype>
+class const_table_iterator {
+ public:
+  typedef table_iterator<tabletype> iterator;
+  typedef const_table_iterator const_iterator;
+
+  typedef STL_NAMESPACE::random_access_iterator_tag iterator_category;
+  typedef typename tabletype::value_type value_type;
+  typedef typename tabletype::difference_type difference_type;
+  typedef typename tabletype::size_type size_type;
+  typedef typename tabletype::const_reference reference;  // we're const-only
+  typedef typename tabletype::const_pointer pointer;
+
+  // The "real" constructor
+  const_table_iterator(const tabletype *tbl, size_type p)
+    : table(tbl), pos(p) { }
+  // The default constructor, used when I define vars of type table::iterator
+  const_table_iterator() : table(NULL), pos(0) { }
+  // The copy constructor, for when I say table::iterator foo = tbl.begin()
+  // Also converts normal iterators to const iterators
+  const_table_iterator(const iterator &from)
+    : table(from.table), pos(from.pos) { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // The main thing our iterator does is dereference.  If the table entry
+  // we point to is empty, we return the default value type.
+  reference operator*() const       { return (*table)[pos]; }
+  pointer operator->() const        { return &(operator*()); }
+
+  // Helper function to assert things are ok; eg pos is still in range
+  void check() const {
+    assert(table);
+    assert(pos <= table->size());
+  }
+
+  // Arithmetic: we just do arithmetic on pos.  We don't even need to
+  // do bounds checking, since STL doesn't consider that it's job.  :-)
+  const_iterator& operator+=(size_type t) { pos += t; check(); return *this; }
+  const_iterator& operator-=(size_type t) { pos -= t; check(); return *this; }
+  const_iterator& operator++()            { ++pos; check(); return *this; }
+  const_iterator& operator--()            { --pos; check(); return *this; }
+  const_iterator operator++(int)          { const_iterator tmp(*this); // for x++
+                                            ++pos; check(); return tmp; }
+  const_iterator operator--(int)          { const_iterator tmp(*this); // for x--
+                                            --pos; check(); return tmp; }
+  const_iterator operator+(difference_type i) const  { const_iterator tmp(*this);
+                                                       tmp += i; return tmp; }
+  const_iterator operator-(difference_type i) const  { const_iterator tmp(*this);
+                                                       tmp -= i; return tmp; }
+  difference_type operator-(const_iterator it) const {   // for "x = it2 - it"
+    assert(table == it.table);
+    return pos - it.pos;
+  }
+  reference operator[](difference_type n) const {
+    return *(*this + n);            // simple though not totally efficient
+  }
+
+  // Comparisons.
+  bool operator==(const const_iterator& it) const {
+    return table == it.table && pos == it.pos;
+  }
+  bool operator<(const const_iterator& it) const {
+    assert(table == it.table);              // life is bad bad bad otherwise
+    return pos < it.pos;
+  }
+  bool operator!=(const const_iterator& it) const { return !(*this == it); }
+  bool operator<=(const const_iterator& it) const { return !(it < *this); }
+  bool operator>(const const_iterator& it) const { return it < *this; }
+  bool operator>=(const const_iterator& it) const { return !(*this < it); }
+
+  // Here's the info we actually need to be an iterator
+  const tabletype *table;        // so we can dereference and bounds-check
+  size_type pos;                 // index into the table
+};
+
+// support for "3 + iterator" has to be defined outside the class, alas
+template<class T>
+const_table_iterator<T> operator+(typename
+                                  const_table_iterator<T>::difference_type i,
+                                  const_table_iterator<T> it) {
+  return it + i;               // so people can say it2 = 3 + it
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+/*
+// This is a 2-D iterator.  You specify a begin and end over a list
+// of *containers*.  We iterate over each container by iterating over
+// it.  It's actually simple:
+// VECTOR.begin() VECTOR[0].begin()  --------> VECTOR[0].end() ---,
+//     |          ________________________________________________/
+//     |          \_> VECTOR[1].begin()  -------->  VECTOR[1].end() -,
+//     |          ___________________________________________________/
+//     v          \_> ......
+// VECTOR.end()
+//
+// It's impossible to do random access on one of these things in constant
+// time, so it's just a bidirectional iterator.
+//
+// Unfortunately, because we need to use this for a non-empty iterator,
+// we use nonempty_begin() and nonempty_end() instead of begin() and end()
+// (though only going across, not down).
+*/
+
+#define TWOD_BEGIN_      nonempty_begin
+#define TWOD_END_        nonempty_end
+#define TWOD_ITER_       nonempty_iterator
+#define TWOD_CONST_ITER_ const_nonempty_iterator
+
+template <class containertype>
+class two_d_iterator {
+ public:
+  typedef two_d_iterator iterator;
+
+  typedef STL_NAMESPACE::bidirectional_iterator_tag iterator_category;
+  // apparently some versions of VC++ have trouble with two ::'s in a typename
+  typedef typename containertype::value_type _tmp_vt;
+  typedef typename _tmp_vt::value_type value_type;
+  typedef typename _tmp_vt::difference_type difference_type;
+  typedef typename _tmp_vt::reference reference;
+  typedef typename _tmp_vt::pointer pointer;
+
+  // The "real" constructor.  begin and end specify how many rows we have
+  // (in the diagram above); we always iterate over each row completely.
+  two_d_iterator(typename containertype::iterator begin,
+                 typename containertype::iterator end,
+                 typename containertype::iterator curr)
+    : row_begin(begin), row_end(end), row_current(curr), col_current() {
+    if ( row_current != row_end ) {
+      col_current = row_current->TWOD_BEGIN_();
+      advance_past_end();                 // in case cur->begin() == cur->end()
+    }
+  }
+  // If you want to start at an arbitrary place, you can, I guess
+  two_d_iterator(typename containertype::iterator begin,
+                 typename containertype::iterator end,
+                 typename containertype::iterator curr,
+                 typename containertype::value_type::TWOD_ITER_ col)
+    : row_begin(begin), row_end(end), row_current(curr), col_current(col) {
+    advance_past_end();                 // in case cur->begin() == cur->end()
+  }
+  // The default constructor, used when I define vars of type table::iterator
+  two_d_iterator() : row_begin(), row_end(), row_current(), col_current() { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const    { return *col_current; }
+  pointer operator->() const     { return &(operator*()); }
+
+  // Arithmetic: we just do arithmetic on pos.  We don't even need to
+  // do bounds checking, since STL doesn't consider that it's job.  :-)
+  // NOTE: this is not amortized constant time!  What do we do about it?
+  void advance_past_end() {          // used when col_current points to end()
+    while ( col_current == row_current->TWOD_END_() ) {  // end of current row
+      ++row_current;                                // go to beginning of next
+      if ( row_current != row_end )                 // col is irrelevant at end
+        col_current = row_current->TWOD_BEGIN_();
+      else
+        break;                                      // don't go past row_end
+    }
+  }
+
+  iterator& operator++() {
+    assert(row_current != row_end);                 // how to ++ from there?
+    ++col_current;
+    advance_past_end();                 // in case col_current is at end()
+    return *this;
+  }
+  iterator& operator--() {
+    while ( row_current == row_end ||
+            col_current == row_current->TWOD_BEGIN_() ) {
+      assert(row_current != row_begin);
+      --row_current;
+      col_current = row_current->TWOD_END_();             // this is 1 too far
+    }
+    --col_current;
+    return *this;
+  }
+  iterator operator++(int)       { iterator tmp(*this); ++*this; return tmp; }
+  iterator operator--(int)       { iterator tmp(*this); --*this; return tmp; }
+
+
+  // Comparisons.
+  bool operator==(const iterator& it) const {
+    return ( row_begin == it.row_begin &&
+             row_end == it.row_end &&
+             row_current == it.row_current &&
+             (row_current == row_end || col_current == it.col_current) );
+  }
+  bool operator!=(const iterator& it) const { return !(*this == it); }
+
+
+  // Here's the info we actually need to be an iterator
+  // These need to be public so we convert from iterator to const_iterator
+  typename containertype::iterator row_begin, row_end, row_current;
+  typename containertype::value_type::TWOD_ITER_ col_current;
+};
+
+// The same thing again, but this time const.  :-(
+template <class containertype>
+class const_two_d_iterator {
+ public:
+  typedef const_two_d_iterator iterator;
+
+  typedef STL_NAMESPACE::bidirectional_iterator_tag iterator_category;
+  // apparently some versions of VC++ have trouble with two ::'s in a typename
+  typedef typename containertype::value_type _tmp_vt;
+  typedef typename _tmp_vt::value_type value_type;
+  typedef typename _tmp_vt::difference_type difference_type;
+  typedef typename _tmp_vt::const_reference reference;
+  typedef typename _tmp_vt::const_pointer pointer;
+
+  const_two_d_iterator(typename containertype::const_iterator begin,
+                       typename containertype::const_iterator end,
+                       typename containertype::const_iterator curr)
+    : row_begin(begin), row_end(end), row_current(curr), col_current() {
+    if ( curr != end ) {
+      col_current = curr->TWOD_BEGIN_();
+      advance_past_end();                 // in case cur->begin() == cur->end()
+    }
+  }
+  const_two_d_iterator(typename containertype::const_iterator begin,
+                       typename containertype::const_iterator end,
+                       typename containertype::const_iterator curr,
+                       typename containertype::value_type::TWOD_CONST_ITER_ col)
+    : row_begin(begin), row_end(end), row_current(curr), col_current(col) {
+    advance_past_end();                 // in case cur->begin() == cur->end()
+  }
+  const_two_d_iterator()
+    : row_begin(), row_end(), row_current(), col_current() {
+  }
+  // Need this explicitly so we can convert normal iterators to const iterators
+  const_two_d_iterator(const two_d_iterator<containertype>& it) :
+    row_begin(it.row_begin), row_end(it.row_end), row_current(it.row_current),
+    col_current(it.col_current) { }
+
+  typename containertype::const_iterator row_begin, row_end, row_current;
+  typename containertype::value_type::TWOD_CONST_ITER_ col_current;
+
+
+  // EVERYTHING FROM HERE DOWN IS THE SAME AS THE NON-CONST ITERATOR
+  reference operator*() const    { return *col_current; }
+  pointer operator->() const     { return &(operator*()); }
+
+  void advance_past_end() {          // used when col_current points to end()
+    while ( col_current == row_current->TWOD_END_() ) {  // end of current row
+      ++row_current;                                // go to beginning of next
+      if ( row_current != row_end )                 // col is irrelevant at end
+        col_current = row_current->TWOD_BEGIN_();
+      else
+        break;                                      // don't go past row_end
+    }
+  }
+  iterator& operator++() {
+    assert(row_current != row_end);                 // how to ++ from there?
+    ++col_current;
+    advance_past_end();                 // in case col_current is at end()
+    return *this;
+  }
+  iterator& operator--() {
+    while ( row_current == row_end ||
+            col_current == row_current->TWOD_BEGIN_() ) {
+      assert(row_current != row_begin);
+      --row_current;
+      col_current = row_current->TWOD_END_();             // this is 1 too far
+    }
+    --col_current;
+    return *this;
+  }
+  iterator operator++(int)       { iterator tmp(*this); ++*this; return tmp; }
+  iterator operator--(int)       { iterator tmp(*this); --*this; return tmp; }
+
+  bool operator==(const iterator& it) const {
+    return ( row_begin == it.row_begin &&
+             row_end == it.row_end &&
+             row_current == it.row_current &&
+             (row_current == row_end || col_current == it.col_current) );
+  }
+  bool operator!=(const iterator& it) const { return !(*this == it); }
+};
+
+// We provide yet another version, to be as frugal with memory as
+// possible.  This one frees each block of memory as it finishes
+// iterating over it.  By the end, the entire table is freed.
+// For understandable reasons, you can only iterate over it once,
+// which is why it's an input iterator
+template <class containertype>
+class destructive_two_d_iterator {
+ public:
+  typedef destructive_two_d_iterator iterator;
+
+  typedef STL_NAMESPACE::input_iterator_tag iterator_category;
+  // apparently some versions of VC++ have trouble with two ::'s in a typename
+  typedef typename containertype::value_type _tmp_vt;
+  typedef typename _tmp_vt::value_type value_type;
+  typedef typename _tmp_vt::difference_type difference_type;
+  typedef typename _tmp_vt::reference reference;
+  typedef typename _tmp_vt::pointer pointer;
+
+  destructive_two_d_iterator(typename containertype::iterator begin,
+                             typename containertype::iterator end,
+                             typename containertype::iterator curr)
+    : row_begin(begin), row_end(end), row_current(curr), col_current() {
+    if ( curr != end ) {
+      col_current = curr->TWOD_BEGIN_();
+      advance_past_end();                 // in case cur->begin() == cur->end()
+    }
+  }
+  destructive_two_d_iterator(typename containertype::iterator begin,
+                             typename containertype::iterator end,
+                             typename containertype::iterator curr,
+                             typename containertype::value_type::TWOD_ITER_ col)
+    : row_begin(begin), row_end(end), row_current(curr), col_current(col) {
+    advance_past_end();                 // in case cur->begin() == cur->end()
+  }
+  destructive_two_d_iterator()
+    : row_begin(), row_end(), row_current(), col_current() {
+  }
+
+  typename containertype::iterator row_begin, row_end, row_current;
+  typename containertype::value_type::TWOD_ITER_ col_current;
+
+  // This is the part that destroys
+  void advance_past_end() {          // used when col_current points to end()
+    while ( col_current == row_current->TWOD_END_() ) {  // end of current row
+      row_current->clear();                         // the destructive part
+      // It would be nice if we could decrement sparsetable->num_buckets here
+      ++row_current;                                // go to beginning of next
+      if ( row_current != row_end )                 // col is irrelevant at end
+        col_current = row_current->TWOD_BEGIN_();
+      else
+        break;                                      // don't go past row_end
+    }
+  }
+
+  // EVERYTHING FROM HERE DOWN IS THE SAME AS THE REGULAR ITERATOR
+  reference operator*() const    { return *col_current; }
+  pointer operator->() const     { return &(operator*()); }
+
+  iterator& operator++() {
+    assert(row_current != row_end);                 // how to ++ from there?
+    ++col_current;
+    advance_past_end();                 // in case col_current is at end()
+    return *this;
+  }
+  iterator operator++(int)       { iterator tmp(*this); ++*this; return tmp; }
+
+  bool operator==(const iterator& it) const {
+    return ( row_begin == it.row_begin &&
+             row_end == it.row_end &&
+             row_current == it.row_current &&
+             (row_current == row_end || col_current == it.col_current) );
+  }
+  bool operator!=(const iterator& it) const { return !(*this == it); }
+};
+
+#undef TWOD_BEGIN_
+#undef TWOD_END_
+#undef TWOD_ITER_
+#undef TWOD_CONST_ITER_
+
+
+
+
+// SPARSE-TABLE
+// ------------
+// The idea is that a table with (logically) t buckets is divided
+// into t/M *groups* of M buckets each.  (M is a constant set in
+// GROUP_SIZE for efficiency.)  Each group is stored sparsely.
+// Thus, inserting into the table causes some array to grow, which is
+// slow but still constant time.  Lookup involves doing a
+// logical-position-to-sparse-position lookup, which is also slow but
+// constant time.  The larger M is, the slower these operations are
+// but the less overhead (slightly).
+//
+// To store the sparse array, we store a bitmap B, where B[i] = 1 iff
+// bucket i is non-empty.  Then to look up bucket i we really look up
+// array[# of 1s before i in B].  This is constant time for fixed M.
+//
+// Terminology: the position of an item in the overall table (from
+// 1 .. t) is called its "location."  The logical position in a group
+// (from 1 .. M ) is called its "position."  The actual location in
+// the array (from 1 .. # of non-empty buckets in the group) is
+// called its "offset."
+
+// The weird mod in the offset is entirely to quiet compiler warnings
+// as is the cast to int after doing the "x mod 256"
+#define PUT_(take_from, offset)  do {                                          \
+  if (putc(static_cast<int>(((take_from) >> ((offset) % (sizeof(take_from)*8)))\
+                             % 256), fp)                                       \
+      == EOF)                                                                  \
+    return false;                                                              \
+} while (0)
+
+#define GET_(add_to, offset)  do {                                            \
+  if ((x=getc(fp)) == EOF)                                                    \
+    return false;                                                             \
+  else                                                                        \
+    add_to |= (static_cast<size_type>(x) << ((offset) % (sizeof(add_to)*8))); \
+} while (0)
+
+template <class T, u_int16_t GROUP_SIZE>
+class sparsegroup {
+ public:
+  // Basic types
+  typedef T value_type;
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef table_iterator<sparsegroup<T, GROUP_SIZE> > iterator;
+  typedef const_table_iterator<sparsegroup<T, GROUP_SIZE> > const_iterator;
+  typedef table_element_adaptor<sparsegroup<T, GROUP_SIZE> > element_adaptor;
+  typedef value_type &reference;
+  typedef const value_type &const_reference;
+  typedef u_int16_t size_type;                  // max # of buckets
+  typedef int16_t difference_type;
+  typedef STL_NAMESPACE::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<iterator> reverse_iterator;
+
+  // These are our special iterators, that go over non-empty buckets in a
+  // group.  These aren't const-only because you can change non-empty bcks.
+  typedef pointer nonempty_iterator;
+  typedef const_pointer const_nonempty_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<nonempty_iterator> reverse_nonempty_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<const_nonempty_iterator> const_reverse_nonempty_iterator;
+
+  // Iterator functions
+  iterator begin()                      { return iterator(this, 0); }
+  const_iterator begin() const          { return const_iterator(this, 0); }
+  iterator end()                        { return iterator(this, size()); }
+  const_iterator end() const            { return const_iterator(this, size()); }
+  reverse_iterator rbegin()             { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+  reverse_iterator rend()               { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+
+  // We'll have versions for our special non-empty iterator too
+  nonempty_iterator nonempty_begin()             { return group; }
+  const_nonempty_iterator nonempty_begin() const { return group; }
+  nonempty_iterator nonempty_end()               { return group + num_buckets; }
+  const_nonempty_iterator nonempty_end() const   { return group + num_buckets; }
+  reverse_nonempty_iterator nonempty_rbegin() {
+    return reverse_nonempty_iterator(nonempty_end());
+  }
+  const_reverse_nonempty_iterator nonempty_rbegin() const {
+    return const_reverse_nonempty_iterator(nonempty_end());
+  }
+  reverse_nonempty_iterator nonempty_rend() {
+    return reverse_nonempty_iterator(nonempty_begin());
+  }
+  const_reverse_nonempty_iterator nonempty_rend() const {
+    return const_reverse_nonempty_iterator(nonempty_begin());
+  }
+
+
+  // This gives us the "default" value to return for an empty bucket.
+  // We just use the default constructor on T, the template type
+  const_reference default_value() const {
+    static value_type defaultval = value_type();
+    return defaultval;
+  }
+
+
+ private:
+  // We need to do all this bit manipulation, of course.  ick
+  static size_type charbit(size_type i)  { return i >> 3; }
+  static size_type modbit(size_type i)   { return 1 << (i&7); }
+  int bmtest(size_type i) const    { return bitmap[charbit(i)] & modbit(i); }
+  void bmset(size_type i)          { bitmap[charbit(i)] |= modbit(i); }
+  void bmclear(size_type i)        { bitmap[charbit(i)] &= ~modbit(i); }
+
+  void* realloc_or_die(void* ptr, size_t num_bytes) {
+    void* retval = realloc(ptr, num_bytes);
+    if (retval == NULL) {
+      // We really should use PRIuS here, but I don't want to have to add
+      // a whole new configure option, with concomitant macro namespace
+      // pollution, just to print this (unlikely) error message.  So I cast.
+      fprintf(stderr, "FATAL ERROR: failed to allocate %lu bytes for ptr %p",
+              static_cast<unsigned long>(num_bytes), ptr);
+      exit(1);
+    }
+    return retval;
+  }
+
+  value_type* allocate_group(size_t n) {
+    return static_cast<value_type*>(realloc_or_die(NULL,
+                                                   n * sizeof(value_type)));
+  }
+
+  void free_group() {
+    // Valid even for empty group, because NULL+0 is defined to be NULL
+    value_type* end_it = group + num_buckets;
+    for (value_type* p = group; p != end_it; ++p)
+      p->~value_type();
+    free(group);
+    group = NULL;
+  }
+
+ public:                         // get_iter() in sparsetable needs it
+  // We need a small function that tells us how many set bits there are
+  // in positions 0..i-1 of the bitmap.  It uses a big table.
+  // We make it static so templates don't allocate lots of these tables
+  static size_type pos_to_offset(const unsigned char *bm, size_type pos) {
+    // We could make these ints.  The tradeoff is size (eg does it overwhelm
+    // the cache?) vs efficiency in referencing sub-word-sized array elements
+    static const char bits_in[256] = {      // # of bits set in one char
+      0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+      1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+      1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+      1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+      2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+      3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+      3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+      4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+    };
+    size_type retval = 0;
+
+    // [Note: condition pos > 8 is an optimization; convince yourself we
+    // give exactly the same result as if we had pos >= 8 here instead.]
+    for ( ; pos > 8; pos -= 8 )                    // bm[0..pos/8-1]
+      retval += bits_in[*bm++];                    // chars we want *all* bits in
+    return retval + bits_in[*bm & ((1 << pos)-1)]; // the char that includes pos
+  }
+
+  size_type pos_to_offset(size_type pos) const {   // not static but still const
+    return pos_to_offset(bitmap, pos);
+  }
+
+
+ public:
+  // Constructors -- default and copy -- and destructor
+  sparsegroup() : group(0), num_buckets(0) { memset(bitmap, 0, sizeof(bitmap)); }
+  sparsegroup(const sparsegroup& x) : group(0), num_buckets(x.num_buckets) {
+    if ( num_buckets ) {
+      group = allocate_group(x.num_buckets);
+      uninitialized_copy(x.group, x.group + x.num_buckets, group);
+    }
+    memcpy(bitmap, x.bitmap, sizeof(bitmap));
+  }
+  ~sparsegroup() { free_group(); }
+
+  // Operator= is just like the copy constructor, I guess
+  // TODO(austern): Make this exception safe. Handle exceptions in value_type's
+  // copy constructor.
+  sparsegroup &operator=(const sparsegroup& x) {
+    if ( &x == this ) return *this;                    // x = x
+    if ( x.num_buckets == 0 ) {
+      free_group();
+    } else {
+      value_type* p = allocate_group(x.num_buckets);
+      uninitialized_copy(x.group, x.group + x.num_buckets, p);
+      free_group();
+      group = p;
+    }
+    memcpy(bitmap, x.bitmap, sizeof(bitmap));
+    num_buckets = x.num_buckets;
+    return *this;
+  }
+
+  // Many STL algorithms use swap instead of copy constructors
+  void swap(sparsegroup& x) {
+    STL_NAMESPACE::swap(group, x.group);
+    for ( int i = 0; i < sizeof(bitmap) / sizeof(*bitmap); ++i )
+      STL_NAMESPACE::swap(bitmap[i], x.bitmap[i]);  // swap not defined on arrays
+    STL_NAMESPACE::swap(num_buckets, x.num_buckets);
+  }
+
+  // It's always nice to be able to clear a table without deallocating it
+  void clear() {
+    free_group();
+    memset(bitmap, 0, sizeof(bitmap));
+    num_buckets = 0;
+  }
+
+  // Functions that tell you about size.  Alas, these aren't so useful
+  // because our table is always fixed size.
+  size_type size() const           { return GROUP_SIZE; }
+  size_type max_size() const       { return GROUP_SIZE; }
+  bool empty() const               { return false; }
+  // We also may want to know how many *used* buckets there are
+  size_type num_nonempty() const   { return num_buckets; }
+
+
+  // get()/set() are explicitly const/non-const.  You can use [] if
+  // you want something that can be either (potentially more expensive).
+  const_reference get(size_type i) const {
+    if ( bmtest(i) )           // bucket i is occupied
+      return group[pos_to_offset(bitmap, i)];
+    else
+      return default_value();  // return the default reference
+  }
+
+  // TODO(csilvers): make protected + friend
+  reference mutating_get(size_type i) {    // fills bucket i before getting
+    if ( !bmtest(i) )
+      set(i, default_value());
+    return group[pos_to_offset(bitmap, i)];
+  }
+
+  // Syntactic sugar.  It's easy to return a const reference.  To
+  // return a non-const reference, we need to use the assigner adaptor.
+  const_reference operator[](size_type i) const {
+    return get(i);
+  }
+
+  element_adaptor operator[](size_type i) {
+    return element_adaptor(this, i);
+  }
+
+ private:
+  // Create space at group[offset], assuming value_type has trivial
+  // copy constructor and destructor.  (Really, we want it to have
+  // "trivial move", because that's what realloc and memmove both do.
+  // But there's no way to capture that using type_traits, so we
+  // pretend that move(x, y) is equivalent to "x.~T(); new(x) T(y);"
+  // which is pretty much correct, if a bit conservative.)
+  void set_aux(size_type offset, true_type) {
+    group = (value_type *)
+            realloc_or_die(group, sizeof(*group) * (num_buckets+1));
+    // This is equivalent to memmove(), but faster on my Intel P4,
+    // at least with gcc4.1 -O2 / glibc 2.3.6.
+    for (size_type i = num_buckets; i > offset; --i)
+      memcpy(group + i, group + i-1, sizeof(*group));
+  }
+
+  // Create space at group[offset], without special assumptions about value_type
+  void set_aux(size_type offset, false_type) {
+    // This is valid because 0 <= offset <= num_buckets
+    value_type* p = allocate_group(num_buckets + 1);
+    uninitialized_copy(group, group + offset, p);
+    uninitialized_copy(group + offset, group + num_buckets, p + offset + 1);
+    free_group();
+    group = p;
+  }
+
+ public:
+  // This returns a reference to the inserted item (which is a copy of val).
+  // TODO(austern): Make this exception safe: handle exceptions from
+  // value_type's copy constructor.
+  reference set(size_type i, const_reference val) {
+    size_type offset = pos_to_offset(bitmap, i);  // where we'll find (or insert)
+    if ( bmtest(i) ) {
+      // Delete the old value, which we're replacing with the new one
+      group[offset].~value_type();
+    } else {
+      typedef integral_constant<bool,
+          (has_trivial_copy<value_type>::value &&
+           has_trivial_destructor<value_type>::value)>
+          realloc_and_memmove_ok; // we pretend mv(x,y) == "x.~T(); new(x) T(y)"
+      set_aux(offset, realloc_and_memmove_ok());
+      ++num_buckets;
+      bmset(i);
+    }
+    // This does the actual inserting.  Since we made the array using
+    // malloc, we use "placement new" to just call the constructor.
+    new(&group[offset]) value_type(val);
+    return group[offset];
+  }
+
+  // We let you see if a bucket is non-empty without retrieving it
+  bool test(size_type i) const {
+    return bmtest(i) ? true : false;   // cast an int to a bool
+  }
+  bool test(iterator pos) const {
+    return bmtest(pos.pos) ? true : false;
+  }
+
+ private:
+  // Shrink the array, assuming value_type has trivial copy
+  // constructor and destructor.  (Really, we want it to have "trivial
+  // move", because that's what realloc and memmove both do.  But
+  // there's no way to capture that using type_traits, so we pretend
+  // that move(x, y) is equivalent to ""x.~T(); new(x) T(y);"
+  // which is pretty much correct, if a bit conservative.)
+  void erase_aux(size_type offset, true_type) {
+    // This isn't technically necessary, since we know we have a
+    // trivial destructor, but is a cheap way to get a bit more safety.
+    group[offset].~value_type();
+    // This is equivalent to memmove(), but faster on my Intel P4,
+    // at lesat with gcc4.1 -O2 / glibc 2.3.6.
+    assert(num_buckets > 0);
+    for (size_type i = offset; i < num_buckets-1; ++i)
+      memcpy(group + i, group + i+1, sizeof(*group));  // hopefully inlined!
+    group = (value_type *)
+            realloc_or_die(group, sizeof(*group) * (num_buckets-1));
+  }
+
+  // Shrink the array, without any special assumptions about value_type.
+  void erase_aux(size_type offset, false_type) {
+    // This is valid because 0 <= offset < num_buckets. Note the inequality.
+    value_type* p = allocate_group(num_buckets - 1);
+    uninitialized_copy(group, group + offset, p);
+    uninitialized_copy(group + offset + 1, group + num_buckets, p + offset);
+    free_group();
+    group = p;
+  }
+
+ public:
+  // This takes the specified elements out of the group.  This is
+  // "undefining", rather than "clearing".
+  // TODO(austern): Make this exception safe: handle exceptions from
+  // value_type's copy constructor.
+  void erase(size_type i) {
+    if ( bmtest(i) ) {                           // trivial to erase empty bucket
+      size_type offset = pos_to_offset(bitmap,i); // where we'll find (or insert)
+      if ( num_buckets == 1 ) {
+        free_group();
+        group = NULL;
+      } else {
+        typedef integral_constant<bool,
+            (has_trivial_copy<value_type>::value &&
+             has_trivial_destructor<value_type>::value)>
+            realloc_and_memmove_ok; // pretend mv(x,y) == "x.~T(); new(x) T(y)"
+        erase_aux(offset, realloc_and_memmove_ok());
+      }
+      --num_buckets;
+      bmclear(i);
+    }
+  }
+
+  void erase(iterator pos) {
+    erase(pos.pos);
+  }
+
+  void erase(iterator start_it, iterator end_it) {
+    // This could be more efficient, but to do so we'd need to make
+    // bmclear() clear a range of indices.  Doesn't seem worth it.
+    for ( ; start_it != end_it; ++start_it )
+      erase(start_it);
+  }
+
+
+  // I/O
+  // We support reading and writing groups to disk.  We don't store
+  // the actual array contents (which we don't know how to store),
+  // just the bitmap and size.  Meant to be used with table I/O.
+  // Returns true if all was ok
+  bool write_metadata(FILE *fp) const {
+    assert(sizeof(num_buckets) == 2);     // we explicitly set to u_int16_t
+    PUT_(num_buckets, 8);
+    PUT_(num_buckets, 0);
+    if ( !fwrite(bitmap, sizeof(bitmap), 1, fp) )  return false;
+    return true;
+  }
+
+  // Reading destroys the old group contents!  Returns true if all was ok
+  bool read_metadata(FILE *fp) {
+    clear();
+
+    int x;          // the GET_ macro requires an 'int x' to be defined
+    GET_(num_buckets, 8);
+    GET_(num_buckets, 0);
+
+    if ( !fread(bitmap, sizeof(bitmap), 1, fp) )  return false;
+
+    // We'll allocate the space, but we won't fill it: it will be
+    // left as uninitialized raw memory.
+    group = allocate_group(num_buckets);
+    return true;
+  }
+
+  // If your keys and values are simple enough, we can write them
+  // to disk for you.  "simple enough" means POD and no pointers.
+  // However, we don't try to normalize endianness
+  bool write_nopointer_data(FILE *fp) const {
+    for ( const_nonempty_iterator it = nonempty_begin();
+          it != nonempty_end(); ++it ) {
+      if ( !fwrite(&*it, sizeof(*it), 1, fp) )  return false;
+    }
+    return true;
+  }
+
+  // When reading, we have to override the potential const-ness of *it.
+  // Again, only meaningful if value_type is a POD.
+  bool read_nopointer_data(FILE *fp) {
+    for ( nonempty_iterator it = nonempty_begin();
+          it != nonempty_end(); ++it ) {
+      if ( !fread(reinterpret_cast<void*>(&(*it)), sizeof(*it), 1, fp) )
+        return false;
+    }
+    return true;
+  }
+
+  // Comparisons.  Note the comparisons are pretty arbitrary: we
+  // compare values of the first index that isn't equal (using default
+  // value for empty buckets).
+  bool operator==(const sparsegroup& x) const {
+    return ( num_buckets == x.num_buckets &&
+             memcmp(bitmap, x.bitmap, sizeof(bitmap)) == 0 &&
+             STL_NAMESPACE::equal(begin(), end(), x.begin()) ); // from algorithm
+  }
+  bool operator<(const sparsegroup& x) const {      // also from algorithm
+    return STL_NAMESPACE::lexicographical_compare(begin(), end(), 
+                                                  x.begin(), x.end());
+  }
+  bool operator!=(const sparsegroup& x) const { return !(*this == x); }
+  bool operator<=(const sparsegroup& x) const { return !(x < *this); }
+  bool operator>(const sparsegroup& x) const { return x < *this; }
+  bool operator>=(const sparsegroup& x) const { return !(*this < x); }
+
+ private:
+  // The actual data
+  value_type *group;                            // (small) array of T's
+  unsigned char bitmap[(GROUP_SIZE-1)/8 + 1];   // fancy math is so we round up
+  size_type num_buckets;                        // limits GROUP_SIZE to 64K
+};
+
+// We need a global swap as well
+template <class T, u_int16_t GROUP_SIZE>
+inline void swap(sparsegroup<T,GROUP_SIZE> &x, sparsegroup<T,GROUP_SIZE> &y) {
+  x.swap(y);
+}
+
+// ---------------------------------------------------------------------------
+
+
+template <class T, u_int16_t GROUP_SIZE = DEFAULT_SPARSEGROUP_SIZE>
+class sparsetable {
+ public:
+  // Basic types
+  typedef T value_type;                        // stolen from stl_vector.h
+  typedef value_type* pointer;
+  typedef const value_type* const_pointer;
+  typedef table_iterator<sparsetable<T, GROUP_SIZE> > iterator;
+  typedef const_table_iterator<sparsetable<T, GROUP_SIZE> > const_iterator;
+  typedef table_element_adaptor<sparsetable<T, GROUP_SIZE> > element_adaptor;
+  typedef value_type &reference;
+  typedef const value_type &const_reference;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+  typedef STL_NAMESPACE::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<iterator> reverse_iterator;
+
+  // These are our special iterators, that go over non-empty buckets in a
+  // table.  These aren't const only because you can change non-empty bcks.
+  typedef two_d_iterator< vector< sparsegroup<value_type, GROUP_SIZE> > >
+     nonempty_iterator;
+  typedef const_two_d_iterator< vector< sparsegroup<value_type, GROUP_SIZE> > >
+     const_nonempty_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<nonempty_iterator> reverse_nonempty_iterator;
+  typedef STL_NAMESPACE::reverse_iterator<const_nonempty_iterator> const_reverse_nonempty_iterator;
+  // Another special iterator: it frees memory as it iterates (used to resize)
+  typedef destructive_two_d_iterator< vector< sparsegroup<value_type, GROUP_SIZE> > >
+     destructive_iterator;
+
+  // Iterator functions
+  iterator begin()                      { return iterator(this, 0); }
+  const_iterator begin() const          { return const_iterator(this, 0); }
+  iterator end()                        { return iterator(this, size()); }
+  const_iterator end() const            { return const_iterator(this, size()); }
+  reverse_iterator rbegin()             { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+  reverse_iterator rend()               { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+
+  // Versions for our special non-empty iterator
+  nonempty_iterator nonempty_begin()             {
+    return nonempty_iterator(groups.begin(), groups.end(), groups.begin());
+  }
+  const_nonempty_iterator nonempty_begin() const {
+    return const_nonempty_iterator(groups.begin(),groups.end(), groups.begin());
+  }
+  nonempty_iterator nonempty_end() {
+    return nonempty_iterator(groups.begin(), groups.end(), groups.end());
+  }
+  const_nonempty_iterator nonempty_end() const {
+    return const_nonempty_iterator(groups.begin(), groups.end(), groups.end());
+  }
+  reverse_nonempty_iterator nonempty_rbegin() {
+    return reverse_nonempty_iterator(nonempty_end());
+  }
+  const_reverse_nonempty_iterator nonempty_rbegin() const {
+    return const_reverse_nonempty_iterator(nonempty_end());
+  }
+  reverse_nonempty_iterator nonempty_rend() {
+    return reverse_nonempty_iterator(nonempty_begin());
+  }
+  const_reverse_nonempty_iterator nonempty_rend() const {
+    return const_reverse_nonempty_iterator(nonempty_begin());
+  }
+  destructive_iterator destructive_begin() {
+    return destructive_iterator(groups.begin(), groups.end(), groups.begin());
+  }
+  destructive_iterator destructive_end() {
+    return destructive_iterator(groups.begin(), groups.end(), groups.end());
+  }
+
+ private:
+  typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::reference
+    GroupsReference;
+  typedef typename
+    vector< sparsegroup<value_type, GROUP_SIZE> >::const_reference
+    GroupsConstReference;
+  typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::iterator
+    GroupsIterator;
+  typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::const_iterator
+    GroupsConstIterator;
+
+  // How to deal with the proper group
+  static size_type num_groups(size_type num) {   // how many to hold num buckets
+    return num == 0 ? 0 : ((num-1) / GROUP_SIZE) + 1;
+  }
+
+  u_int16_t pos_in_group(size_type i) const {
+    return static_cast<u_int16_t>(i % GROUP_SIZE);
+  }
+  size_type group_num(size_type i) const {
+    return i / GROUP_SIZE;
+  }
+  GroupsReference which_group(size_type i) {
+    return groups[group_num(i)];
+  }
+  GroupsConstReference which_group(size_type i) const {
+    return groups[group_num(i)];
+  }
+
+ public:
+  // Constructors -- default, normal (when you specify size), and copy
+  sparsetable(size_type sz = 0)
+    : groups(num_groups(sz)), table_size(sz), num_buckets(0) { }
+  // We'll can get away with using the default copy constructor,
+  // and default destructor, and hence the default operator=.  Huzzah!
+
+  // Many STL algorithms use swap instead of copy constructors
+  void swap(sparsetable& x) {
+    STL_NAMESPACE::swap(groups, x.groups);
+    STL_NAMESPACE::swap(table_size, x.table_size);
+    STL_NAMESPACE::swap(num_buckets, x.num_buckets);
+  }
+
+  // It's always nice to be able to clear a table without deallocating it
+  void clear() {
+    GroupsIterator group;
+    for ( group = groups.begin(); group != groups.end(); ++group ) {
+      group->clear();
+    }
+    num_buckets = 0;
+  }
+
+  // Functions that tell you about size.
+  // NOTE: empty() is non-intuitive!  It does not tell you the number
+  // of not-empty buckets (use num_nonempty() for that).  Instead
+  // it says whether you've allocated any buckets or not.
+  size_type size() const           { return table_size; }
+  size_type max_size() const       { return size_type(-1); }
+  bool empty() const               { return table_size == 0; }
+  // We also may want to know how many *used* buckets there are
+  size_type num_nonempty() const   { return num_buckets; }
+
+  // OK, we'll let you resize one of these puppies
+  void resize(size_type new_size) {
+    groups.resize(num_groups(new_size));
+    if ( new_size < table_size) {   // lower num_buckets, clear last group
+      if ( pos_in_group(new_size) > 0 )     // need to clear inside last group
+        groups.back().erase(groups.back().begin() + pos_in_group(new_size),
+                            groups.back().end());
+      num_buckets = 0;                       // refigure # of used buckets
+      GroupsConstIterator group;
+      for ( group = groups.begin(); group != groups.end(); ++group )
+        num_buckets += group->num_nonempty();
+    }
+    table_size = new_size;
+  }
+
+
+  // We let you see if a bucket is non-empty without retrieving it
+  bool test(size_type i) const {
+    return which_group(i).test(pos_in_group(i));
+  }
+  bool test(iterator pos) const {
+    return which_group(pos.pos).test(pos_in_group(pos.pos));
+  }
+  bool test(const_iterator pos) const {
+    return which_group(pos.pos).test(pos_in_group(pos.pos));
+  }
+
+  // We only return const_references because it's really hard to
+  // return something settable for empty buckets.  Use set() instead.
+  const_reference get(size_type i) const {
+    assert(i < table_size);
+    return which_group(i).get(pos_in_group(i));
+  }
+
+  // TODO(csilvers): make protected + friend element_adaptor
+  reference mutating_get(size_type i) {    // fills bucket i before getting
+    assert(i < table_size);
+    size_type old_numbuckets = which_group(i).num_nonempty();
+    reference retval = which_group(i).mutating_get(pos_in_group(i));
+    num_buckets += which_group(i).num_nonempty() - old_numbuckets;
+    return retval;
+  }
+
+  // Syntactic sugar.  As in sparsegroup, the non-const version is harder
+  const_reference operator[](size_type i) const {
+    return get(i);
+  }
+
+  element_adaptor operator[](size_type i) {
+    return element_adaptor(this, i);
+  }
+
+  // Needed for hashtables, gets as a nonempty_iterator.  Crashes for empty bcks
+  const_nonempty_iterator get_iter(size_type i) const {
+    assert(test(i));    // how can a nonempty_iterator point to an empty bucket?
+    return const_nonempty_iterator(
+      groups.begin(), groups.end(),
+      groups.begin() + group_num(i),
+      (groups[group_num(i)].nonempty_begin() +
+       groups[group_num(i)].pos_to_offset(pos_in_group(i))));
+  }
+  // For nonempty we can return a non-const version
+  nonempty_iterator get_iter(size_type i) {
+    assert(test(i));    // how can a nonempty_iterator point to an empty bucket?
+    return nonempty_iterator(
+      groups.begin(), groups.end(),
+      groups.begin() + group_num(i),
+      (groups[group_num(i)].nonempty_begin() +
+       groups[group_num(i)].pos_to_offset(pos_in_group(i))));
+  }
+
+
+  // This returns a reference to the inserted item (which is a copy of val)
+  // The trick is to figure out whether we're replacing or inserting anew
+  reference set(size_type i, const_reference val) {
+    assert(i < table_size);
+    size_type old_numbuckets = which_group(i).num_nonempty();
+    reference retval = which_group(i).set(pos_in_group(i), val);
+    num_buckets += which_group(i).num_nonempty() - old_numbuckets;
+    return retval;
+  }
+
+  // This takes the specified elements out of the table.  This is
+  // "undefining", rather than "clearing".
+  void erase(size_type i) {
+    assert(i < table_size);
+    size_type old_numbuckets = which_group(i).num_nonempty();
+    which_group(i).erase(pos_in_group(i));
+    num_buckets += which_group(i).num_nonempty() - old_numbuckets;
+  }
+
+  void erase(iterator pos) {
+    erase(pos.pos);
+  }
+
+  void erase(iterator start_it, iterator end_it) {
+    // This could be more efficient, but then we'd need to figure
+    // out if we spanned groups or not.  Doesn't seem worth it.
+    for ( ; start_it != end_it; ++start_it )
+      erase(start_it);
+  }
+
+
+  // We support reading and writing tables to disk.  We don't store
+  // the actual array contents (which we don't know how to store),
+  // just the groups and sizes.  Returns true if all went ok.
+
+ private:
+  // Every time the disk format changes, this should probably change too
+  static const unsigned long MAGIC_NUMBER = 0x24687531;
+
+  // Old versions of this code write all data in 32 bits.  We need to
+  // support these files as well as having support for 64-bit systems.
+  // So we use the following encoding scheme: for values < 2^32-1, we
+  // store in 4 bytes in big-endian order.  For values > 2^32, we
+  // store 0xFFFFFFF followed by 8 bytes in big-endian order.  This
+  // causes us to mis-read old-version code that stores exactly
+  // 0xFFFFFFF, but I don't think that is likely to have happened for
+  // these particular values.
+  static bool write_32_or_64(FILE* fp, size_type value) {
+    if ( value < 0xFFFFFFFFULL ) {        // fits in 4 bytes
+      PUT_(value, 24);
+      PUT_(value, 16);
+      PUT_(value, 8);
+      PUT_(value, 0);
+    } else if ( value == 0xFFFFFFFFUL ) {   // special case in 32bit systems
+      PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0);  // marker
+      PUT_(0, 0); PUT_(0, 0); PUT_(0, 0); PUT_(0, 0);
+      PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0);
+    } else {
+      PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0); PUT_(0xFF, 0);  // marker
+      PUT_(value, 56);
+      PUT_(value, 48);
+      PUT_(value, 40);
+      PUT_(value, 32);
+      PUT_(value, 24);
+      PUT_(value, 16);
+      PUT_(value, 8);
+      PUT_(value, 0);
+    }
+    return true;
+  }
+
+  static bool read_32_or_64(FILE* fp, size_type *value) {  // reads into value
+    size_type first4 = 0;
+    int x;
+    GET_(first4, 24);
+    GET_(first4, 16);
+    GET_(first4, 8);
+    GET_(first4, 0);
+    if ( first4 < 0xFFFFFFFFULL ) {
+      *value = first4;
+    } else {
+      GET_(*value, 56);
+      GET_(*value, 48);
+      GET_(*value, 40);
+      GET_(*value, 32);
+      GET_(*value, 24);
+      GET_(*value, 16);
+      GET_(*value, 8);
+      GET_(*value, 0);
+    }
+    return true;
+  }
+
+ public:
+  bool write_metadata(FILE *fp) const {
+    if ( !write_32_or_64(fp, MAGIC_NUMBER) )  return false;
+    if ( !write_32_or_64(fp, table_size) )  return false;
+    if ( !write_32_or_64(fp, num_buckets) )  return false;
+
+    GroupsConstIterator group;
+    for ( group = groups.begin(); group != groups.end(); ++group )
+      if ( group->write_metadata(fp) == false )  return false;
+    return true;
+  }
+
+  // Reading destroys the old table contents!  Returns true if read ok.
+  bool read_metadata(FILE *fp) {
+    size_type magic_read = 0;
+    if ( !read_32_or_64(fp, &magic_read) )  return false;
+    if ( magic_read != MAGIC_NUMBER ) {
+      clear();                        // just to be consistent
+      return false;
+    }
+
+    if ( !read_32_or_64(fp, &table_size) )  return false;
+    if ( !read_32_or_64(fp, &num_buckets) )  return false;
+
+    resize(table_size);                            // so the vector's sized ok
+    GroupsIterator group;
+    for ( group = groups.begin(); group != groups.end(); ++group )
+      if ( group->read_metadata(fp) == false )  return false;
+    return true;
+  }
+
+  // This code is identical to that for SparseGroup
+  // If your keys and values are simple enough, we can write them
+  // to disk for you.  "simple enough" means no pointers.
+  // However, we don't try to normalize endianness
+  bool write_nopointer_data(FILE *fp) const {
+    for ( const_nonempty_iterator it = nonempty_begin();
+          it != nonempty_end(); ++it ) {
+      if ( !fwrite(&*it, sizeof(*it), 1, fp) )  return false;
+    }
+    return true;
+  }
+
+  // When reading, we have to override the potential const-ness of *it
+  bool read_nopointer_data(FILE *fp) {
+    for ( nonempty_iterator it = nonempty_begin();
+          it != nonempty_end(); ++it ) {
+      if ( !fread(reinterpret_cast<void*>(&(*it)), sizeof(*it), 1, fp) )
+        return false;
+    }
+    return true;
+  }
+
+  // Comparisons.  Note the comparisons are pretty arbitrary: we
+  // compare values of the first index that isn't equal (using default
+  // value for empty buckets).
+  bool operator==(const sparsetable& x) const {
+    return ( table_size == x.table_size &&
+             num_buckets == x.num_buckets &&
+             groups == x.groups );
+  }
+  bool operator<(const sparsetable& x) const {      // also from algobase.h
+    return STL_NAMESPACE::lexicographical_compare(begin(), end(), 
+                                                  x.begin(), x.end());
+  }
+  bool operator!=(const sparsetable& x) const { return !(*this == x); }
+  bool operator<=(const sparsetable& x) const { return !(x < *this); }
+  bool operator>(const sparsetable& x) const { return x < *this; }
+  bool operator>=(const sparsetable& x) const { return !(*this < x); }
+
+
+ private:
+  // The actual data
+  vector< sparsegroup<value_type, GROUP_SIZE> > groups;  // our list of groups
+  size_type table_size;                         // how many buckets they want
+  size_type num_buckets;                        // number of non-empty buckets
+};
+
+// We need a global swap as well
+template <class T, u_int16_t GROUP_SIZE>
+inline void swap(sparsetable<T,GROUP_SIZE> &x, sparsetable<T,GROUP_SIZE> &y) {
+  x.swap(y);
+}
+
+#undef GET_
+#undef PUT_
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/3rdparty/google/type_traits.h b/3rdparty/google/type_traits.h
new file mode 100644
index 0000000000..5f88133b95
--- /dev/null
+++ b/3rdparty/google/type_traits.h
@@ -0,0 +1,250 @@
+// Copyright (c) 2006, Google Inc.
+// 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 Google Inc. 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.
+
+// ----
+// Author: Matt Austern
+//
+// Define a small subset of tr1 type traits. The traits we define are:
+//   is_integral
+//   is_floating_point
+//   is_pointer
+//   is_reference
+//   is_pod
+//   has_trivial_constructor
+//   has_trivial_copy
+//   has_trivial_assign
+//   has_trivial_destructor
+//   remove_const
+//   remove_volatile
+//   remove_cv
+//   remove_reference
+//   remove_pointer
+//   is_convertible
+// We can add more type traits as required.
+
+#ifndef BASE_TYPE_TRAITS_H_
+#define BASE_TYPE_TRAITS_H_
+
+#include <google/sparsehash/sparseconfig.h>
+#include <utility>                  // For pair
+
+_START_GOOGLE_NAMESPACE_
+
+// integral_constant, defined in tr1, is a wrapper for an integer
+// value. We don't really need this generality; we could get away
+// with hardcoding the integer type to bool. We use the fully
+// general integer_constant for compatibility with tr1.
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+// Abbreviations: true_type and false_type are structs that represent
+// boolean true and false values.
+typedef integral_constant<bool, true>  true_type;
+typedef integral_constant<bool, false> false_type;
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+  char dummy[2];
+};
+
+// is_integral is false except for the built-in integer types.
+template <class T> struct is_integral : false_type { };
+template<> struct is_integral<bool> : true_type { };
+template<> struct is_integral<char> : true_type { };
+template<> struct is_integral<unsigned char> : true_type { };
+template<> struct is_integral<signed char> : true_type { };
+#if defined(_MSC_VER)
+// wchar_t is not by default a distinct type from unsigned short in
+// Microsoft C.
+// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
+template<> struct is_integral<__wchar_t> : true_type { };
+#else
+template<> struct is_integral<wchar_t> : true_type { };
+#endif
+template<> struct is_integral<short> : true_type { };
+template<> struct is_integral<unsigned short> : true_type { };
+template<> struct is_integral<int> : true_type { };
+template<> struct is_integral<unsigned int> : true_type { };
+template<> struct is_integral<long> : true_type { };
+template<> struct is_integral<unsigned long> : true_type { };
+#ifdef HAVE_LONG_LONG
+template<> struct is_integral<long long> : true_type { };
+template<> struct is_integral<unsigned long long> : true_type { };
+#endif
+
+
+// is_floating_point is false except for the built-in floating-point types.
+template <class T> struct is_floating_point : false_type { };
+template<> struct is_floating_point<float> : true_type { };
+template<> struct is_floating_point<double> : true_type { };
+template<> struct is_floating_point<long double> : true_type { };
+
+
+// is_pointer is false except for pointer types.
+template <class T> struct is_pointer : false_type { };
+template <class T> struct is_pointer<T*> : true_type { };
+
+
+// is_reference is false except for reference types.
+template<typename T> struct is_reference : false_type {};
+template<typename T> struct is_reference<T&> : true_type {};
+
+
+// We can't get is_pod right without compiler help, so fail conservatively.
+// We will assume it's false except for arithmetic types and pointers,
+// and const versions thereof. Note that std::pair is not a POD.
+template <class T> struct is_pod
+ : integral_constant<bool, (is_integral<T>::value ||
+                            is_floating_point<T>::value ||
+                            is_pointer<T>::value)> { };
+template <class T> struct is_pod<const T> : is_pod<T> { };
+
+
+// We can't get has_trivial_constructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// constructors. (3) array of a type with a trivial constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_constructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_constructor<T>::value &&
+                       has_trivial_constructor<U>::value)> { };
+template <class A, int N> struct has_trivial_constructor<A[N]>
+  : has_trivial_constructor<A> { };
+template <class T> struct has_trivial_constructor<const T>
+  : has_trivial_constructor<T> { };
+
+// We can't get has_trivial_copy right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial copy constructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_copy : is_pod<T> { };
+template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_copy<T>::value &&
+                       has_trivial_copy<U>::value)> { };
+template <class A, int N> struct has_trivial_copy<A[N]>
+  : has_trivial_copy<A> { };
+template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
+
+// We can't get has_trivial_assign right without compiler help, so fail
+// conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial copy
+// constructors. (3) array of a type with a trivial assign constructor.
+template <class T> struct has_trivial_assign : is_pod<T> { };
+template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_assign<T>::value &&
+                       has_trivial_assign<U>::value)> { };
+template <class A, int N> struct has_trivial_assign<A[N]>
+  : has_trivial_assign<A> { };
+
+// We can't get has_trivial_destructor right without compiler help, so
+// fail conservatively. We will assume it's false except for: (1) types
+// for which is_pod is true. (2) std::pair of types with trivial
+// destructors. (3) array of a type with a trivial destructor.
+// (4) const versions thereof.
+template <class T> struct has_trivial_destructor : is_pod<T> { };
+template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
+  : integral_constant<bool,
+                      (has_trivial_destructor<T>::value &&
+                       has_trivial_destructor<U>::value)> { };
+template <class A, int N> struct has_trivial_destructor<A[N]>
+  : has_trivial_destructor<A> { };
+template <class T> struct has_trivial_destructor<const T>
+  : has_trivial_destructor<T> { };
+
+// Specified by TR1 [4.7.1]
+template<typename T> struct remove_const { typedef T type; };
+template<typename T> struct remove_const<T const> { typedef T type; };
+template<typename T> struct remove_volatile { typedef T type; };
+template<typename T> struct remove_volatile<T volatile> { typedef T type; };
+template<typename T> struct remove_cv {
+  typedef typename remove_const<typename remove_volatile<T>::type>::type type;
+};
+
+
+// Specified by TR1 [4.7.2]
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+
+// Specified by TR1 [4.7.4] Pointer modifications.
+template<typename T> struct remove_pointer { typedef T type; };
+template<typename T> struct remove_pointer<T*> { typedef T type; };
+template<typename T> struct remove_pointer<T* const> { typedef T type; };
+template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
+template<typename T> struct remove_pointer<T* const volatile> {
+  typedef T type; };
+
+// Specified by TR1 [4.6] Relationships between types
+#ifndef _MSC_VER
+namespace internal {
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+template <typename From, typename To>
+struct ConvertHelper {
+  static small_ Test(To);
+  static big_ Test(...);
+  static From Create();
+};
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper<From, To>::Test(
+                                  internal::ConvertHelper<From, To>::Create()))
+                        == sizeof(small_)> {
+};
+#endif
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_TYPE_TRAITS_H_
diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp
index 310079f376..c3a520538d 100644
--- a/pcsx2/Hw.cpp
+++ b/pcsx2/Hw.cpp
@@ -130,13 +130,13 @@ int hwMFIFOWrite(u32 addr, u8 *data, u32 size) {
 		/* it does, so first copy 's1' bytes from 'data' to 'addr' */
 		dst = (u8*)PSM(addr);
 		if (dst == NULL) return -1;
-		Cpu->Clear(addr, s1/4);
+		//Cpu->Clear(addr, s1/4);
 		memcpy_fast(dst, data, s1);
 
 		/* and second copy 's2' bytes from '&data[s1]' to 'maddr' */
 		dst = (u8*)PSM(psHu32(DMAC_RBOR));
 		if (dst == NULL) return -1;
-		Cpu->Clear(psHu32(DMAC_RBOR), s2/4);
+		//Cpu->Clear(psHu32(DMAC_RBOR), s2/4);
 		memcpy_fast(dst, &data[s1], s2);
 	} else {
 		//u32 * tempptr, * tempptr2;
@@ -144,7 +144,7 @@ int hwMFIFOWrite(u32 addr, u8 *data, u32 size) {
 		/* it doesn't, so just copy 'size' bytes from 'data' to 'addr' */
 		dst = (u8*)PSM(addr);
 		if (dst == NULL) return -1;
-		Cpu->Clear(addr, size/4);
+		//Cpu->Clear(addr, size/4);
 		memcpy_fast(dst, data, size);
 	}
 
diff --git a/pcsx2/MemoryVM.cpp b/pcsx2/MemoryVM.cpp
deleted file mode 100644
index 132b4db9ce..0000000000
--- a/pcsx2/MemoryVM.cpp
+++ /dev/null
@@ -1,2140 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
- *  Copyright (C) 2002-2009  Pcsx2 Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-// Virtual memory model for Pcsx2.
-// This module is left in primarily as a reference for the implementation of constant
-// propagation.
-
-#include "PrecompiledHeader.h"
-#include "Common.h"
-#include "iR5900.h"
-
-#include "PsxCommon.h"
-#include "VUmicro.h"
-#include "GS.h"
-#include "vtlb.h"
-#include "IPU/IPU.h"
-
-#ifdef PCSX2_VIRTUAL_MEM
-#include "iR3000A.h"		// VM handles both Iop and EE memory from here. >_<
-#include "Counters.h"
-#endif
-
-#pragma warning(disable:4799) // No EMMS at end of function
-
-#ifdef ENABLECACHE
-#include "Cache.h"
-#endif
-
-#ifdef __LINUX__
-#include <sys/mman.h>
-#endif
-
-/////////////////////////////
-// VIRTUAL MEM START 
-/////////////////////////////
-#ifdef PCSX2_VIRTUAL_MEM
-
-class vm_alloc_failed_exception : public std::runtime_error
-{
-public:
-	void* requested_addr;
-	int requested_size;
-	void* returned_addr;
-
-	explicit vm_alloc_failed_exception( void* reqadr, uint reqsize, void* retadr ) :
-	std::runtime_error( "virtual memory allocation failure." )
-		, requested_addr( reqadr )
-		, requested_size( reqsize )
-		, returned_addr( retadr )
-	{}
-};
-
-PSMEMORYBLOCK s_psM = {0}, s_psHw = {0}, s_psS = {0}, s_psxM = {0}, s_psVuMem = {0};
-
-static void PHYSICAL_ALLOC( void* ptr, uint size, PSMEMORYBLOCK& block)
-{
-	if(SysPhysicalAlloc(size, &block) == -1 )
-		throw vm_alloc_failed_exception( ptr, size, NULL );
-	if(SysVirtualPhyAlloc(ptr, size, &block) == -1)
-		throw vm_alloc_failed_exception( ptr, size, NULL );
-}
-
-static void PHYSICAL_FREE( void* ptr, uint size, PSMEMORYBLOCK& block)
-{
-	SysVirtualFree(ptr, size);
-	SysPhysicalFree(&block);
-}
-
-
-#ifdef _WIN32 // windows implementation of vm
-
-static PSMEMORYMAP initMemoryMap(uptr* aPFNs, uptr* aVFNs)
-{
-	PSMEMORYMAP m;
-	m.aPFNs = aPFNs;
-	m.aVFNs = aVFNs;
-	return m;
-}
-
-// only do vm hack for release
-#ifndef PCSX2_DEVBUILD
-#define VM_HACK
-#endif
-
-// virtual memory blocks
-PSMEMORYMAP *memLUT = NULL;
-
-static void VIRTUAL_ALLOC( void* base, uint size, uint Protection)
-{
-	LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE|MEM_COMMIT, Protection );
-	if( base != lpMemReserved )
-		throw vm_alloc_failed_exception( base, size, lpMemReserved );
-}
-
-static void ReserveExtraMem( void* base, uint size )
-{
-	void* pExtraMem = VirtualAlloc(base, size, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE);
-	if( pExtraMem != base )
-		throw vm_alloc_failed_exception( base, size, pExtraMem);
-}
-
-void memAlloc()
-{
-	LPVOID pExtraMem = NULL;	
-
-	// release the previous reserved mem
-	VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE);
-
-	try
-	{
-		// allocate all virtual memory
-		PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM);
-		VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY);
-		VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY);
-		VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY);
-		VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY);
-		PHYSICAL_ALLOC(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS);
-		PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
-		PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
-		PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
-
-		VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PAGE_READWRITE);
-		//VIRTUAL_ALLOC(PS2MEM_PSXHW2, 0x00010000, PAGE_READWRITE);
-		VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PAGE_NOACCESS);
-		VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PAGE_READWRITE);
-		VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PAGE_NOACCESS);
-		VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PAGE_NOACCESS);
-		VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PAGE_NOACCESS);
-
-		VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PAGE_READWRITE);
-		VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PAGE_READWRITE);
-
-		// reserve the left over 224Mb, don't map
-		ReserveExtraMem( PS2MEM_BASE+Ps2MemSize::Base, 0x0e000000 );
-
-		// reserve left over psx mem
-		ReserveExtraMem( PS2MEM_PSX+Ps2MemSize::IopRam, 0x00600000 );
-
-		// reserve gs mem
-		ReserveExtraMem( PS2MEM_BASE+0x20000000, 0x10000000 );
-
-		// special addrs mmap
-		VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PAGE_READWRITE);
-
-		// alloc virtual mappings
-		if( memLUT == NULL )
-			memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16);
-		if( memLUT == NULL )
-			throw Exception::OutOfMemory( "memAlloc VM > failed to allocated memory for LUT." );
-	}
-	catch( vm_alloc_failed_exception& ex )
-	{
-		Console::Error( "Virtual Memory Error > Cannot reserve %dk memory block at 0x%8.8x", params
-			ex.requested_size / 1024, ex.requested_addr );
-
-		Console::Error( "\tError code: %d  \tReturned address: 0x%8.8x", params
-			GetLastError(), ex.returned_addr);
-
-		memShutdown();
-	}
-	catch( std::exception& )
-	{
-		memShutdown();
-	}
-}
-
-void memShutdown()
-{
-	// Free up the "extra mem" reservations
-	VirtualFree(PS2MEM_BASE+Ps2MemSize::Base, 0, MEM_RELEASE);
-	VirtualFree(PS2MEM_PSX+Ps2MemSize::IopRam, 0, MEM_RELEASE);
-	VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE);		// GS reservation
-
-	PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM);
-	SysMunmap(PS2MEM_ROM, Ps2MemSize::Rom);
-	SysMunmap(PS2MEM_ROM1, Ps2MemSize::Rom1);
-	SysMunmap(PS2MEM_ROM2, Ps2MemSize::Rom2);
-	SysMunmap(PS2MEM_EROM, Ps2MemSize::ERom);
-	PHYSICAL_FREE(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS);
-	PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
-	PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
-	PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
-
-	SysMunmap(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs
-
-	SysMunmap(PS2MEM_PSXHW, Ps2MemSize::IopHardware);
-	//SysMunmap(PS2MEM_PSXHW2, 0x00010000);
-	SysMunmap(PS2MEM_PSXHW4, 0x00010000);
-	SysMunmap(PS2MEM_GS, 0x00002000);
-	SysMunmap(PS2MEM_DEV9, 0x00010000);
-	SysMunmap(PS2MEM_SPU2, 0x00010000);
-	SysMunmap(PS2MEM_SPU2_, 0x00010000);
-
-	SysMunmap(PS2MEM_B80, 0x00010000);
-	SysMunmap(PS2MEM_BA0, 0x00010000);
-
-	// Special Addrs.. ?
-	SysMunmap(PS2MEM_BASE+0x5fff0000, 0x10000);
-
-	VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE);
-
-	safe_aligned_free( memLUT );
-
-	// reserve mem
-	VirtualAlloc(PS2MEM_BASE, 0x40000000, MEM_RESERVE, PAGE_NOACCESS);
-}
-
-//NOTE: A lot of the code reading depends on the registers being less than 8
-// MOV8 88/8A
-// MOV16 6689
-// MOV32 89/8B
-// SSEMtoR64 120f
-// SSERtoM64 130f
-// SSEMtoR128 280f
-// SSERtoM128 290f
-
-#define SKIP_WRITE() { \
-	switch(code&0xff) { \
-		case 0x88: \
-		if( !(code&0x8000) ) goto DefaultHandler; \
-		ContextRecord->Eip += 6; \
-		break; \
-		case 0x66: \
-		assert( code&0x800000 ); \
-		assert( (code&0xffff) == 0x8966 ); \
-		ContextRecord->Eip += 7; \
-		break; \
-		case 0x89: \
-		assert( code&0x8000 ); \
-		ContextRecord->Eip += 6; \
-		break; \
-		case 0x0f: /* 130f, 230f*/ \
-		assert( (code&0xffff) == 0x290f || (code&0xffff) == 0x130f ); \
-		assert( code&0x800000 ); \
-		ContextRecord->Eip += 7; \
-		break; \
-		default: \
-		goto DefaultHandler; \
-} \
-} \
-
-#define SKIP_READ() { \
-	switch(code&0xff) { \
-		case 0x8A: \
-		if( !(code&0x8000) ) goto DefaultHandler; \
-		ContextRecord->Eip += 6; \
-		rd = (code>>(8+3))&7; \
-		break; \
-		case 0x66: \
-		if( (code&0x07000000) == 0x05000000 ) ContextRecord->Eip += 8; /* 8 for mem reads*/ \
-			else ContextRecord->Eip += 4 + ((code&0x1f000000) == 0x0c000000) + !!(code&0x40000000); \
-			rd = (code>>(24+3))&7; \
-			break; \
-		case 0x8B: \
-		if( !(code&0x8000) ) goto DefaultHandler; \
-		ContextRecord->Eip += 6; \
-		rd = (code>>(8+3))&7; \
-		break; \
-		case 0x0f: { \
-		assert( (code&0xffff)==0x120f || (code&0xffff)==0x280f || (code&0xffff) == 0xb60f || (code&0xffff) == 0xb70f ); \
-		if( !(code&0x800000) ) goto DefaultHandler; \
-		ContextRecord->Eip += 7; \
-		rd = (code>>(16+3))&7; \
-		break; } \
-		default: \
-		goto DefaultHandler; \
-} \
-} \
-
-int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
-{
-	struct _EXCEPTION_RECORD* ExceptionRecord = eps->ExceptionRecord;
-	struct _CONTEXT* ContextRecord = eps->ContextRecord;
-
-	u32 addr;
-
-	C_ASSERT(sizeof(ContextRecord->Eax) == 4);
-
-	// If the exception is not a page fault, exit.
-	if (ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
-	{
-		return EXCEPTION_CONTINUE_SEARCH;
-	}
-
-	// get bad virtual address
-	addr = (u32)ExceptionRecord->ExceptionInformation[1];
-
-	if( (unsigned)(addr-(u32)PS2MEM_BASE) < 0x60000000) {
-		PSMEMORYMAP* pmap;
-
-		pmap = &memLUT[(addr-(u32)PS2MEM_BASE)>>12];
-
-		if( !pmap->aPFNs ) {
-			// NOTE: this is a hack because the address is truncated and there's no way
-			// to tell what it's upper bits are (due to OS limitations).
-			pmap += 0x80000;
-			if( !pmap->aPFNs ) {
-				pmap += 0x20000;
-				if( !pmap->aPFNs ) goto OtherException;
-			}
-			//else addr += 0x20000000;
-		}
-
-		{
-			//LPVOID pnewaddr; not used
-			uptr curvaddr = pmap->aVFNs[0];
-
-			if( curvaddr ) {
-				// delete the current mapping
-				SysMapUserPhysicalPages((void*)curvaddr, 1, NULL, 0);
-			}
-
-			assert( pmap->aPFNs[0] != 0 );
-
-			pmap->aVFNs[0] = curvaddr = addr&~0xfff;
-			if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) )
-				return EXCEPTION_CONTINUE_EXECUTION;
-
-			// try allocing the virtual mem
-			//pnewaddr = <- not used
-			/* use here the size of allocation granularity and force rounding down,
-			because in reserve mode the address is rounded up/down to the nearest
-			multiple of this granularity; if you did it not this way, in some cases
-			the same address would be used twice, so the api fails */
-			VirtualAlloc((void*)(curvaddr&~0xffff), 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE);
-
-			if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) )
-				return EXCEPTION_CONTINUE_EXECUTION;
-
-			Console::Error("Virtual Memory Error > page 0x%x cannot be found %d (p:%x,v:%x)", params
-				addr-(u32)PS2MEM_BASE, GetLastError(), pmap->aPFNs[0], curvaddr);
-		}
-	}
-	// check if vumem
-	else if( (addr&0xffff4000) == 0x11000000 ) {
-		// vu0mem
-		SysMapUserPhysicalPages((void*)s_psVuMem.aVFNs[1], 1, NULL, 0);
-
-		s_psVuMem.aVFNs[1] = addr&~0xfff;
-		SysMapUserPhysicalPages((void*)addr, 1, s_psVuMem.aPFNs, 1);
-
-		//SysPrintf("Exception: vumem\n");
-		return EXCEPTION_CONTINUE_EXECUTION;
-	}
-OtherException:
-
-#ifdef VM_HACK
-	{
-		u32 code = *(u32*)ExceptionRecord->ExceptionAddress;
-		u32 rd = 0;
-
-		if( ExceptionRecord->ExceptionInformation[0] ) {
-			//SKIP_WRITE();
-			// shouldn't be writing
-		}
-		else {
-			SysPrintf("vmhack ");
-			SKIP_READ();
-			//((u32*)&ContextRecord->Eax)[rd] = 0;
-			return EXCEPTION_CONTINUE_EXECUTION; // TODO: verify this!!!
-		}
-	}
-DefaultHandler:
-#endif
-
-	return EXCEPTION_CONTINUE_SEARCH;
-}
-
-#else // linux implementation
-
-#define VIRTUAL_ALLOC(base, size, Protection) { \
-	void* lpMemReserved = mmap( base, size, Protection, MAP_PRIVATE|MAP_ANONYMOUS ); \
-	if( lpMemReserved == NULL || base != lpMemReserved ) \
-{ \
-	SysPrintf("Cannot reserve memory at 0x%8.8x(%x).\n", base, lpMemReserved); \
-	perror("err"); \
-	goto eCleanupAndExit; \
-} \
-} \
-
-#define VIRTUAL_FREE(ptr, size) munmap(ptr, size)
-
-uptr *memLUT = NULL;
-
-void memAlloc()
-{
-	int i;
-	LPVOID pExtraMem = NULL;	
-
-	// release the previous reserved mem
-	munmap(PS2MEM_BASE, 0x40000000);
-
-	// allocate all virtual memory
-	PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM);
-	VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PROT_READ);
-	VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PROT_READ);
-	VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PROT_READ);
-	VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PROT_READ);
-	PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS);
-	PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
-	PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
-	PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
-
-	VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PROT_READ|PROT_WRITE);
-	VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PROT_NONE);
-	VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PROT_READ|PROT_WRITE);
-	VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PROT_NONE);
-	VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PROT_NONE);
-	VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PROT_NONE);
-
-	VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PROT_READ|PROT_WRITE);
-	VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PROT_READ|PROT_WRITE);
-
-	// special addrs mmap
-	VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PROT_READ|PROT_WRITE);
-
-eCleanupAndExit:
-	memShutdown();
-	return -1;
-}
-
-void memShutdown()
-{
-	VIRTUAL_FREE(PS2MEM_BASE, 0x40000000);
-	VIRTUAL_FREE(PS2MEM_PSX, 0x00800000);
-
-	PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM);
-	VIRTUAL_FREE(PS2MEM_ROM, Ps2MemSize::Rom);
-	VIRTUAL_FREE(PS2MEM_ROM1, Ps2MemSize::Rom1);
-	VIRTUAL_FREE(PS2MEM_ROM2, Ps2MemSize::Rom2);
-	VIRTUAL_FREE(PS2MEM_EROM, Ps2MemSize::ERom);
-	PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS);
-	PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw);
-	PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM);
-	PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem);
-
-	VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs
-
-	VIRTUAL_FREE(PS2MEM_PSXHW, Ps2MemSize::IopHardware);
-	VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000);
-	VIRTUAL_FREE(PS2MEM_GS, 0x00002000);
-	VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000);
-	VIRTUAL_FREE(PS2MEM_SPU2, 0x00010000);
-	VIRTUAL_FREE(PS2MEM_SPU2_, 0x00010000);
-
-	VIRTUAL_FREE(PS2MEM_B80, 0x00010000);
-	VIRTUAL_FREE(PS2MEM_BA0, 0x00010000);
-
-	VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE);
-
-	safe_aligned_free(memLUT); 
-
-	// reserve mem
-	if( mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) != PS2MEM_BASE ) {
-		SysPrintf("failed to reserve mem\n");
-	}
-}
-
-#endif // _WIN32
-
-void vm_Reset()
-{
-	jASSUME( memLUT != NULL );
-
-	memzero_ptr<sizeof(PSMEMORYMAP)*0x100000>(memLUT);
-	for (int i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]);
-	for (int i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]);
-	for (int i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]);
-	for (int i=0; i<0x00004; i++)
-	{
-		memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]);
-		memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]);
-		memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]);
-		memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]);
-
-		// Yay! Scratchpad mapping!  We love the scratchpad.
-		memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]);
-	}
-
-	// map to other modes
-	memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
-	memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP));
-}
-
-// Some games read/write between different addrs but same physical memory
-// this causes major slowdowns because it goes into the exception handler, so use this (zerofrog)
-u32 VM_RETRANSLATE(u32 mem)
-{
-	u8* p, *pbase;
-	if( (mem&0xffff0000) == 0x50000000 ) // reserved scratch pad mem
-		return PS2MEM_BASE_+mem;
-
-	p = (u8*)dmaGetAddrBase(mem);
-
-#ifdef _WIN32	
-	// do manual LUT since IPU/SPR seems to use addrs 0x3000xxxx quite often
-	if( memLUT[ (p-PS2MEM_BASE)>>12 ].aPFNs == NULL ) {
-		return PS2MEM_BASE_+mem;
-	}
-
-	pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0];
-	if( pbase != NULL )
-		p = pbase + ((u32)p&0xfff);
-#endif
-
-	return (u32)p;
-}
-
-void memSetPageAddr(u32 vaddr, u32 paddr) {
-
-	PSMEMORYMAP* pmap;
-
-	if( vaddr == paddr )
-		return;
-
-	if( (vaddr>>28) != 1 && (vaddr>>28) != 9 && (vaddr>>28) != 11 ) {
-#ifdef _WIN32
-		pmap = &memLUT[vaddr >> 12];
-
-		if( pmap->aPFNs != NULL && (pmap->aPFNs != memLUT[paddr>>12].aPFNs ||
-			pmap->aVFNs[0] != TRANSFORM_ADDR(vaddr)+(u32)PS2MEM_BASE) ) {
-
-				SysMapUserPhysicalPages((void*)pmap->aVFNs[0], 1, NULL, 0);
-				pmap->aVFNs[0] = 0;
-		}
-
-		*pmap = memLUT[paddr >> 12];
-#else
-		memLUT[vaddr>>12] = memLUT[paddr>>12];
-#endif
-	}
-}
-
-void memClearPageAddr(u32 vaddr) {
-	//	SysPrintf("memClearPageAddr: %8.8x\n", vaddr);
-
-	if ((vaddr & 0xffffc000) == 0x70000000) return;
-
-#ifdef _WIN32
-	//	if( vaddr >= 0x20000000 && vaddr < 0x80000000 ) {
-	//		Cpu->Clear(vaddr&~0xfff, 0x1000/4);
-	//		if( memLUT[vaddr>>12].aVFNs != NULL ) {
-	//			SysMapUserPhysicalPages((void*)memLUT[vaddr>>12].aVFNs[0], 1, NULL, 0 );
-	//			memLUT[vaddr>>12].aVFNs = NULL;
-	//			memLUT[vaddr>>12].aPFNs = NULL;
-	//		}
-	//	}
-#else
-	if( memLUT[vaddr>>12] != NULL ) {
-		SysVirtualFree(memLUT[vaddr>>12], 0x1000);
-		memLUT[vaddr>>12] = 0;
-	}
-#endif
-}
-
-u8 recMemRead8()
-{
-	register u32 mem;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-
-		switch( (mem&~0xffff) ) {
-case 0x1f400000: return psxHw4Read8(mem);
-case 0x10000000: return hwRead8(mem);
-case 0x1f800000: return psxHwRead8(mem);
-case 0x12000000: return *(PS2MEM_BASE+(mem&~0xc00));
-case 0x14000000:
-	{
-		u32 ret = DEV9read8(mem & ~0x04000000);
-		SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret);
-		return ret;
-	}
-
-default:
-	return *(u8*)(PS2MEM_BASE+mem);
-	}
-	MEM_LOG("Unknown Memory read32  from address %8.8x\n", mem);
-
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return 0;
-}
-
-void _eeReadConstMem8(int mmreg, u32 mem, int sign)
-{
-	assert( !IS_XMMREG(mmreg));
-
-	if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVDMtoMMX(mmreg&0xf, mem-3);
-		assert(0);
-	}
-	else {
-		if( sign ) MOVSX32M8toR(mmreg, mem);
-		else MOVZX32M8toR(mmreg, mem);
-	}
-}
-
-void _eeReadConstMem16(int mmreg, u32 mem, int sign)
-{
-	assert( !IS_XMMREG(mmreg));
-
-	if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVDMtoMMX(mmreg&0xf, mem-2);
-		assert(0);
-	}
-	else {
-		if( sign ) MOVSX32M16toR(mmreg, mem);
-		else MOVZX32M16toR(mmreg, mem);
-	}
-}
-
-void _eeReadConstMem32(int mmreg, u32 mem)
-{
-	if( IS_XMMREG(mmreg) ) SSEX_MOVD_M32_to_XMM(mmreg&0xf, mem);
-	else if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVDMtoMMX(mmreg&0xf, mem);
-	}
-	else MOV32MtoR(mmreg, mem);
-}
-
-void _eeReadConstMem128(int mmreg, u32 mem)
-{
-	if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVQMtoR((mmreg>>4)&0xf, mem+8);
-		MOVQMtoR(mmreg&0xf, mem);
-	}
-	else SSEX_MOVDQA_M128_to_XMM( mmreg&0xf, mem);
-}
-
-void _eeWriteConstMem8(u32 mem, int mmreg)
-{
-	assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) );
-	if( IS_EECONSTREG(mmreg) ) MOV8ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) MOV8ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else MOV8RtoM(mem, mmreg);
-}
-
-void _eeWriteConstMem16(u32 mem, int mmreg)
-{
-	assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) );
-	if( IS_EECONSTREG(mmreg) ) MOV16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) MOV16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else MOV16RtoM(mem, mmreg);
-}
-
-// op - 0 for AND, 1 for OR
-void _eeWriteConstMem16OP(u32 mem, int mmreg, int op)
-{
-	assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) );
-	switch(op) {
-case 0: // AND operation
-	if( IS_EECONSTREG(mmreg) ) AND16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) AND16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else AND16RtoM(mem, mmreg);
-	break;
-case 1: // OR operation
-	if( IS_EECONSTREG(mmreg) ) OR16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) OR16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else OR16RtoM(mem, mmreg);
-	break;
-
-	jNO_DEFAULT
-	}
-}
-
-void _eeWriteConstMem32(u32 mem, int mmreg)
-{
-	if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf);
-	else if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVDMMXtoM(mem, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else MOV32RtoM(mem, mmreg);
-}
-
-void _eeWriteConstMem32OP(u32 mem, int mmreg, int op)
-{
-	switch(op) {
-case 0: // and
-	if( IS_XMMREG(mmreg) ) {
-		_deleteEEreg((mmreg>>16)&0x1f, 1);
-		SSE2_PAND_M128_to_XMM(mmreg&0xf, mem);
-		SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf);
-	}
-	else if( IS_MMXREG(mmreg) ) {
-		_deleteEEreg((mmreg>>16)&0x1f, 1);
-		SetMMXstate();
-		PANDMtoR(mmreg&0xf, mem);
-		MOVDMMXtoM(mem, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) {
-		AND32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	}
-	else if( IS_PSXCONSTREG(mmreg) ) {
-		AND32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	}
-	else {
-		AND32RtoM(mem, mmreg&0xf);
-	}
-	break;
-
-case 1: // or
-	if( IS_XMMREG(mmreg) ) {
-		_deleteEEreg((mmreg>>16)&0x1f, 1);
-		SSE2_POR_M128_to_XMM(mmreg&0xf, mem);
-		SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf);
-	}
-	else if( IS_MMXREG(mmreg) ) {
-		_deleteEEreg((mmreg>>16)&0x1f, 1);
-		SetMMXstate();
-		PORMtoR(mmreg&0xf, mem);
-		MOVDMMXtoM(mem, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) {
-		OR32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	}
-	else if( IS_PSXCONSTREG(mmreg) ) {
-		OR32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	}
-	else {
-		OR32RtoM(mem, mmreg&0xf);
-	}
-	break;
-
-case 2: // not and
-	if( mmreg & MEM_XMMTAG ) {
-		_deleteEEreg(mmreg>>16, 1);
-		SSEX_PANDN_M128_to_XMM(mmreg&0xf, mem);
-		SSEX_MOVD_XMM_to_M32(mem, mmreg&0xf);
-	}
-	else if( mmreg & MEM_MMXTAG ) {
-		_deleteEEreg(mmreg>>16, 1);
-		PANDNMtoR(mmreg&0xf, mem);
-		MOVDMMXtoM(mem, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) {
-		AND32ItoM(mem, ~g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	}
-	else if( IS_PSXCONSTREG(mmreg) ) {
-		AND32ItoM(mem, ~g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	}
-	else {
-		NOT32R(mmreg&0xf);
-		AND32RtoM(mem, mmreg&0xf);
-	}
-	break;
-
-default: assert(0);
-	}
-}
-
-void _eeWriteConstMem64(u32 mem, int mmreg)
-{
-	if( IS_XMMREG(mmreg) ) SSE_MOVLPS_XMM_to_M64(mem, mmreg&0xf);
-	else if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVQRtoM(mem, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) {
-		MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-		MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]);
-	}
-	else assert(0);
-}
-
-void _eeWriteConstMem128(u32 mem, int mmreg)
-{
-	if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVQRtoM(mem, mmreg&0xf);
-		MOVQRtoM(mem+8, (mmreg>>4)&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) {
-		SetMMXstate();
-		MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-		MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]);
-		MOVQRtoM(mem+8, mmreg&0xf);
-	}
-	else SSEX_MOVDQA_XMM_to_M128(mem, mmreg&0xf);
-}
-
-void _eeMoveMMREGtoR(x86IntRegType to, int mmreg)
-{
-	if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_R(to, mmreg&0xf);
-	else if( IS_MMXREG(mmreg) ) {
-		SetMMXstate();
-		MOVD32MMXtoR(to, mmreg&0xf);
-	}
-	else if( IS_EECONSTREG(mmreg) ) MOV32ItoR(to, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]);
-	else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoR(to, g_psxConstRegs[((mmreg>>16)&0x1f)]);
-	else if( mmreg != to ) MOV32RtoR(to, mmreg);
-}
-
-int recMemConstRead8(u32 x86reg, u32 mem, u32 sign)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( mem>>16 ) {
-case 0x1f40: return psxHw4ConstRead8(x86reg, mem, sign);
-case 0x1000: return hwConstRead8(x86reg, mem, sign);
-case 0x1f80: return psxHwConstRead8(x86reg, mem, sign);
-case 0x1200: return gsConstRead8(x86reg, mem, sign);
-case 0x1400:
-	{
-		iFlushCall(0);
-		PUSH32I(mem & ~0x04000000);
-		CALLFunc((u32)DEV9read8);
-		if( sign ) MOVSX32R8toR(EAX, EAX);
-		else MOVZX32R8toR(EAX, EAX);
-		return 1;
-	}
-
-default:
-	_eeReadConstMem8(x86reg, VM_RETRANSLATE(mem), sign);
-	return 0;
-	}
-}
-
-u16 recMemRead16()  {
-
-	register u32 mem;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-
-		switch( mem>>16 ) {
-		case 0x1000: return hwRead16(mem);
-		case 0x1f80: return psxHwRead16(mem);
-		case 0x1200: return *(u16*)(PS2MEM_BASE+(mem&~0xc00));
-		case 0x1800: return 0;
-		case 0x1a00: return ba0R16(mem);
-		case 0x1f90:
-		case 0x1f00:
-			return SPU2read(mem);
-		case 0x1400:
-			{
-				u32 ret = DEV9read16(mem & ~0x04000000);
-				SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret);
-				return ret;
-			}
-
-		default:
-			return *(u16*)(PS2MEM_BASE+mem);
-	}
-	MEM_LOG("Unknown Memory read16  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-	return 0;
-}
-
-int recMemConstRead16(u32 x86reg, u32 mem, u32 sign)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( mem>>16 ) {
-case 0x1000: return hwConstRead16(x86reg, mem, sign);
-case 0x1f80: return psxHwConstRead16(x86reg, mem, sign);
-case 0x1200: return gsConstRead16(x86reg, mem, sign);
-case 0x1800: 
-	if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);
-	else XOR32RtoR(x86reg, x86reg);
-	return 0;
-case 0x1a00:
-	iFlushCall(0);
-	PUSH32I(mem);
-	CALLFunc((u32)ba0R16);
-	ADD32ItoR(ESP, 4);
-	if( sign ) MOVSX32R16toR(EAX, EAX);
-	else MOVZX32R16toR(EAX, EAX);
-	return 1;
-
-case 0x1f90:
-case 0x1f00:
-	iFlushCall(0);
-	PUSH32I(mem);
-	CALLFunc((u32)SPU2read);
-	if( sign ) MOVSX32R16toR(EAX, EAX);
-	else MOVZX32R16toR(EAX, EAX);
-	return 1;
-
-case 0x1400:
-	iFlushCall(0);
-	PUSH32I(mem & ~0x04000000);
-	CALLFunc((u32)DEV9read16);
-	if( sign ) MOVSX32R16toR(EAX, EAX);
-	else MOVZX32R16toR(EAX, EAX);
-	return 1;
-
-default:
-	_eeReadConstMem16(x86reg, VM_RETRANSLATE(mem), sign);
-	return 0;
-	}
-}
-
-__declspec(naked)
-u32 recMemRead32()  {
-	// ecx is address - already anded with ~0xa0000000
-	__asm {
-
-		mov edx, ecx
-			shr edx, 16
-			cmp dx, 0x1000
-			je hwread
-			cmp dx, 0x1f80
-			je psxhwread
-			cmp dx, 0x1200
-			je gsread
-			cmp dx, 0x1400
-			je devread
-
-			// default read
-			mov eax, dword ptr [ecx+PS2MEM_BASE_]
-		ret
-	}
-
-hwread:
-		{
-			__asm {
-				cmp ecx, 0x10002000
-					jb counterread
-
-					cmp ecx, 0x1000f260
-					je hwsifpresetread
-					cmp ecx, 0x1000f240
-					je hwsifsyncread
-					cmp ecx, 0x1000f440
-					je hwmch_drd
-					cmp ecx, 0x1000f430
-					je hwmch_ricm
-
-					cmp ecx, 0x10003000
-					jb hwdefread2
-					mov eax, dword ptr [ecx+PS2MEM_BASE_]
-				ret
-
-					// ipu
-hwdefread2:
-				push ecx
-					call ipuRead32
-					add esp, 4	
-					ret
-
-					// sif
-hwsifpresetread:
-				xor eax, eax
-					ret
-hwsifsyncread:
-				mov eax, 0x1000F240
-					mov eax, dword ptr [eax+PS2MEM_BASE_]
-				or eax, 0xF0000102
-					ret
-			}
-
-counterread:
-				{
-					static u32 mem, index;
-
-					// counters
-					__asm mov mem, ecx
-						index = (mem>>11)&3;
-
-					if( (mem&0x7ff) == 0 ) {
-						__asm {
-							push index
-								call rcntRcount
-								add esp, 4
-								and eax, 0xffff
-								ret
-						}
-					}
-
-					index = (u32)&counters[index] + ((mem>>2)&0xc);
-
-					__asm {
-						mov eax, index
-							mov eax, dword ptr [eax]
-						movzx eax, ax
-							ret
-					}
-				}
-
-hwmch_drd: // MCH_DRD
-				__asm {
-					mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10]
-					shr eax, 6
-						test eax, 0xf
-						jz mch_drd_2
-hwmch_ricm:
-					xor eax, eax
-						ret
-
-mch_drd_2:
-					shr eax, 10
-						and eax, 0xfff
-						cmp eax, 0x21 // INIT
-						je mch_drd_init
-						cmp eax, 0x23 // CNFGA
-						je mch_drd_cnfga
-						cmp eax, 0x24 // CNFGB
-						je mch_drd_cnfgb
-						cmp eax, 0x40 // DEVID
-						je mch_drd_devid
-						xor eax, eax 
-						ret
-
-mch_drd_init:
-					mov edx, rdram_devices
-						xor eax, eax
-						cmp edx, rdram_sdevid
-						setg al
-						add rdram_sdevid, eax
-						imul eax, 0x1f
-						ret
-
-mch_drd_cnfga:
-					mov eax, 0x0D0D
-						ret
-
-mch_drd_cnfgb:
-					mov eax, 0x0090
-						ret
-
-mch_drd_devid:
-					mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10]
-					and eax, 0x1f
-						ret
-				}
-		}
-
-psxhwread:
-		__asm {
-			push ecx
-				call psxHwRead32		
-				add esp, 4
-				ret
-		}
-
-gsread:
-		__asm {
-			and ecx, 0xfffff3ff
-				mov eax, dword ptr [ecx+PS2MEM_BASE_]
-			ret
-		}
-
-devread:
-		__asm {
-			and ecx, 0xfbffffff
-				push ecx
-				call DEV9read32
-				add esp, 4
-				ret
-		}
-}
-
-int recMemConstRead32(u32 x86reg, u32 mem)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( (mem&~0xffff) ) {
-case 0x10000000: return hwConstRead32(x86reg, mem);
-case 0x1f800000: return psxHwConstRead32(x86reg, mem);
-case 0x12000000: return gsConstRead32(x86reg, mem);
-case 0x14000000:
-	iFlushCall(0);
-	PUSH32I(mem & ~0x04000000);
-	CALLFunc((u32)DEV9read32);
-	return 1;
-
-default:
-	_eeReadConstMem32(x86reg, VM_RETRANSLATE(mem));
-	return 0;
-	}
-}
-
-void recMemRead64(u64 *out)
-{	
-	register u32 mem;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-
-		switch( (mem&0xffff0000) ) {
-case 0x10000000: *out = hwRead64(mem); return;
-case 0x11000000: *out = *(u64*)(PS2MEM_BASE+mem); return;
-case 0x12000000: *out = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); return;
-
-default:
-	//assert(0);
-	*out = *(u64*)(PS2MEM_BASE+mem);
-	return;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-}
-
-void recMemConstRead64(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( (mem&0xffff0000) ) {
-case 0x10000000: hwConstRead64(mem, mmreg); return;
-case 0x12000000: gsConstRead64(mem, mmreg); return;
-default:
-	if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, VM_RETRANSLATE(mem));
-	else {
-		MOVQMtoR(mmreg, VM_RETRANSLATE(mem));
-		SetMMXstate();
-	}
-	return;
-	}
-}
-
-void recMemRead128(u64 *out)  {
-
-	register u32 mem;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-
-		switch( (mem&0xffff0000) ) {
-		case 0x10000000: 
-			hwRead128(mem, out);
-			return;
-		case 0x12000000:
-			out[0] = *(u64*)(PS2MEM_BASE+(mem&~0xc00));
-			out[1] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)+8);
-			return;
-		case 0x11000000:
-			out[0] = *(u64*)(PS2MEM_BASE+mem);
-			out[1] = *(u64*)(PS2MEM_BASE+mem+8);
-			return;
-		default:
-			//assert(0);
-			out[0] = *(u64*)(PS2MEM_BASE+mem);
-			out[1] = *(u64*)(PS2MEM_BASE+mem+8);
-			return;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-}
-
-void recMemConstRead128(u32 mem, int xmmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( (mem&0xffff0000) ) {
-case 0x10000000: hwConstRead128(mem, xmmreg); return;
-case 0x12000000: gsConstRead128(mem, xmmreg); return;
-default:
-	_eeReadConstMem128(xmmreg, VM_RETRANSLATE(mem));
-	return;
-	}
-}
-
-void errwrite()
-{
-	int i, bit, tempeax;
-	__asm mov i, ecx
-		__asm mov tempeax, eax
-		__asm mov bit, edx
-		SysPrintf("Error write%d at %x\n", bit, i);
-	assert(0);
-	__asm mov eax, tempeax
-		__asm mov ecx, i
-}
-
-void recMemWrite8()
-{
-	register u32 mem;
-	register u8 value;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-		__asm mov value, al
-
-		switch( mem>>16 ) {
-case 0x1f40: psxHw4Write8(mem, value); return;
-case 0x1000: hwWrite8(mem, value); return;
-case 0x1f80: psxHwWrite8(mem, value); return;
-case 0x1200: gsWrite8(mem, value); return;
-case 0x1400:
-	DEV9write8(mem & ~0x04000000, value);
-	SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value);
-	return;
-
-#ifdef _DEBUG
-case 0x1100: assert(0);
-#endif
-default:
-	// vus, bad addrs, etc
-	*(u8*)(PS2MEM_BASE+mem) = value;
-	return;
-	}
-	MEM_LOG("Unknown Memory write8   to  address %x with data %2.2x\n", mem, value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-int recMemConstWrite8(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( mem>>16 ) {
-case 0x1f40: psxHw4ConstWrite8(mem, mmreg); return 0;
-case 0x1000: hwConstWrite8(mem, mmreg); return 0;
-case 0x1f80: psxHwConstWrite8(mem, mmreg); return 0;
-case 0x1200: gsConstWrite8(mem, mmreg); return 0;
-case 0x1400:
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(mem & ~0x04000000);
-	CALLFunc((u32)DEV9write8);
-	return 0;
-
-case 0x1100:
-	_eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg);
-
-	if( mem < 0x11004000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU0->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU1->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	return 0;
-
-default:
-	_eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg);
-	return 1;
-	}
-}
-
-void recMemWrite16()   {
-
-	register u32 mem;
-	register u16 value;
-	__asm mov mem, ecx // already anded with ~0xa0000000
-		__asm mov value, ax
-
-		switch( mem>>16 ) {
-		case 0x1000: hwWrite16(mem, value); return;
-		case 0x1600:
-			//HACK: DEV9 VM crash fix
-			return;
-		case 0x1f80: psxHwWrite16(mem, value); return;
-		case 0x1200: gsWrite16(mem, value); return;
-		case 0x1f90:
-		case 0x1f00: SPU2write(mem, value); return;
-		case 0x1400:
-			DEV9write16(mem & ~0x04000000, value);
-			SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value);
-			return;
-
-#ifdef _DEBUG
-		case 0x1100: assert(0);
-#endif
-		default:
-			// vus, bad addrs, etc
-			*(u16*)(PS2MEM_BASE+mem) = value;
-			return;
-	}
-	MEM_LOG("Unknown Memory write16  to  address %x with data %4.4x\n", mem, value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-int recMemConstWrite16(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( mem>>16 ) {
-case 0x1000: hwConstWrite16(mem, mmreg); return 0;
-case 0x1600:
-	//HACK: DEV9 VM crash fix
-	return 0;
-case 0x1f80: psxHwConstWrite16(mem, mmreg); return 0;
-case 0x1200: gsConstWrite16(mem, mmreg); return 0;
-case 0x1f90:
-case 0x1f00:
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(mem);
-	CALLFunc((u32)SPU2write);
-	return 0;
-case 0x1400:
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(mem & ~0x04000000);
-	CALLFunc((u32)DEV9write16);
-	return 0;
-
-case 0x1100:
-	_eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg);
-
-	if( mem < 0x11004000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU0->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU1->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	return 0;
-
-default:
-	_eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg);
-	return 1;
-	}
-}
-
-C_ASSERT( sizeof(BASEBLOCK) == 8 );
-
-__declspec(naked)
-void recMemWrite32()
-{
-	// ecx is address - already anded with ~0xa0000000
-	__asm {
-
-		mov edx, ecx
-			shr edx, 16
-			cmp dx, 0x1000
-			je hwwrite
-			cmp dx, 0x1f80
-			je psxwrite
-			cmp dx, 0x1200
-			je gswrite
-			cmp dx, 0x1400
-			je devwrite
-			cmp dx, 0x1100
-			je vuwrite
-	}
-
-	__asm {
-		// default write
-		mov dword ptr [ecx+PS2MEM_BASE_], eax
-			ret
-
-hwwrite:
-		push eax
-			push ecx
-			call hwWrite32
-			add esp, 8
-			ret
-psxwrite:
-		push eax
-			push ecx
-			call psxHwWrite32
-			add esp, 8
-			ret
-gswrite:
-		push eax
-			push ecx
-			call gsWrite32
-			add esp, 8
-			ret
-devwrite:
-		and ecx, 0xfbffffff
-			push eax
-			push ecx
-			call DEV9write32
-			add esp, 8
-			ret
-vuwrite:
-		// default write
-		mov dword ptr [ecx+PS2MEM_BASE_], eax
-
-			cmp ecx, 0x11004000
-			jge vu1write
-			and ecx, 0x3ff8
-			// clear vu0mem
-			mov eax, CpuVU0
-			push 1
-			push ecx
-			call [eax]CpuVU0.Clear
-			add esp, 8
-			ret
-
-vu1write:
-		cmp ecx, 0x11008000
-			jl vuend
-			cmp ecx, 0x1100c000
-			jge vuend
-			// clear vu1mem
-			and ecx, 0x3ff8
-			mov eax, CpuVU1
-			push 1
-			push ecx
-			call [eax]CpuVU1.Clear
-			add esp, 8
-vuend:
-		ret
-	}
-}
-
-int recMemConstWrite32(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( mem&0xffff0000 ) {
-case 0x10000000: hwConstWrite32(mem, mmreg); return 0;
-case 0x1f800000: psxHwConstWrite32(mem, mmreg); return 0;
-case 0x12000000: gsConstWrite32(mem, mmreg); return 0;
-case 0x1f900000:
-case 0x1f000000:
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(mem);
-	CALLFunc((u32)SPU2write);
-	return 0;
-case 0x14000000:
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(mem & ~0x04000000);
-	CALLFunc((u32)DEV9write32);
-	return 0;
-
-case 0x11000000:
-	_eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg);
-
-	if( mem < 0x11004000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU0->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
-		PUSH32I(1);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU1->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	return 0;
-
-default:
-	_eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg);
-	return 1;
-	}
-}
-
-__declspec(naked) void recMemWrite64()
-{
-	__asm {
-		mov edx, ecx
-			shr edx, 16
-			cmp dx, 0x1000
-			je hwwrite
-			cmp dx, 0x1200
-			je gswrite
-			cmp dx, 0x1100
-			je vuwrite
-	}
-
-	__asm {
-		// default write
-		mov edx, 64
-			call errwrite
-
-hwwrite:
-		push dword ptr [eax+4]
-		push dword ptr [eax]
-		push ecx
-			call hwWrite64
-			add esp, 12
-			ret
-
-gswrite:
-		push dword ptr [eax+4]
-		push dword ptr [eax]
-		push ecx
-			call gsWrite64
-			add esp, 12
-			ret
-
-vuwrite:
-		mov ebx, dword ptr [eax]
-		mov edx, dword ptr [eax+4]
-		mov dword ptr [ecx+PS2MEM_BASE_], ebx
-			mov dword ptr [ecx+PS2MEM_BASE_+4], edx
-
-			cmp ecx, 0x11004000
-			jge vu1write
-			and ecx, 0x3ff8
-			// clear vu0mem
-			mov eax, CpuVU0
-			push 2
-			push ecx
-			call [eax]CpuVU0.Clear
-			add esp, 8
-			ret
-
-vu1write:
-		cmp ecx, 0x11008000
-			jl vuend
-			cmp ecx, 0x1100c000
-			jge vuend
-			// clear vu1mem
-			and ecx, 0x3ff8
-			mov eax, CpuVU0
-			push 2
-			push ecx
-			call [eax]CpuVU1.Clear
-			add esp, 8
-vuend:
-		ret
-	}
-}
-
-int recMemConstWrite64(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( (mem>>16) ) {
-case 0x1000: hwConstWrite64(mem, mmreg); return 0;
-case 0x1200: gsConstWrite64(mem, mmreg); return 0;
-
-case 0x1100:
-	_eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg);
-
-	if( mem < 0x11004000 ) {
-		PUSH32I(2);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU0->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
-		PUSH32I(2);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU1->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	return 0;
-
-default:
-	_eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg);
-	return 1;
-	}
-}
-
-__declspec(naked)
-void recMemWrite128()
-{
-	__asm {
-
-		mov edx, ecx
-			shr edx, 16
-			cmp dx, 0x1000
-			je hwwrite
-			cmp dx, 0x1200
-			je gswrite
-			cmp dx, 0x1100
-			je vuwrite
-	}
-
-	__asm {
-		mov edx, 128
-			call errwrite
-
-hwwrite:
-
-		push eax
-			push ecx
-			call hwWrite128
-			add esp, 8
-			ret
-
-vuwrite:
-		mov ebx, dword ptr [eax]
-		mov edx, dword ptr [eax+4]
-		mov edi, dword ptr [eax+8]
-		mov eax, dword ptr [eax+12]
-		mov dword ptr [ecx+PS2MEM_BASE_], ebx
-			mov dword ptr [ecx+PS2MEM_BASE_+4], edx
-			mov dword ptr [ecx+PS2MEM_BASE_+8], edi
-			mov dword ptr [ecx+PS2MEM_BASE_+12], eax
-
-			cmp ecx, 0x11004000
-			jge vu1write
-			and ecx, 0x3ff8
-			// clear vu0mem
-			mov eax, CpuVU0
-			push 4
-			push ecx
-			call [eax]CpuVU0.Clear
-			add esp, 8
-			ret
-
-vu1write:
-		cmp ecx, 0x11008000
-			jl vuend
-			cmp ecx, 0x1100c000
-			jge vuend
-			// clear vu1mem
-			and ecx, 0x3ff8
-			mov eax, CpuVU1
-			push 4
-			push ecx
-			call [eax]CpuVU1.Clear
-			add esp, 8
-vuend:
-
-		// default write
-		//movaps xmm7, qword ptr [eax]
-
-		// removes possible exceptions and saves on remapping memory
-		// *might* be faster for certain games, no way to tell
-		//		cmp ecx, 0x20000000
-		//		jb Write128
-		//
-		//		// look for better mapping
-		//		mov edx, ecx
-		//		shr edx, 12
-		//		shl edx, 3
-		//		add edx, memLUT
-		//		mov edx, dword ptr [edx + 4]
-		//		cmp edx, 0
-		//		je Write128
-		//		mov edx, dword ptr [edx]
-		//		cmp edx, 0
-		//		je Write128
-		//		and ecx, 0xfff
-		//		movaps qword ptr [ecx+edx], xmm7
-		//		jmp CheckOverwrite
-		//Write128:
-		//movaps qword ptr [ecx+PS2MEM_BASE_], xmm7
-		ret
-
-gswrite:
-		sub esp, 8
-			movlps xmm7, qword ptr [eax]
-		movlps qword ptr [esp], xmm7
-			push ecx
-			call gsWrite64
-
-			// call again for upper 8 bytes
-			movlps xmm7, qword ptr [eax+8]
-		movlps qword ptr [esp+4], xmm7
-			add [esp], 8
-			call gsWrite64
-			add esp, 12
-			ret
-	}
-}
-
-int recMemConstWrite128(u32 mem, int mmreg)
-{
-	mem = TRANSFORM_ADDR(mem);
-
-	switch( (mem&0xffff0000) ) {
-case 0x10000000: hwConstWrite128(mem, mmreg); return 0;
-case 0x12000000: gsConstWrite128(mem, mmreg); return 0;
-
-case 0x11000000:
-	_eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg);
-
-	if( mem < 0x11004000 ) {
-		PUSH32I(4);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU0->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	else if( mem >= 0x11008000 && mem < 0x1100c000 ) {
-		PUSH32I(4);
-		PUSH32I(mem&0x3ff8);
-		CALLFunc((u32)CpuVU1->Clear);
-		ADD32ItoR(ESP, 8);
-	}
-	return 0;
-
-default:
-	_eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg);
-	return 1;
-	}
-}
-
-int  __fastcall memRead8 (u32 mem, u8  *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x1f400000: *out = psxHw4Read8(mem); return 0;
-		case 0x10000000: *out = hwRead8(mem); return 0;
-		case 0x1f800000: *out = psxHwRead8(mem); return 0;
-		case 0x12000000: *out = gsRead8(mem); return 0;
-		case 0x14000000:
-			*out = DEV9read8(mem & ~0x04000000);
-			SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-			return 0;
-
-		default:
-			*out = *(u8*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-
-#ifdef MEM_LOG
-	MEM_LOG("Unknown Memory read32  from address %8.8x\n", mem);
-#endif
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int  __fastcall memRead8RS (u32 mem, u64 *out)
-{	
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-case 0x1f400000: *out = (s8)psxHw4Read8(mem); return 0;
-case 0x10000000: *out = (s8)hwRead8(mem); return 0;
-case 0x1f800000: *out = (s8)psxHwRead8(mem); return 0;
-case 0x12000000: *out = (s8)gsRead8(mem); return 0;
-case 0x14000000:
-	*out = (s8)DEV9read8(mem & ~0x04000000);
-	SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-	return 0;
-
-default:
-	*out = *(s8*)(PS2MEM_BASE+mem);
-	return 0;
-	}
-	MEM_LOG("Unknown Memory read32  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead8RU (u32 mem, u64 *out)
-{
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-case 0x1f400000: *out = (u8)psxHw4Read8(mem); return 0;
-case 0x10000000: *out = (u8)hwRead8(mem); return 0;
-case 0x1f800000: *out = (u8)psxHwRead8(mem); return 0;
-case 0x12000000: *out = (u8)gsRead8(mem); return 0;
-case 0x14000000:
-	*out = (u8)DEV9read8(mem & ~0x04000000);
-	SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-	return 0;
-
-default:
-	*out = *(u8*)(PS2MEM_BASE+mem);
-	return 0;
-	}
-	MEM_LOG("Unknown Memory read32  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead16(u32 mem, u16 *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: *out = hwRead16(mem); return 0;
-		case 0x1f800000: *out = psxHwRead16(mem); return 0;
-		case 0x12000000: *out = gsRead16(mem); return 0;
-		case 0x18000000: *out = 0; return 0;
-		case 0x1a000000: *out = ba0R16(mem); return 0;
-		case 0x1f900000:
-		case 0x1f000000:
-			*out = SPU2read(mem); return 0;
-			break;
-		case 0x14000000:
-			*out = DEV9read16(mem & ~0x04000000);
-			SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-			return 0;
-
-		default:
-			*out = *(u16*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-	MEM_LOG("Unknown Memory read16  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-	return -1;
-}
-
-int __fastcall memRead16RS(u32 mem, u64 *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: *out = (s16)hwRead16(mem); return 0;
-		case 0x1f800000: *out = (s16)psxHwRead16(mem); return 0;
-		case 0x12000000: *out = (s16)gsRead16(mem); return 0;
-		case 0x18000000: *out = 0; return 0;
-		case 0x1a000000: *out = (s16)ba0R16(mem); return 0;
-		case 0x1f900000:
-		case 0x1f000000:
-			*out = (s16)SPU2read(mem); return 0;
-			break;
-		case 0x14000000:
-			*out = (s16)DEV9read16(mem & ~0x04000000);
-			SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-			return 0;
-
-		default:
-			*out = *(s16*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-	MEM_LOG("Unknown Memory read16  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-	return -1;
-}
-
-int __fastcall memRead16RU(u32 mem, u64 *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: *out = (u16)hwRead16(mem ); return 0;
-		case 0x1f800000: *out = (u16)psxHwRead16(mem ); return 0;
-		case 0x12000000: *out = (u16)gsRead16(mem); return 0;
-		case 0x18000000: *out = 0; return 0;
-		case 0x1a000000: *out = (u16)ba0R16(mem); return 0;
-		case 0x1f900000:
-		case 0x1f000000:
-			*out = (u16)SPU2read(mem ); return 0;
-			break;
-		case 0x14000000:
-			*out = (u16)DEV9read16(mem & ~0x04000000);
-			SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-			return 0;
-
-		default:
-			*out = *(u16*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-	MEM_LOG("Unknown Memory read16  from address %8.8x\n", mem);
-	cpuTlbMissR(mem, cpuRegs.branch);
-	return -1;
-}
-
-int __fastcall memRead32(u32 mem, u32 *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: *out = hwRead32(mem); return 0;
-		case 0x1f800000: *out = psxHwRead32(mem); return 0;
-		case 0x12000000: *out = gsRead32(mem); return 0;
-		case 0x14000000:
-			*out = (u32)DEV9read32(mem & ~0x04000000);
-			SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-			return 0;
-
-		default:
-			*out = *(u32*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead32RS(u32 mem, u64 *out)
-{
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-case 0x10000000: *out = (s32)hwRead32(mem); return 0;
-case 0x1f800000: *out = (s32)psxHwRead32(mem); return 0;
-case 0x12000000: *out = (s32)gsRead32(mem); return 0;
-case 0x14000000:
-	*out = (s32)DEV9read32(mem & ~0x04000000);
-	SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-	return 0;
-
-default:
-	*out = *(s32*)(PS2MEM_BASE+mem);
-	return 0;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead32RU(u32 mem, u64 *out)
-{
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-case 0x10000000: *out = (u32)hwRead32(mem); return 0;
-case 0x1f800000: *out = (u32)psxHwRead32(mem); return 0;
-case 0x12000000: *out = (u32)gsRead32(mem); return 0;
-case 0x14000000:
-	*out = (u32)DEV9read32(mem & ~0x04000000);
-	SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out);
-	return 0;
-
-default:
-	*out = *(u32*)(PS2MEM_BASE+mem);
-	return 0;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead64(u32 mem, u64 *out)  {
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: *out = hwRead64(mem); return 0;
-		case 0x12000000: *out = gsRead64(mem); return 0;
-
-		default:
-			*out = *(u64*)(PS2MEM_BASE+mem);
-			return 0;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-int __fastcall memRead128(u32 mem, u64 *out)  {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: 
-			hwRead128(mem, out);
-			return 0;
-		case 0x12000000:
-			out[0] = gsRead64(mem);
-			out[1] = gsRead64(mem + 8);
-			return 0;
-
-		default:
-			out[0] = *(u64*)(PS2MEM_BASE+mem);
-			out[1] = *(u64*)(PS2MEM_BASE+mem+8);
-			return 0;
-	}
-
-	MEM_LOG("Unknown Memory read32  from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val);
-	cpuTlbMissR(mem, cpuRegs.branch);
-
-	return -1;
-}
-
-void __fastcall memWrite8 (u32 mem, u8  value)   {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x1f400000: psxHw4Write8(mem, value); return;
-		case 0x10000000: hwWrite8(mem, value); return;
-		case 0x1f800000: psxHwWrite8(mem, value); return;
-		case 0x12000000: gsWrite8(mem, value); return;
-		case 0x14000000:
-			DEV9write8(mem & ~0x04000000, value);
-			SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value);
-			return;
-
-		default:
-			*(u8*)(PS2MEM_BASE+mem) = value;
-
-			if (CHECK_EEREC) {
-				REC_CLEARM(mem&~3);
-			}
-			return;
-	}
-	MEM_LOG("Unknown Memory write8   to  address %x with data %2.2x\n", mem, value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-void __fastcall memWrite16(u32 mem, u16 value)   {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: hwWrite16(mem, value); return;
-		case 0x1f800000: psxHwWrite16(mem, value); return;
-		case 0x12000000: gsWrite16(mem, value); return;
-		case 0x1f900000:
-		case 0x1f000000: SPU2write(mem, value); return;
-		case 0x14000000:
-			DEV9write16(mem & ~0x04000000, value);
-			SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value);
-			return;
-
-		default:
-			*(u16*)(PS2MEM_BASE+mem) = value;
-			if (CHECK_EEREC) {
-				REC_CLEARM(mem&~3);
-			}
-			return;
-	}
-	MEM_LOG("Unknown Memory write16  to  address %x with data %4.4x\n", mem, value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-void __fastcall memWrite32(u32 mem, u32 value)
-{
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-case 0x10000000: hwWrite32(mem, value); return;
-case 0x1f800000: psxHwWrite32(mem, value); return;
-case 0x12000000: gsWrite32(mem, value); return;
-case 0x1f900000:
-case 0x1f000000: SPU2write(mem, value); return;
-case 0x14000000:
-	DEV9write32(mem & ~0x4000000, value);
-	SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0x4000000, value);
-	return;
-
-default:
-	*(u32*)(PS2MEM_BASE+mem) = value;
-
-	if (CHECK_EEREC) {
-		REC_CLEARM(mem);
-	}
-	return;
-	}
-	MEM_LOG("Unknown Memory write32  to  address %x with data %8.8x\n", mem, value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-void __fastcall memWrite64(u32 mem, const u64* value)   {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: hwWrite64(mem, *value); return;
-		case 0x12000000: gsWrite64(mem, *value); return;
-
-		default:
-			*(u64*)(PS2MEM_BASE+mem) = *value;
-
-			if (CHECK_EEREC) {
-				REC_CLEARM(mem);
-				REC_CLEARM(mem+4);
-			}
-			return;
-	}
-	MEM_LOG("Unknown Memory write64  to  address %x with data %8.8x_%8.8x\n", mem, (u32)((*value)>>32), (u32)value);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-void __fastcall memWrite128(u32 mem, const u64 *value) {
-
-	mem = TRANSFORM_ADDR(mem);
-	switch( (mem&~0xffff) ) {
-		case 0x10000000: hwWrite128(mem, value); return;
-		case 0x12000000:
-			gsWrite64(mem, value[0]);
-			gsWrite64(mem + 8, value[1]);
-			return;
-
-		default:
-			*(u64*)(PS2MEM_BASE+mem) = value[0];
-			*(u64*)(PS2MEM_BASE+mem+8) = value[1];
-
-			if (CHECK_EEREC) {
-				REC_CLEARM(mem);
-				REC_CLEARM(mem+4);
-				REC_CLEARM(mem+8);
-				REC_CLEARM(mem+12);
-			}
-			return;
-	}
-	MEM_LOG("Unknown Memory write128 to  address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]);
-	cpuTlbMissW(mem, cpuRegs.branch);
-}
-
-// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
-void memReset()
-{
-#ifdef _WIN32
-	DWORD OldProtect;
-	// make sure can write
-	VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READWRITE, &OldProtect);
-	VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READWRITE, &OldProtect);
-	VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READWRITE, &OldProtect);
-	VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READWRITE, &OldProtect);
-#else
-	mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ|PROT_WRITE);
-	mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ|PROT_WRITE);
-	mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ|PROT_WRITE);
-	mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ|PROT_WRITE);
-#endif
-
-	memzero_ptr<Ps2MemSize::Base>(PS2MEM_BASE);
-	memzero_ptr<Ps2MemSize::Scratch>(PS2MEM_SCRATCH);
-	vm_Reset();
-
-	string Bios;
-	FILE *fp;
-
-	Path::Combine( Bios, Config.BiosDir, Config.Bios );
-
-	long filesize;
-	if( ( filesize = Path::getFileSize( Bios ) ) <= 0 )
-	{
-		//Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios);
-		throw Exception::FileNotFound( Bios,
-			"The specified Bios file was not found.  A bios is required for Pcsx2 to run.\n\nFile not found" );
-	}
-
-	fp = fopen(Bios.c_str(), "rb");
-	fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp);
-	fclose(fp);
-
-	BiosVersion = GetBiosVersion();
-	Console::Status("Bios Version %d.%d", params BiosVersion >> 8, BiosVersion & 0xff);
-
-	//injectIRX("host.irx");	//not fully tested; still buggy
-
-	loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1);
-	loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2);
-	loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom);
-
-#ifdef _WIN32
-	VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY, &OldProtect);
-	VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY, &OldProtect);
-	VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY, &OldProtect);
-	VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY, &OldProtect);
-#else
-	mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ);
-	mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ);
-	mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ);
-	mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ);
-#endif
-}
-
-#endif
diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp
index 28d7225d89..d346f33c0e 100644
--- a/pcsx2/SPR.cpp
+++ b/pcsx2/SPR.cpp
@@ -81,7 +81,7 @@ int  _SPR0chain() {
 		mfifotransferred += spr0->qwc;
 	} else {
 		memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4);
-		Cpu->Clear(spr0->madr, spr0->qwc<<2);
+		//Cpu->Clear(spr0->madr, spr0->qwc<<2);
 		// clear VU mem also!
 		TestClearVUs(spr0->madr, spr0->qwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes)
 		
@@ -117,7 +117,7 @@ void _SPR0interleave() {
 			hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4);
 			mfifotransferred += spr0->qwc;
 		} else {
-			Cpu->Clear(spr0->madr, spr0->qwc<<2);
+			//Cpu->Clear(spr0->madr, spr0->qwc<<2);
 			// clear VU mem also!
 			TestClearVUs(spr0->madr, spr0->qwc<<2);
 			memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4);
diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
index 573a33c793..2773ac336e 100644
--- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
+++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
@@ -757,10 +757,6 @@
 					/>
 				</FileConfiguration>
 			</File>
-			<File
-				RelativePath="..\WinVM.cpp"
-				>
-			</File>
 			<Filter
 				Name="Debugger"
 				>
@@ -911,6 +907,14 @@
 		<Filter
 			Name="Misc"
 			>
+			<File
+				RelativePath="..\..\HashMap.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\HashTools.cpp"
+				>
+			</File>
 			<File
 				RelativePath="..\..\Misc.cpp"
 				>
@@ -2049,10 +2053,6 @@
 						RelativePath="..\..\x86\iR5900Branch.h"
 						>
 					</File>
-					<File
-						RelativePath="..\..\x86\iR5900CoissuedLoadStore.cpp"
-						>
-					</File>
 					<File
 						RelativePath="..\..\x86\iR5900Jump.h"
 						>
@@ -2229,34 +2229,6 @@
 				<Filter
 					Name="Dynarec"
 					>
-					<File
-						RelativePath="..\..\x86\iPsxMem.cpp"
-						>
-						<FileConfiguration
-							Name="Debug|Win32"
-							ExcludedFromBuild="true"
-							>
-							<Tool
-								Name="VCCLCompilerTool"
-							/>
-						</FileConfiguration>
-						<FileConfiguration
-							Name="Devel|Win32"
-							ExcludedFromBuild="true"
-							>
-							<Tool
-								Name="VCCLCompilerTool"
-							/>
-						</FileConfiguration>
-						<FileConfiguration
-							Name="Release|Win32"
-							ExcludedFromBuild="true"
-							>
-							<Tool
-								Name="VCCLCompilerTool"
-							/>
-						</FileConfiguration>
-					</File>
 					<File
 						RelativePath="..\..\x86\iR3000A.cpp"
 						>
@@ -2382,10 +2354,6 @@
 					RelativePath="..\..\Memory.h"
 					>
 				</File>
-				<File
-					RelativePath="..\..\MemoryVM.cpp"
-					>
-				</File>
 				<File
 					RelativePath="..\..\x86\ix86-32\recVTLB.cpp"
 					>
@@ -3106,10 +3074,6 @@
 			RelativePath="..\..\Stats.h"
 			>
 		</File>
-		<File
-			RelativePath="..\WinDebugResource"
-			>
-		</File>
 	</Files>
 	<Globals>
 	</Globals>
diff --git a/pcsx2/windows/WinVM.cpp b/pcsx2/windows/WinVM.cpp
deleted file mode 100644
index f2ee585ed4..0000000000
--- a/pcsx2/windows/WinVM.cpp
+++ /dev/null
@@ -1,470 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
- *  Copyright (C) 2002-2009  Pcsx2 Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include "PrecompiledHeader.h"
-#include "win32.h"
-
-
-#ifdef PCSX2_VIRTUAL_MEM
-
-// virtual memory/privileges
-#include "ntsecapi.h"
-
-static wchar_t s_szUserName[255];
-
-LRESULT WINAPI UserNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
-	switch(uMsg) {
-		case WM_INITDIALOG:
-			SetWindowPos(hDlg, HWND_TOPMOST, 200, 100, 0, 0, SWP_NOSIZE);
-			return TRUE;
-
-		case WM_COMMAND:
-			switch(wParam) {
-				case IDOK:
-				{
-					wchar_t str[255];
-					GetWindowTextW(GetDlgItem(hDlg, IDC_USER_NAME), str, 255);
-					swprintf(s_szUserName, 255, L"%hs", &str);
-					EndDialog(hDlg, TRUE );
-					return TRUE;
-				}
-
-				case IDCANCEL:
-					EndDialog(hDlg, FALSE );
-					return TRUE;
-			}
-			break;
-	}
-	return FALSE;
-}
-
-BOOL InitLsaString(
-  PLSA_UNICODE_STRING pLsaString,
-  LPCWSTR pwszString
-)
-{
-  DWORD dwLen = 0;
-
-  if (NULL == pLsaString)
-      return FALSE;
-
-  if (NULL != pwszString) 
-  {
-      dwLen = wcslen(pwszString);
-      if (dwLen > 0x7ffe)   // String is too large
-          return FALSE;
-  }
-
-  // Store the string.
-  pLsaString->Buffer = (WCHAR *)pwszString;
-  pLsaString->Length =  (USHORT)dwLen * sizeof(WCHAR);
-  pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR);
-
-  return TRUE;
-}
-
-PLSA_TRANSLATED_SID2 GetSIDInformation (LPWSTR AccountName,LSA_HANDLE PolicyHandle)
-{
-  LSA_UNICODE_STRING lucName;
-  PLSA_TRANSLATED_SID2 ltsTranslatedSID;
-  PLSA_REFERENCED_DOMAIN_LIST lrdlDomainList;
-  //LSA_TRUST_INFORMATION myDomain;
-  NTSTATUS ntsResult;
-  PWCHAR DomainString = NULL;
-
-  // Initialize an LSA_UNICODE_STRING with the name.
-  if (!InitLsaString(&lucName, AccountName))
-  {
-         wprintf(L"Failed InitLsaString\n");
-         return NULL;
-  }
-
-  ntsResult = LsaLookupNames2(
-     PolicyHandle,     // handle to a Policy object
-	 0,
-     1,                // number of names to look up
-     &lucName,         // pointer to an array of names
-     &lrdlDomainList,  // receives domain information
-     &ltsTranslatedSID // receives relative SIDs
-  );
-  if (0 != ntsResult) 
-  {
-    wprintf(L"Failed LsaLookupNames - %lu \n",
-      LsaNtStatusToWinError(ntsResult));
-    return NULL;
-  }
-
-  // Get the domain the account resides in.
-//  myDomain = lrdlDomainList->Domains[ltsTranslatedSID->DomainIndex];
-//  DomainString = (PWCHAR) LocalAlloc(LPTR, myDomain.Name.Length + 1);
-//  wcsncpy(DomainString, myDomain.Name.Buffer, myDomain.Name.Length);
-
-  // Display the relative Id. 
-//  wprintf(L"Relative Id is %lu in domain %ws.\n",
-//    ltsTranslatedSID->RelativeId,
-//    DomainString);
-
-  LsaFreeMemory(lrdlDomainList);
-
-  return ltsTranslatedSID;
-}
-
-BOOL AddPrivileges(PSID AccountSID, LSA_HANDLE PolicyHandle, BOOL bAdd)
-{
-  LSA_UNICODE_STRING lucPrivilege;
-  NTSTATUS ntsResult;
-
-  // Create an LSA_UNICODE_STRING for the privilege name(s).
-  if (!InitLsaString(&lucPrivilege, L"SeLockMemoryPrivilege"))
-  {
-         wprintf(L"Failed InitLsaString\n");
-         return FALSE;
-  }
-
-  if( bAdd ) {
-    ntsResult = LsaAddAccountRights(
-        PolicyHandle,  // An open policy handle.
-        AccountSID,    // The target SID.
-        &lucPrivilege, // The privilege(s).
-        1              // Number of privileges.
-    );
-  }
-  else {
-      ntsResult = LsaRemoveAccountRights(
-        PolicyHandle,  // An open policy handle.
-        AccountSID,    // The target SID
-        FALSE,
-        &lucPrivilege, // The privilege(s).
-        1              // Number of privileges.
-    );
-  }
-      
-  if (ntsResult == 0) 
-  {
-    wprintf(L"Privilege added.\n");
-  }
-  else
-  {
-	  int err = LsaNtStatusToWinError(ntsResult);
-	  char str[255];
-		_snprintf(str, 255, "Privilege was not added - %lu \n", LsaNtStatusToWinError(ntsResult));
-		MessageBox(NULL, str, "Privilege error", MB_OK);
-	return FALSE;
-  }
-
-  return TRUE;
-} 
-
-#define TARGET_SYSTEM_NAME L"mysystem"
-LSA_HANDLE GetPolicyHandle()
-{
-  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
-  WCHAR SystemName[] = TARGET_SYSTEM_NAME;
-  USHORT SystemNameLength;
-  LSA_UNICODE_STRING lusSystemName;
-  NTSTATUS ntsResult;
-  LSA_HANDLE lsahPolicyHandle;
-
-  // Object attributes are reserved, so initialize to zeroes.
-  ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
-
-  //Initialize an LSA_UNICODE_STRING to the server name.
-  SystemNameLength = wcslen(SystemName);
-  lusSystemName.Buffer = SystemName;
-  lusSystemName.Length = SystemNameLength * sizeof(WCHAR);
-  lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR);
-
-  // Get a handle to the Policy object.
-  ntsResult = LsaOpenPolicy(
-        NULL,    //Name of the target system.
-        &ObjectAttributes, //Object attributes.
-        POLICY_ALL_ACCESS, //Desired access permissions.
-        &lsahPolicyHandle  //Receives the policy handle.
-    );
-
-  if (ntsResult != 0)
-  {
-    // An error occurred. Display it as a win32 error code.
-    wprintf(L"OpenPolicy returned %lu\n",
-      LsaNtStatusToWinError(ntsResult));
-    return NULL;
-  } 
-  return lsahPolicyHandle;
-}
-
-
-/*****************************************************************
-   LoggedSetLockPagesPrivilege: a function to obtain, if possible, or
-   release the privilege of locking physical pages.
-
-   Inputs:
-
-       HANDLE hProcess: Handle for the process for which the
-       privilege is needed
-
-       BOOL bEnable: Enable (TRUE) or disable?
-
-   Return value: TRUE indicates success, FALSE failure.
-
-*****************************************************************/
-BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable)
-{
-	struct {
-	u32 Count;
-	LUID_AND_ATTRIBUTES Privilege [1];
-	} Info;
-
-	HANDLE Token;
-	BOOL Result;
-
-	// Open the token.
-
-	Result = OpenProcessToken ( hProcess,
-								TOKEN_ADJUST_PRIVILEGES,
-								& Token);
-
-	if( Result != TRUE ) {
-		Console::Error( "VirtualMemory Error > Cannot open process token." );
-		return FALSE;
-	}
-
-	// Enable or disable?
-
-	Info.Count = 1;
-	if( bEnable ) 
-	{
-		Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
-	} 
-	else 
-	{
-		Info.Privilege[0].Attributes = SE_PRIVILEGE_REMOVED;
-	}
-
-	// Get the LUID.
-	Result = LookupPrivilegeValue ( NULL,
-									SE_LOCK_MEMORY_NAME,
-									&(Info.Privilege[0].Luid));
-
-	if( Result != TRUE ) 
-	{
-		Console::Error( "VirtualMemory Error > Cannot get privilege value for %s.", params SE_LOCK_MEMORY_NAME );
-		return FALSE;
-	}
-
-	// Adjust the privilege.
-
-	Result = AdjustTokenPrivileges ( Token, FALSE,
-									(PTOKEN_PRIVILEGES) &Info,
-									0, NULL, NULL);
-
-	// Check the result.
-	if( Result != TRUE ) 
-	{
-		Console::Error( "VirtualMemory Error > Cannot adjust token privileges, error %u.", params GetLastError() );
-		return FALSE;
-	} 
-	else 
-	{
-		if( GetLastError() != ERROR_SUCCESS ) 
-		{
-
-			BOOL bSuc = FALSE;
-			LSA_HANDLE policy;
-			PLSA_TRANSLATED_SID2 ltsTranslatedSID;
-
-//			if( !DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_USERNAME), gApp.hWnd, (DLGPROC)UserNameProc) )
-//				return FALSE;
-            DWORD len = sizeof(s_szUserName);
-            GetUserNameW(s_szUserName, &len);
-
-			policy = GetPolicyHandle();
-
-			if( policy != NULL ) {
-
-				ltsTranslatedSID = GetSIDInformation(s_szUserName, policy);
-
-				if( ltsTranslatedSID != NULL ) {
-					bSuc = AddPrivileges(ltsTranslatedSID->Sid, policy, bEnable);
-					LsaFreeMemory(ltsTranslatedSID);
-				}
-
-				LsaClose(policy);
-			}
-
-			if( bSuc ) {
-				// Get the LUID.
-				LookupPrivilegeValue ( NULL, SE_LOCK_MEMORY_NAME, &(Info.Privilege[0].Luid));
-
-				bSuc = AdjustTokenPrivileges ( Token, FALSE, (PTOKEN_PRIVILEGES) &Info, 0, NULL, NULL);
-			}
-
-			if( bSuc ) {
-				if( MessageBox(NULL, "PCSX2 just changed your SE_LOCK_MEMORY privilege in order to gain access to physical memory.\n"
-								"Log off/on and run pcsx2 again. Do you want to log off?\n",
-								"Privilege changed query", MB_YESNO) == IDYES ) {
-					ExitWindows(EWX_LOGOFF, 0);
-				}
-			}
-			else {
-				MessageBox(NULL, "Failed adding SE_LOCK_MEMORY privilege, please check the local policy.\n"
-					"Go to security settings->Local Policies->User Rights. There should be a \"Lock pages in memory\".\n"
-					"Add your user to that and log off/on. This enables pcsx2 to run at real-time by allocating physical memory.\n"
-					"Also can try Control Panel->Local Security Policy->... (this does not work on Windows XP Home)\n"
-					"(zerofrog)\n", "Virtual Memory Access Denied", MB_OK);
-				return FALSE;
-			}
-		}
-	}
-
-	CloseHandle( Token );
-
-	return TRUE;
-}
-
-static u32 s_dwPageSize = 0;
-int SysPhysicalAlloc(u32 size, PSMEMORYBLOCK* pblock)
-{
-//#ifdef WIN32_FILE_MAPPING
-//	assert(0);
-//#endif
-	ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
-	int PFNArraySize;               // memory to request for PFN array
-	BOOL bResult;
-
-	assert( pblock != NULL );
-	memset(pblock, 0, sizeof(PSMEMORYBLOCK));
-
-	if( s_dwPageSize == 0 ) {
-		SYSTEM_INFO sSysInfo;           // useful system information
-		GetSystemInfo(&sSysInfo);  // fill the system information structure
-		s_dwPageSize = sSysInfo.dwPageSize;
-
-		if( s_dwPageSize != 0x1000 ) {
-			Msgbox::Alert("Error! OS page size must be 4Kb!\n"
-				"If for some reason the OS cannot have 4Kb pages, then run the TLB build.");
-			return -1;
-		}
-	}
-
-	// Calculate the number of pages of memory to request.
-	pblock->NumberPages = (size+s_dwPageSize-1)/s_dwPageSize;
-	PFNArraySize = pblock->NumberPages * sizeof (ULONG_PTR);
-
-	pblock->aPFNs = (uptr*)HeapAlloc (GetProcessHeap (), 0, PFNArraySize);
-
-	if (pblock->aPFNs == NULL) {
-		Console::Error("Failed to allocate on heap.");
-		goto eCleanupAndExit;
-	}
-
-	// Allocate the physical memory.
-	NumberOfPagesInitial = pblock->NumberPages;
-	bResult = AllocateUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs );
-
-	if( bResult != TRUE ) 
-	{
-		Console::Error("Virtual Memory Error %u > Cannot allocate physical pages.", params GetLastError() );
-		goto eCleanupAndExit;
-	}
-
-	if( NumberOfPagesInitial != pblock->NumberPages ) 
-	{
-		Console::Error("Virtual Memory > Physical allocation failed!\n\tAllocated only %p of %p pages.", params pblock->NumberPages, NumberOfPagesInitial );
-		goto eCleanupAndExit;
-	}
-
-	pblock->aVFNs = (uptr*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
-
-	return 0;
-
-eCleanupAndExit:
-	SysPhysicalFree(pblock);
-	return -1;
-}
-
-void SysPhysicalFree(PSMEMORYBLOCK* pblock)
-{
-	assert( pblock != NULL );
-
-	// Free the physical pages.
-	FreeUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs );
-
-	if( pblock->aPFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aPFNs);
-	if( pblock->aVFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aVFNs);
-	memset(pblock, 0, sizeof(PSMEMORYBLOCK));
-}
-
-int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock)
-{
-	BOOL bResult;
-	int i;
-
-	LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE );
-	if( lpMemReserved == NULL || base != lpMemReserved )
-	{
-		Console::WriteLn("VirtualMemory Error %d > Cannot reserve memory at 0x%8.8x(%x).", params base, lpMemReserved, GetLastError());
-		goto eCleanupAndExit;
-	}
-
-	// Map the physical memory into the window.  
-	bResult = MapUserPhysicalPages( base, (ULONG_PTR)pblock->NumberPages, (PULONG_PTR)pblock->aPFNs );
-
-	for(i = 0; i < pblock->NumberPages; ++i)
-		pblock->aVFNs[i] = (uptr)base + 0x1000*i;
-
-	if( bResult != TRUE ) 
-	{
-		Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to map.", params GetLastError() );
-		goto eCleanupAndExit;
-	}
-
-	return 0;
-
-eCleanupAndExit:
-	SysVirtualFree(base, size);
-	return -1;
-}
-
-void SysVirtualFree(void* lpMemReserved, u32 size)
-{
-	// unmap   
-	if( MapUserPhysicalPages( lpMemReserved, (size+s_dwPageSize-1)/s_dwPageSize, NULL ) != TRUE ) 
-	{
-		Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to unmap", params GetLastError() );
-		return;
-	}
-
-	// Free virtual memory.
-	VirtualFree( lpMemReserved, 0, MEM_RELEASE );
-}
-
-int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pfn, int pageoffset)
-{
-	BOOL bResult = MapUserPhysicalPages(Addr, NumPages, (PULONG_PTR)(pfn+pageoffset));
-
-#ifdef _DEBUG
-	//if( !bResult )
-		//__Log("Failed to map user pages: 0x%x:0x%x, error = %d\n", Addr, NumPages, GetLastError());
-#endif
-
-	return bResult;
-}
-
-#else
-
-#endif
diff --git a/pcsx2/x86/iGS.cpp b/pcsx2/x86/iGS.cpp
deleted file mode 100644
index aa0bf63a9c..0000000000
--- a/pcsx2/x86/iGS.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
- *  Copyright (C) 2002-2009  Pcsx2 Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include "PrecompiledHeader.h"
-
-#include "Common.h"
-#include "VU.h"
-
-#include "iR5900.h"
-
-#include "GS.h"
-#include "DebugTools/Debug.h"
-	
-extern u8 g_RealGSMem[0x2000];
-#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff))
-
-// __thiscall -- Calling Convention Notes.
-
-// ** MSVC passes the pointer to the object as ECX.  Other parameters are passed normally
-// (_cdecl style).  Stack is cleaned by the callee.
-
-// ** GCC works just like a __cdecl, except the pointer to the object is pushed onto the
-// stack last (passed as the first parameter).  Caller cleans up the stack.
-
-// The GCC code below is untested.  Hope it works. :|  (air)
-
-
-// Used to send 8, 16, and 32 bit values to the MTGS.
-static void __fastcall _rec_mtgs_Send32orSmaller( GS_RINGTYPE ringtype, u32 mem, int mmreg )
-{
-	iFlushCall(0);
-
-	PUSH32I( 0 );
-	_callPushArg( mmreg, 0 );
-    PUSH32I( mem&0x13ff );
-    PUSH32I( ringtype );
-
-#ifdef _MSC_VER
-	MOV32ItoR( ECX, (uptr)mtgsThread );
-	CALLFunc( mtgsThread->FnPtr_SimplePacket() );
-#else	// GCC -->
-	PUSH32I( (uptr)mtgsThread );
-	CALLFunc( mtgsThread->FnPtr_SimplePacket() );
-	ADD32ItoR( ESP, 20 );
-#endif
-}
-
-// Used to send 64 and 128 bit values to the MTGS (called twice for 128's, which
-// is why it doesn't call iFlushCall)
-static void __fastcall _rec_mtgs_Send64( uptr gsbase, u32 mem, int mmreg )
-{
-    PUSH32M( gsbase+4 );
-    PUSH32M( gsbase );
-    PUSH32I( mem&0x13ff );
-    PUSH32I( GS_RINGTYPE_MEMWRITE64 );
-
-#ifdef _MSC_VER
-	MOV32ItoR( ECX, (uptr)mtgsThread );
-	CALLFunc( mtgsThread->FnPtr_SimplePacket() );
-#else	// GCC -->
-	PUSH32I( (uptr)mtgsThread );
-	CALLFunc( mtgsThread->FnPtr_SimplePacket() );
-	ADD32ItoR( ESP, 20 );
-#endif
-
-}
-
-void gsConstWrite8(u32 mem, int mmreg)
-{
-	switch (mem&~3) {
-		case 0x12001000: // GS_CSR
-			_eeMoveMMREGtoR(EAX, mmreg);
-			iFlushCall(0);
-			MOV32MtoR(ECX, (uptr)&CSRw);
-			AND32ItoR(EAX, 0xff<<(mem&3)*8);
-			AND32ItoR(ECX, ~(0xff<<(mem&3)*8));
-			OR32ItoR(EAX, ECX);
-			_callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0);
-			break;
-		default:
-			_eeWriteConstMem8( (uptr)PS2GS_BASE(mem), mmreg );
-
-			if( mtgsThread != NULL )
-				_rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE8, mem, mmreg );
-
-			break;
-	}
-}
-
-void gsConstWrite16(u32 mem, int mmreg)
-{	
-	switch (mem&~3) {
-
-		case 0x12000010: // GS_SMODE1
-		case 0x12000020: // GS_SMODE2
-			// SMODE1 and SMODE2 fall back on the gsWrite library.
-			iFlushCall(0);
-			_callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 );
-			break;
-
-		case 0x12001000: // GS_CSR
-
-			assert( !(mem&2) );
-			_eeMoveMMREGtoR(EAX, mmreg);
-			iFlushCall(0);
-
-			MOV32MtoR(ECX, (uptr)&CSRw);
-			AND32ItoR(EAX, 0xffff<<(mem&2)*8);
-			AND32ItoR(ECX, ~(0xffff<<(mem&2)*8));
-			OR32ItoR(EAX, ECX);
-			_callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0);
-			break;
-
-		default:
-			_eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg );
-
-			if( mtgsThread != NULL )
-				_rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE16, mem, mmreg );
-
-			break;
-	}
-}
-
-// (value&0x1f00)|0x6000
-void gsConstWriteIMR(int mmreg)
-{
-	const u32 mem = 0x12001010;
-	if( mmreg & MEM_XMMTAG ) {
-		SSE2_MOVD_XMM_to_M32((uptr)PS2GS_BASE(mem), mmreg&0xf);
-		AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00);
-		OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000);
-	}
-	else if( mmreg & MEM_MMXTAG ) {
-		SetMMXstate();
-		MOVDMMXtoM((uptr)PS2GS_BASE(mem), mmreg&0xf);
-		AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00);
-		OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000);
-	}
-	else if( mmreg & MEM_EECONSTTAG ) {
-		MOV32ItoM( (uptr)PS2GS_BASE(mem), (g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x1f00)|0x6000);
-	}
-	else {
-		AND32ItoR(mmreg, 0x1f00);
-		OR32ItoR(mmreg, 0x6000);
-		MOV32RtoM( (uptr)PS2GS_BASE(mem), mmreg );
-	}
-
-	// IMR doesn't need to be updated in MTGS mode
-}
-
-void gsConstWrite32(u32 mem, int mmreg) {
-
-	switch (mem) {
-
-		case 0x12000010: // GS_SMODE1
-		case 0x12000020: // GS_SMODE2
-			// SMODE1 and SMODE2 fall back on the gsWrite library.
-			iFlushCall(0);
-			_callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 );
-			break;
-
-		case 0x12001000: // GS_CSR
-			iFlushCall(0);
-            _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0);
-			break;
-
-		case 0x12001010: // GS_IMR
-			gsConstWriteIMR(mmreg);
-			break;
-		default:
-			_eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg );
-
-			if( mtgsThread != NULL )
-				_rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE32, mem, mmreg );
-
-			break;
-	}
-}
-
-void gsConstWrite64(u32 mem, int mmreg)
-{
-	switch (mem) {
-		case 0x12000010: // GS_SMODE1
-		case 0x12000020: // GS_SMODE2
-			// SMODE1 and SMODE2 fall back on the gsWrite library.
-			// the low 32 bit dword is all the SMODE regs care about.
-			iFlushCall(0);
-			_callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 );
-			break;
-
-		case 0x12001000: // GS_CSR
-			iFlushCall(0);
-            _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0);
-			break;
-
-		case 0x12001010: // GS_IMR
-			gsConstWriteIMR(mmreg);
-			break;
-
-		default:
-			_eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg);
-
-			if( mtgsThread != NULL )
-			{
-				iFlushCall( 0 );
-				_rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg );
-			}
-
-			break;
-	}
-}
-
-void gsConstWrite128(u32 mem, int mmreg)
-{
-	switch (mem) {
-		case 0x12000010: // GS_SMODE1
-		case 0x12000020: // GS_SMODE2
-			// SMODE1 and SMODE2 fall back on the gsWrite library.
-			// the low 32 bit dword is all the SMODE regs care about.
-			iFlushCall(0);
-			_callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 );
-			break;
-
-		case 0x12001000: // GS_CSR
-			iFlushCall(0);
-            _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0);
-			break;
-
-		case 0x12001010: // GS_IMR
-			// (value&0x1f00)|0x6000
-			gsConstWriteIMR(mmreg);
-			break;
-
-		default:
-			_eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg);
-
-			if( mtgsThread != NULL )
-			{
-				iFlushCall(0);
-				_rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg );
-				_rec_mtgs_Send64( (uptr)PS2GS_BASE(mem)+8, mem+8, mmreg );
-			}
-
-			break;
-	}
-}
-
-int gsConstRead8(u32 x86reg, u32 mem, u32 sign)
-{
-	GIF_LOG("GS read 8 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem);
-	_eeReadConstMem8(x86reg, (uptr)PS2GS_BASE(mem), sign);
-	return 0;
-}
-
-int gsConstRead16(u32 x86reg, u32 mem, u32 sign)
-{
-	GIF_LOG("GS read 16 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem);
-	_eeReadConstMem16(x86reg, (uptr)PS2GS_BASE(mem), sign);
-	return 0;
-}
-
-int gsConstRead32(u32 x86reg, u32 mem)
-{
-	GIF_LOG("GS read 32 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem);
-	_eeReadConstMem32(x86reg, (uptr)PS2GS_BASE(mem));
-	return 0;
-}
-
-void gsConstRead64(u32 mem, int mmreg)
-{
-	GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem);
-	if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PS2GS_BASE(mem));
-	else {
-		MOVQMtoR(mmreg, (uptr)PS2GS_BASE(mem));
-		SetMMXstate();
-	}
-}
-
-void gsConstRead128(u32 mem, int xmmreg)
-{
-	GIF_LOG("GS read 128 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem);
-	_eeReadConstMem128( xmmreg, (uptr)PS2GS_BASE(mem));
-}
diff --git a/pcsx2/x86/iHw.cpp b/pcsx2/x86/iHw.cpp
deleted file mode 100644
index b59744dca8..0000000000
--- a/pcsx2/x86/iHw.cpp
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
- *  Copyright (C) 2002-2009  Pcsx2 Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include "PrecompiledHeader.h"
-
-#include "Common.h"
-#include "iR5900.h"
-#include "VUmicro.h"
-#include "IopMem.h"
-
-// The full suite of hardware APIs:
-#include "IPU/IPU.h"
-#include "GS.h"
-#include "Counters.h"
-#include "Vif.h"
-#include "VifDma.h"
-#include "SPR.h"
-#include "Sif.h"
-
-
-extern int rdram_devices;	// put 8 for TOOL and 2 for PS2 and PSX
-extern int rdram_sdevid;
-extern char sio_buffer[1024];
-extern int sio_count;
-
-int hwConstRead8(u32 x86reg, u32 mem, u32 sign)
-{
-	if( mem >= 0x10000000 && mem < 0x10008000 )
-		DevCon::WriteLn("hwRead8 to %x", params mem);
-
-	if ((mem & 0xffffff0f) == 0x1000f200) {
-		if(mem == 0x1000f260) {
-			MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);
-			else)
-                XOR32RtoR(x86reg, x86reg);
-			return 0;
-		}
-		else if(mem == 0x1000F240) {
-
-			_eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign);
-			//psHu32(mem) &= ~0x4000;
-			return 0;
-		}
-	}
-	
-	if (mem < 0x10010000)
-	{
-		_eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign);
-	}
-	else {
-		MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);
-		else )
-            XOR32RtoR(x86reg, x86reg);
-	}
-
-	return 0;
-}
-
-#define CONSTREAD16_CALL(name) { \
-	iFlushCall(0); \
-	CALLFunc((uptr)name); \
-	if( sign ) MOVSX32R16toR(EAX, EAX); \
-	else MOVZX32R16toR(EAX, EAX); \
-} \
-
-static u32 s_regreads[3] = {0x010200000, 0xbfff0000, 0xF0000102};
-int hwConstRead16(u32 x86reg, u32 mem, u32 sign)
-{
-	if( mem >= 0x10002000 && mem < 0x10008000 )
-		DevCon::WriteLn("hwRead16 to %x", params mem);
-
-	if( mem >= 0x10000000 && mem < 0x10002000 )
-		EECNT_LOG("cnt read to %x\n", params mem);
-
-	switch (mem) {
-		case 0x10000000:
-			PUSH32I(0);
-			CONSTREAD16_CALL(rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x10000010:
-			_eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign);
-			return 0;
-		case 0x10000020:
-			_eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign);
-			return 0;
-		case 0x10000030:
-			_eeReadConstMem16(x86reg, (uptr)&counters[0].hold, sign);
-			return 0;
-
-		case 0x10000800:
-			PUSH32I(1);
-			CONSTREAD16_CALL(rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x10000810:
-			_eeReadConstMem16(x86reg, (uptr)&counters[1].mode, sign);
-			return 0;
-
-		case 0x10000820:
-			_eeReadConstMem16(x86reg, (uptr)&counters[1].target, sign);
-			return 0;
-
-		case 0x10000830:
-			_eeReadConstMem16(x86reg, (uptr)&counters[1].hold, sign);
-			return 0;
-
-		case 0x10001000:
-			PUSH32I(2);
-			CONSTREAD16_CALL(rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x10001010:
-			_eeReadConstMem16(x86reg, (uptr)&counters[2].mode, sign);
-			return 0;
-
-		case 0x10001020:
-			_eeReadConstMem16(x86reg, (uptr)&counters[2].target, sign);
-			return 0;
-
-		case 0x10001800:
-			PUSH32I(3);
-			CONSTREAD16_CALL(rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x10001810:
-			_eeReadConstMem16(x86reg, (uptr)&counters[3].mode, sign);
-			return 0;
-
-		case 0x10001820:
-			_eeReadConstMem16(x86reg, (uptr)&counters[3].target, sign);
-			return 0;
-
-		default:
-			if ((mem & 0xffffff0f) == 0x1000f200) {
-				if(mem == 0x1000f260) {
-					MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);
-					else )
-                        XOR32RtoR(x86reg, x86reg);
-					return 0;
-				}
-				else if(mem == 0x1000F240) {
-
-					MMXONLY(if( IS_MMXREG(x86reg) ) {
-						MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff] - 2);
-						PORMtoR(x86reg&0xf, (uptr)&s_regreads[0]);
-						PANDMtoR(x86reg&0xf, (uptr)&s_regreads[1]);
-					}
-					else )
-                    {
-						if( sign ) MOVSX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-						else MOVZX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-
-						OR32ItoR(x86reg, 0x0102);
-						AND32ItoR(x86reg, ~0x4000);
-					}
-					return 0;
-				}
-			}
-			if (mem < 0x10010000) {
-				_eeReadConstMem16(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign);
-			}
-			else {
-				MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);
-				else )
-                    XOR32RtoR(x86reg, x86reg);
-			}
-			
-			return 0;
-	}
-}
-
-int hwContRead32_f440()
-{
-    if ((psHu32(0xf430) >> 6) & 0xF)
-        return 0;
-	else
-		switch ((psHu32(0xf430)>>16) & 0xFFF){//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5
-		case 0x21://INIT
-        {
-			int ret = 0x1F * (rdram_sdevid < rdram_devices);
-            rdram_sdevid += (rdram_sdevid < rdram_devices);
-            return ret;
-        }
-		case 0x23://CNFGA
-			return 0x0D0D;	//PVER=3 | MVER=16 | DBL=1 | REFBIT=5
-		case 0x24://CNFGB
-			//0x0110 for PSX  SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0
-			return 0x0090;	//SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0
-		case 0x40://DEVID
-			return psHu32(0xf430) & 0x1F;	// =SDEV
-	}
-
-    return 0;
-}
-
-int hwConstRead32(u32 x86reg, u32 mem)
-{
-	//IPU regs
-	if ((mem>=0x10002000) && (mem<0x10003000)) {
-		//return ipuConstRead32(x86reg, mem);
-		iFlushCall(0);
-		PUSH32I( mem );
-		CALLFunc( (uptr)ipuRead32 );
-	}
-
-	switch (mem) {
-		case 0x10000000:
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x10000010:
-			_eeReadConstMem32(x86reg, (uptr)&counters[0].mode);
-			return 0;
-		case 0x10000020:
-			_eeReadConstMem32(x86reg, (uptr)&counters[0].target);
-			return 0;
-		case 0x10000030:
-			_eeReadConstMem32(x86reg, (uptr)&counters[0].hold);
-			return 0;
-
-		case 0x10000800:
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x10000810:
-			_eeReadConstMem32(x86reg, (uptr)&counters[1].mode);
-			return 0;
-		case 0x10000820:
-			_eeReadConstMem32(x86reg, (uptr)&counters[1].target);
-			return 0;
-		case 0x10000830:
-			_eeReadConstMem32(x86reg, (uptr)&counters[1].hold);
-			return 0;
-
-		case 0x10001000:
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x10001010:
-			_eeReadConstMem32(x86reg, (uptr)&counters[2].mode);
-			return 0;
-		case 0x10001020:
-			_eeReadConstMem32(x86reg, (uptr)&counters[2].target);
-			return 0;
-		case 0x10001030:
-			// fixme: Counters[2].hold and Counters[3].hold are never assigned values
-			// anywhere in Pcsx2.
-			_eeReadConstMem32(x86reg, (uptr)&counters[2].hold);
-			return 0;
-
-		case 0x10001800:
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)rcntRcount);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x10001810:
-			_eeReadConstMem32(x86reg, (uptr)&counters[3].mode);
-			return 0;
-		case 0x10001820:
-			_eeReadConstMem32(x86reg, (uptr)&counters[3].target);
-			return 0;
-		case 0x10001830:
-			// fixme: Counters[2].hold and Counters[3].hold are never assigned values
-			// anywhere in Pcsx2.
-			_eeReadConstMem32(x86reg, (uptr)&counters[3].hold);
-			return 0;
-
-		case 0x1000f130:
-		case 0x1000f410:
-		case 0x1000f430:
-			if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf);
-			MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);)
-			else XOR32RtoR(x86reg, x86reg);
-			return 0;
-
-		case 0x1000f440:
-            iFlushCall(0);
-            CALLFunc((uptr)hwContRead32_f440);
-            return 1;
-
-		case 0x1000f520: // DMAC_ENABLER
-			_eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[0xf590]);
-			return 0;
-
-		default:
-			if ((mem & 0xffffff0f) == 0x1000f200) {
-				if(mem == 0x1000f260) {
-					if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf);
-					MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);)
-					else XOR32RtoR(x86reg, x86reg);
-					return 0;
-				}
-				else if(mem == 0x1000F240) {
-
-					if( IS_XMMREG(x86reg) ) {
-						SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-						SSEX_POR_M128_to_XMM(x86reg&0xf, (uptr)&s_regreads[2]);
-					}
-					MMXONLY(else if( IS_MMXREG(x86reg) ) {
-						MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-						PORMtoR(x86reg&0xf, (uptr)&s_regreads[2]);
-					})
-					else {
-						MOV32MtoR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-						OR32ItoR(x86reg, 0xF0000102);
-					}
-					return 0;
-				}
-			}
-			
-			if (mem < 0x10010000) {
-				_eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]);
-			}
-			else {
-				if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf);
-				MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);)
-				else XOR32RtoR(x86reg, x86reg);
-			}
-
-			return 0;
-	}
-}
-
-void hwConstRead64(u32 mem, int mmreg) {
-	if ((mem>=0x10002000) && (mem<0x10003000)) {
-		ipuConstRead64(mem, mmreg);
-		return;
-	}
-
-	if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PSM(mem));
-	else {
-        MMXONLY(MOVQMtoR(mmreg, (uptr)PSM(mem));
-		SetMMXstate();)
-	}
-}
-
-PCSX2_ALIGNED16(u32 s_TempFIFO[4]);
-void hwConstRead128(u32 mem, int xmmreg) {
-
-	// fixme : This needs to be updated to use the new paged FIFO accessors.
-	/*if (mem >= 0x10004000 && mem < 0x10008000) {
-		iFlushCall(0);
-		PUSH32I((uptr)&s_TempFIFO[0]);
-		PUSH32I(mem);
-		CALLFunc((uptr)ReadFIFO);
-		ADD32ItoR(ESP, 8);
-		_eeReadConstMem128( xmmreg, (uptr)&s_TempFIFO[0]);
-		return;
-	}*/
-
-	_eeReadConstMem128( xmmreg, (uptr)PSM(mem));
-}
-
-// when writing imm
-static void recDmaExecI8(void (*name)(), u32 mem, int mmreg)
-{
-	MOV8ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]);
-	if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 1 ) {
-		TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-		CALLFunc((uptr)name);
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-static void recDmaExec8(void (*name)(), u32 mem, int mmreg)
-{
-	// Flushcall Note : DMA transfers are almost always "involved" operations 
-	// that use memcpys and/or threading.  Freeing all XMM and MMX regs is the
-	// best option.
-
-	iFlushCall(FLUSH_NOCONST);
-	if( IS_EECONSTREG(mmreg) ) {
-		recDmaExecI8(name, mem, mmreg);
-	}
-	else {
-		_eeMoveMMREGtoR(EAX, mmreg);
-		_eeWriteConstMem8((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg);
-
-		TEST8ItoR(EAX, 1);
-		j8Ptr[5] = JZ8(0);
-		TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-
-		CALLFunc((uptr)name);
-
-		x86SetJ8( j8Ptr[5] );
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-static void __fastcall PrintDebug(u8 value)
-{
-	// Note: This is where the EE's diagonstic messages originate from (like the ones that
-	// start with hash # marks)
-
-	if (value == '\n') {
-		sio_buffer[sio_count] = 0;
-		Console::WriteLn( Color_Cyan, sio_buffer );
-		sio_count = 0;
-	} else {
-		if (sio_count < 1023) {
-			sio_buffer[sio_count++] = value;
-		}
-	}
-}
-
-// fixme: this would be more optimal as a C++ template (with bit as the template parameter)
-template< uint bit >
-static void ConstWrite_ExecTimer( uptr func, u8 index, int mmreg)
-{
-	if( bit != 32 )
-	{
-		if( !IS_EECONSTREG(mmreg) )
-		{
-			if( bit == 8 ) MOVZX32R8toR(mmreg&0xf, mmreg&0xf);
-			else if( bit == 16 ) MOVZX32R16toR(mmreg&0xf, mmreg&0xf);
-		}
-	}
-
-	// FlushCall Note : All counter functions are short and sweet, full flush not needed.
-
-	_recPushReg(mmreg);
-	iFlushCall(0);
-	PUSH32I(index);
-	CALLFunc(func);
-	ADD32ItoR(ESP, 8);
-}
-
-#define CONSTWRITE_TIMERS(bit) \
-	case 0x10000000: ConstWrite_ExecTimer<bit>((uptr)&rcntWcount, 0, mmreg); break; \
-	case 0x10000010: ConstWrite_ExecTimer<bit>((uptr)&rcntWmode, 0, mmreg); break; \
-	case 0x10000020: ConstWrite_ExecTimer<bit>((uptr)&rcntWtarget, 0, mmreg); break; \
-	case 0x10000030: ConstWrite_ExecTimer<bit>((uptr)&rcntWhold, 0, mmreg); break; \
-	\
-	case 0x10000800: ConstWrite_ExecTimer<bit>((uptr)&rcntWcount, 1, mmreg); break; \
-	case 0x10000810: ConstWrite_ExecTimer<bit>((uptr)&rcntWmode, 1, mmreg); break; \
-	case 0x10000820: ConstWrite_ExecTimer<bit>((uptr)&rcntWtarget, 1, mmreg); break; \
-	case 0x10000830: ConstWrite_ExecTimer<bit>((uptr)&rcntWhold, 1, mmreg); break; \
-	\
-	case 0x10001000: ConstWrite_ExecTimer<bit>((uptr)&rcntWcount, 2, mmreg); break; \
-	case 0x10001010: ConstWrite_ExecTimer<bit>((uptr)&rcntWmode, 2, mmreg); break; \
-	case 0x10001020: ConstWrite_ExecTimer<bit>((uptr)&rcntWtarget, 2, mmreg); break; \
-	\
-	case 0x10001800: ConstWrite_ExecTimer<bit>((uptr)&rcntWcount, 3, mmreg); break; \
-	case 0x10001810: ConstWrite_ExecTimer<bit>((uptr)&rcntWmode, 3, mmreg); break; \
-	case 0x10001820: ConstWrite_ExecTimer<bit>((uptr)&rcntWtarget, 3, mmreg); break; \
-
-void hwConstWrite8(u32 mem, int mmreg)
-{
-	switch (mem) {
-		CONSTWRITE_TIMERS(8)
-
-		case 0x1000f180:
-			// Yay fastcall!
-			_eeMoveMMREGtoR( ECX, mmreg );
-			iFlushCall(0);
-			CALLFunc((uptr)PrintDebug);
-			break;
-
-		case 0x10008001: // dma0 - vif0
-			recDmaExec8(dmaVIF0, mem, mmreg);
-			break;
-
-		case 0x10009001: // dma1 - vif1
-			recDmaExec8(dmaVIF1, mem, mmreg);
-			break;
-
-		case 0x1000a001: // dma2 - gif
-			recDmaExec8(dmaGIF, mem, mmreg);
-			break;
-
-		case 0x1000b001: // dma3 - fromIPU
-			recDmaExec8(dmaIPU0, mem, mmreg);
-			break;
-
-		case 0x1000b401: // dma4 - toIPU
-			recDmaExec8(dmaIPU1, mem, mmreg);
-			break;
-
-		case 0x1000c001: // dma5 - sif0
-			//if (value == 0) psxSu32(0x30) = 0x40000;
-			recDmaExec8(dmaSIF0, mem, mmreg);
-			break;
-
-		case 0x1000c401: // dma6 - sif1
-			recDmaExec8(dmaSIF1, mem, mmreg);
-			break;
-
-		case 0x1000c801: // dma7 - sif2
-			recDmaExec8(dmaSIF2, mem, mmreg);
-			break;
-
-		case 0x1000d001: // dma8 - fromSPR
-			recDmaExec8(dmaSPR0, mem, mmreg);
-			break;
-
-		case 0x1000d401: // dma9 - toSPR
-			recDmaExec8(dmaSPR1, mem, mmreg);
-			break;
-
-		case 0x1000f592: // DMAC_ENABLEW
-			_eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf522], mmreg );
-			_eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf592], mmreg );			
-			break;
-
-		default:
-			if ((mem & 0xffffff0f) == 0x1000f200) {
-				u32 at = mem & 0xf0;
-				switch(at)
-				{
-				case 0x00:
-					_eeWriteConstMem8( (uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-					break;
-				case 0x40:
-					if( IS_EECONSTREG(mmreg) ) {
-						if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) {
-							AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100);
-						}
-					}
-					else {
-						_eeMoveMMREGtoR(EAX, mmreg);
-						TEST16ItoR(EAX, 0x100);
-						j8Ptr[5] = JNZ8(0);
-						AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100);
-						x86SetJ8(j8Ptr[5]);
-					}
-					break;
-				}
-				return;
-			}
-			assert( (mem&0xff0f) != 0xf200 );
-
-			switch(mem&~3) {
-				case 0x1000f130:
-				case 0x1000f410:
-				case 0x1000f430:
-					break;
-				default:
-					_eeWriteConstMem8((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-			}
-
-			break;
-	}
-}
-
-// Flushcall Note : DMA transfers are almost always "involved" operations 
-// that use memcpys and/or threading.  Freeing all XMM and MMX regs is the
-// best option (removes the need for FreezeXMMRegs()).  But register
-// allocation is such a mess right now that we can't do it (yet).
-
-static void recDmaExecI16( void (*name)(), u32 mem, int mmreg )
-{
-	MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]);
-	if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100 ) {
-		TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-		CALLFunc((uptr)name);
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-static void recDmaExec16(void (*name)(), u32 mem, int mmreg)
-{
-	iFlushCall(0);
-
-	if( IS_EECONSTREG(mmreg) ) {
-		recDmaExecI16(name, mem, mmreg);
-	}
-	else {
-		_eeMoveMMREGtoR(EAX, mmreg);
-		_eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg);
-
-		TEST16ItoR(EAX, 0x100);
-		j8Ptr[5] = JZ8(0);
-		TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-
-		CALLFunc((uptr)name);
-
-		x86SetJ8( j8Ptr[5] );
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-void hwConstWrite16(u32 mem, int mmreg)
-{
-	switch(mem) {
-
-		CONSTWRITE_TIMERS(16)
-
-		case 0x10008000: // dma0 - vif0
-			recDmaExec16(dmaVIF0, mem, mmreg);
-			break;
-
-		case 0x10009000: // dma1 - vif1 - chcr
-			recDmaExec16(dmaVIF1, mem, mmreg);
-			break;
-
-		case 0x1000a000: // dma2 - gif
-			recDmaExec16(dmaGIF, mem, mmreg);
-			break;
-		case 0x1000b000: // dma3 - fromIPU
-			recDmaExec16(dmaIPU0, mem, mmreg);
-			break;
-		case 0x1000b400: // dma4 - toIPU
-			recDmaExec16(dmaIPU1, mem, mmreg);
-			break;
-		case 0x1000c000: // dma5 - sif0
-			//if (value == 0) psxSu32(0x30) = 0x40000;
-			recDmaExec16(dmaSIF0, mem, mmreg);
-			break;
-		case 0x1000c002:
-			//?
-			break;
-		case 0x1000c400: // dma6 - sif1
-			recDmaExec16(dmaSIF1, mem, mmreg);
-			break;
-		case 0x1000c800: // dma7 - sif2
-			recDmaExec16(dmaSIF2, mem, mmreg);
-			break;
-		case 0x1000c802:
-			//?
-			break;
-		case 0x1000d000: // dma8 - fromSPR
-			recDmaExec16(dmaSPR0, mem, mmreg);
-			break;
-		case 0x1000d400: // dma9 - toSPR
-			recDmaExec16(dmaSPR1, mem, mmreg);
-			break;
-		case 0x1000f592: // DMAC_ENABLEW
-			_eeWriteConstMem16((uptr)&PS2MEM_HW[0xf522], mmreg);
-			_eeWriteConstMem16((uptr)&PS2MEM_HW[0xf592], mmreg);
-			break;
-		case 0x1000f130:
-		case 0x1000f410:
-		case 0x1000f430:
-			break;
-		default:
-			if ((mem & 0xffffff0f) == 0x1000f200) {
-				u32 at = mem & 0xf0;
-				switch(at)
-				{
-				case 0x00:
-					_eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-					break;
-				case 0x20:
-					_eeWriteConstMem16OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1);
-					break;
-				case 0x30:
-					if( IS_EECONSTREG(mmreg) ) {
-						AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]);
-					}
-					else {
-						NOT32R(mmreg&0xf);
-						AND16RtoM((uptr)&PS2MEM_HW[mem&0xffff], mmreg&0xf);
-					}
-					break;
-				case 0x40:
-					if( IS_EECONSTREG(mmreg) ) {
-						if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) {
-							AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100);
-						}
-						else {
-							OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100);
-						}
-					}
-					else {
-						_eeMoveMMREGtoR(EAX, mmreg);
-						TEST16ItoR(EAX, 0x100);
-						j8Ptr[5] = JZ8(0);
-						OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100);
-						j8Ptr[6] = JMP8(0);
-
-						x86SetJ8( j8Ptr[5] );
-						AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100);
-
-						x86SetJ8( j8Ptr[6] );
-					}
-
-					break;
-				case 0x60:
-					_eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], 0);
-					break;
-				}
-				return;
-			}
-
-			_eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-	}
-}
-
-// when writing an Imm
-
-static void recDmaExecI( void (*name)(), u32 mem, int mmreg )
-{
-	u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0];
-    /* Keep the old tag if in chain mode and hw doesnt set it*/
-    if( (c & 0xc) == 0x4 && (c&0xffff0000) == 0 ) {
-        MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c);
-    }
-	else MOV32ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c);
-	if( c & 0x100 ) {
-		TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-		CALLFunc((uptr)name);
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-static void recDmaExec( void (*name)(), u32 mem, int mmreg )
-{
-
-	iFlushCall(0);
-
-	if( IS_EECONSTREG(mmreg) ) {
-		recDmaExecI(name, mem, mmreg);
-	}
-	else {
-
-		// fixme: This is a lot of code to be injecting into the recompiler
-		// for every DMA transfer.  It might actually be more efficient to
-		// set this up as a C function call instead (depends on how often
-		// the register is written without actually starting a DMA xfer).
-
-		_eeMoveMMREGtoR(EAX, mmreg);
-        TEST32ItoR(EAX, 0xffff0000);
-        j8Ptr[6] = JNZ8(0);
-        MOV32RtoR(ECX, EAX);
-        AND32ItoR(ECX, 0xc);
-        CMP32ItoR(ECX, 4);
-        j8Ptr[7] = JNE8(0);
-        if( IS_XMMREG(mmreg) || IS_MMXREG(mmreg) ) {
-			MOV16RtoM((uptr)&PS2MEM_HW[(mem) & 0xffff], EAX);
-		}
-		else {
-			_eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg);
-		}
-        j8Ptr[8] = JMP8(0);
-        x86SetJ8(j8Ptr[6]);
-        x86SetJ8(j8Ptr[7]);
-        _eeWriteConstMem32((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg);
-        x86SetJ8(j8Ptr[8]);
-
-        TEST16ItoR(EAX, 0x100);
-		j8Ptr[5] = JZ8(0);
-		TEST32ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1);
-		j8Ptr[6] = JZ8(0);
-
-		CALLFunc((uptr)name);
-		x86SetJ8( j8Ptr[5] );
-		x86SetJ8( j8Ptr[6] );
-	}
-}
-
-
-void hwConstWrite32(u32 mem, int mmreg)
-{
-	//IPU regs
-	if ((mem>=0x10002000) && (mem<0x10003000)) {
-    	//psHu32(mem) = value;
-		ipuConstWrite32(mem, mmreg);
-		return;
-	}
-
-	if ((mem>=0x10003800) && (mem<0x10003c00)) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(mem);
-		CALLFunc((uptr)vif0Write32);
-		ADD32ItoR(ESP, 8);
-		return;
-	}
-	if ((mem>=0x10003c00) && (mem<0x10004000)) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(mem);
-		CALLFunc((uptr)vif1Write32);
-		ADD32ItoR(ESP, 8);
-		return;
-	}
-
-	switch (mem) {
-
-		CONSTWRITE_TIMERS(32)
-
-		case GIF_CTRL:
-
-			_eeMoveMMREGtoR(EAX, mmreg);
-
-			iFlushCall(0);
-			TEST8ItoR(EAX, 1);
-			j8Ptr[5] = JZ8(0);
-
-			// reset GS
-			CALLFunc((uptr)gsGIFReset);
-			j8Ptr[6] = JMP8(0);
-
-			x86SetJ8( j8Ptr[5] );
-			AND32I8toR(EAX, 8);
-			MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX);
-
-			TEST16ItoR(EAX, 8);
-			j8Ptr[5] = JZ8(0);
-			OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8);
-			j8Ptr[7] = JMP8(0);
-
-			x86SetJ8( j8Ptr[5] );
-			AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8);
-			x86SetJ8( j8Ptr[6] );
-			x86SetJ8( j8Ptr[7] );
-			return;
-
-		case GIF_MODE:
-			_eeMoveMMREGtoR(EAX, mmreg);
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-			AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5);
-			AND8ItoR(EAX, 5);
-			OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX);
-			return;
-
-		case GIF_STAT: // stat is readonly
-			return;
-
-		case 0x10008000: // dma0 - vif0
-			recDmaExec(dmaVIF0, mem, mmreg);
-			break;
-
-		case 0x10009000: // dma1 - vif1 - chcr
-			recDmaExec(dmaVIF1, mem, mmreg);
-			break;
-
-		case 0x1000a000: // dma2 - gif
-			recDmaExec(dmaGIF, mem, mmreg);
-			break;
-
-		case 0x1000b000: // dma3 - fromIPU
-			recDmaExec(dmaIPU0, mem, mmreg);
-			break;
-		case 0x1000b400: // dma4 - toIPU
-			recDmaExec(dmaIPU1, mem, mmreg);
-			break;
-		case 0x1000c000: // dma5 - sif0
-			//if (value == 0) psxSu32(0x30) = 0x40000;
-			recDmaExec(dmaSIF0, mem, mmreg);
-			break;
-
-		case 0x1000c400: // dma6 - sif1
-			recDmaExec(dmaSIF1, mem, mmreg);
-			break;
-
-		case 0x1000c800: // dma7 - sif2
-			recDmaExec(dmaSIF2, mem, mmreg);
-			break;
-
-		case 0x1000d000: // dma8 - fromSPR
-			recDmaExec(dmaSPR0, mem, mmreg);
-			break;
-
-		case 0x1000d400: // dma9 - toSPR
-			recDmaExec(dmaSPR1, mem, mmreg);
-			break;
-
-		case 0x1000e010: // DMAC_STAT
-			_eeMoveMMREGtoR(EAX, mmreg);
-			iFlushCall(0);
-			MOV32RtoR(ECX, EAX);
-			SHR32ItoR(EAX, 16);
-			NOT32R(ECX);
-			XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX);
-			AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX);
-
-			CALLFunc((uptr)cpuTestDMACInts);
-			break;
-
-		case 0x1000f000: // INTC_STAT
-			_eeWriteConstMem32OP((uptr)&PS2MEM_HW[0xf000], mmreg, 2);
-			CALLFunc((uptr)cpuTestINTCInts);
-			break;
-
-		case 0x1000f010: // INTC_MASK
-			_eeMoveMMREGtoR(EAX, mmreg);
-			iFlushCall(0);
-			XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX);
-			CALLFunc((uptr)cpuTestINTCInts);
-			break;
-
-        case 0x1000f130:
-		case 0x1000f410:
-			break;
-
-        case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5
-
-            //if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0
-            //    rdram_sdevid = 0
-            _eeMoveMMREGtoR(EAX, mmreg);
-            MOV32RtoR(EDX, EAX);
-            MOV32RtoR(ECX, EAX);
-            SHR32ItoR(EAX, 6);
-            SHR32ItoR(EDX, 16);
-            AND32ItoR(EAX, 0xf);
-            AND32ItoR(EDX, 0xfff);
-            CMP32ItoR(EAX, 1);
-            j8Ptr[5] = JNE8(0);
-            CMP32ItoR(EDX, 0x21);
-            j8Ptr[6] = JNE8(0);
-
-            TEST32ItoM((uptr)&psHu32(0xf440), 0x80);
-            j8Ptr[7] = JNZ8(0);
-
-            // if SIO repeater is cleared, reset sdevid
-            MOV32ItoM((uptr)&rdram_sdevid, 0);
-			
-            //kill the busy bit
-            x86SetJ8(j8Ptr[5]);
-            x86SetJ8(j8Ptr[6]);
-            x86SetJ8(j8Ptr[7]);
-            AND32ItoR(ECX, ~0x80000000);
-            MOV32RtoM((uptr)&psHu32(0xf430), ECX);
-			break;
-
-		case 0x1000f440://MCH_DRD:
-            _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf440], mmreg);
-			break;
-
-		case 0x1000f590: // DMAC_ENABLEW
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg);
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg);
-			return;
-
-		default:
-			if ((mem & 0xffffff0f) == 0x1000f200) {
-				u32 at = mem & 0xf0;
-				switch(at)
-				{
-				case 0x00:
-					_eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-					break;
-				case 0x20:
-					_eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1);
-					break;
-				case 0x30:
-					_eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2);
-					break;
-				case 0x40:
-					if( IS_EECONSTREG(mmreg) ) {
-						if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) {
-							AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100);
-						}
-						else {
-							OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100);
-						}
-					}
-					else {
-						_eeMoveMMREGtoR(EAX, mmreg);
-						TEST32ItoR(EAX, 0x100);
-						j8Ptr[5] = JZ8(0);
-						OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100);
-						j8Ptr[6] = JMP8(0);
-
-						x86SetJ8( j8Ptr[5] );
-						AND32ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100);
-
-						x86SetJ8( j8Ptr[6] );
-					}
-
-					break;
-				case 0x60:
-					MOV32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0);
-					break;
-				}
-				return;
-			}
-
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-		break;
-	}
-}
-
-void hwConstWrite64(u32 mem, int mmreg)
-{
-	if ((mem>=0x10002000) && (mem<=0x10002030)) {
-		ipuConstWrite64(mem, mmreg);
-		return;
-	}
-	
-	if ((mem>=0x10003800) && (mem<0x10003c00)) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(mem);
-		CALLFunc((uptr)vif0Write32);
-		ADD32ItoR(ESP, 8);
-		return;
-	}
-	if ((mem>=0x10003c00) && (mem<0x10004000)) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(mem);
-		CALLFunc((uptr)vif1Write32);
-		ADD32ItoR(ESP, 8);
-		return;
-	}
-
-	switch (mem) {
-		case GIF_CTRL:
-			_eeMoveMMREGtoR(EAX, mmreg);
-			
-			iFlushCall(0);
-			TEST8ItoR(EAX, 1);
-			j8Ptr[5] = JZ8(0);
-
-			// reset GS
-			CALLFunc((uptr)gsGIFReset);
-			j8Ptr[6] = JMP8(0);
-
-			x86SetJ8( j8Ptr[5] );
-			AND32I8toR(EAX, 8);
-			MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX);
-
-			TEST16ItoR(EAX, 8);
-			j8Ptr[5] = JZ8(0);
-			OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8);
-			j8Ptr[7] = JMP8(0);
-
-			x86SetJ8( j8Ptr[5] );
-			AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8);
-			x86SetJ8( j8Ptr[6] );
-			x86SetJ8( j8Ptr[7] );
-			return;
-
-		case GIF_MODE:
-			_eeMoveMMREGtoR(EAX, mmreg);
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-
-			AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5);
-			AND8ItoR(EAX, 5);
-			OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX);
-			break;
-
-		case GIF_STAT: // stat is readonly
-			return;
-
-		case 0x1000a000: // dma2 - gif
-			recDmaExec(dmaGIF, mem, mmreg);
-			break;
-
-		case 0x1000e010: // DMAC_STAT
-			_eeMoveMMREGtoR(EAX, mmreg);
-
-			iFlushCall(0);
-			MOV32RtoR(ECX, EAX);
-			SHR32ItoR(EAX, 16);
-			NOT32R(ECX);
-			XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX);
-			AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX);
-
-			CALLFunc((uptr)cpuTestDMACInts);
-			break;
-
-		case 0x1000f590: // DMAC_ENABLEW
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg);
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg);
-			break;
-
-		case 0x1000f000: // INTC_STAT
-			_eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2);
-			CALLFunc((uptr)cpuTestINTCInts);
-			break;
-
-		case 0x1000f010: // INTC_MASK
-
-			_eeMoveMMREGtoR(EAX, mmreg);
-
-			iFlushCall(0);
-			XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX);
-			CALLFunc((uptr)cpuTestINTCInts);			
-			break;
-
-		case 0x1000f130:
-		case 0x1000f410:
-		case 0x1000f430:
-			break;
-		default:
-
-			_eeWriteConstMem64((uptr)PSM(mem), mmreg);
-			break;
-	}
-}
-
-void hwConstWrite128(u32 mem, int mmreg)
-{
-	// fixme : This needs to be updated to use the new paged FIFO accessors.
-
-	/*if (mem >= 0x10004000 && mem < 0x10008000) {
-		_eeWriteConstMem128((uptr)&s_TempFIFO[0], mmreg);
-		iFlushCall(0);
-		PUSH32I((uptr)&s_TempFIFO[0]);
-		PUSH32I(mem);
-		CALLFunc((uptr)WriteFIFO);
-		ADD32ItoR(ESP, 8);
-		return;
-	}*/
-
-	switch (mem) {
-		case 0x1000f590: // DMAC_ENABLEW
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg);
-			_eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg);
-			break;
-		case 0x1000f130:
-		case 0x1000f410:
-		case 0x1000f430:
-			break;
-
-		default:
-
-			_eeWriteConstMem128((uptr)&PS2MEM_HW[mem&0xffff], mmreg);
-			break;
-	}
-}
diff --git a/pcsx2/x86/iIPU.cpp b/pcsx2/x86/iIPU.cpp
deleted file mode 100644
index e1f1d429fc..0000000000
--- a/pcsx2/x86/iIPU.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
-*  Copyright (C) 2002-2008  Pcsx2 Team
-*
-*  This program is free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*  
-*  This program is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*  
-*  You should have received a copy of the GNU General Public License
-*  along with this program; if not, write to the Free Software
-*  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
-
-
-#include "PrecompiledHeader.h"
-
-#include "Common.h"
-#include "iR5900.h"
-
-#include "IPU.h"
-
-///////////////////////////////////////////////////////////////////////
-//  IPU Register Reads
-
-int ipuConstRead32(u32 x86reg, u32 mem)
-{
-	int workingreg, tempreg, tempreg2;
-	iFlushCall(0);
-	CALLFunc((u32)IPUProcessInterrupt);
-
-	//	if( !(x86reg&(MEM_XMMTAG|MEM_MMXTAG)) ) {
-	//		if( x86reg == EAX ) {
-	//			tempreg =  ECX;
-	//			tempreg2 = EDX;
-	//		}
-	//		else if( x86reg == ECX ) {
-	//			tempreg =  EAX;
-	//			tempreg2 = EDX;
-	//		}
-	//		else if( x86reg == EDX ) {
-	//			tempreg =  EAX;
-	//			tempreg2 = ECX;
-	//		}
-	//
-	//		workingreg = x86reg;
-	//	}
-	//	else {
-	workingreg = EAX;
-	tempreg =  ECX;
-	tempreg2 = EDX;
-	//	}
-
-	switch (mem){
-
-		case 0x10002010: // IPU_CTRL
-
-			MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32);
-			AND32ItoR(workingreg, ~0x3f0f); // save OFC
-			OR8MtoR(workingreg, (u32)&g_BP.IFC);
-			OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem
-
-			//			MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32);
-			//			AND32ItoR(workingreg, ~0x3fff);
-			//			MOV32MtoR(tempreg, (u32)&g_nIPU0Data);
-			//			MOV8MtoR(workingreg, (u32)&g_BP.IFC);
-			//
-			//			CMP32ItoR(tempreg, 8);
-			//			j8Ptr[5] = JLE8(0);
-			//			MOV32ItoR(tempreg, 8);
-			//			x86SetJ8( j8Ptr[5] );
-			//			SHL32ItoR(tempreg, 4);
-			//
-			//			OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem
-			//			OR8RtoR(workingreg, tempreg);
-
-#ifdef _DEBUG
-			MOV32RtoM((u32)&ipuRegs->ctrl._u32, workingreg);
-#endif
-			// NOTE: not updating ipuRegs->ctrl
-			//			if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg);
-			//			else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg);
-			return 1;
-
-		case 0x10002020: // IPU_BP
-
-			assert( (u32)&g_BP.FP + 1 == (u32)&g_BP.bufferhasnew );
-
-			MOVZX32M8toR(workingreg, (u32)&g_BP.BP);
-			MOVZX32M8toR(tempreg, (u32)&g_BP.FP);
-			AND8ItoR(workingreg, 0x7f);
-			ADD8MtoR(tempreg, (u32)&g_BP.bufferhasnew);
-			MOV8MtoR(workingreg+4, (u32)&g_BP.IFC);
-
-			SHL32ItoR(tempreg, 16);
-			OR32RtoR(workingreg, tempreg);
-
-#ifdef _DEBUG
-			MOV32RtoM((u32)&ipuRegs->ipubp, workingreg);
-#endif
-			// NOTE: not updating ipuRegs->ipubp
-			//			if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg);
-			//			else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg);
-
-			return 1;
-
-		default:
-			// ipu repeats every 0x100
-			_eeReadConstMem32(x86reg, (u32)(((u8*)ipuRegs)+(mem&0xff)));
-			return 0;
-	}
-
-	return 0;
-}
-
-void ipuConstRead64(u32 mem, int mmreg)
-{
-	iFlushCall(0);
-	CALLFunc((u32)IPUProcessInterrupt);
-
-	if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (u32)(((u8*)ipuRegs)+(mem&0xff)));
-	else {
-		MOVQMtoR(mmreg, (u32)(((u8*)ipuRegs)+(mem&0xff)));
-		SetMMXstate();
-	}
-}
-
-///////////////////////////////////////////////////////////////////////
-//  IPU Register Writes!
-
-void ipuConstWrite32(u32 mem, int mmreg)
-{
-	iFlushCall(0);
-	if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) PUSH32R(mmreg);
-	CALLFunc((u32)IPUProcessInterrupt);
-
-	switch (mem){
-		case 0x10002000: // IPU_CMD
-			if( (mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) _recPushReg(mmreg);
-			CALLFunc((u32)IPUCMD_WRITE);
-			ADD32ItoR(ESP, 4);
-			break;
-		case 0x10002010: // IPU_CTRL
-			if( mmreg & MEM_EECONSTTAG ) {
-				u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x47f30000;
-
-				if( c & 0x40000000 ) {
-					CALLFunc((u32)ipuSoftReset);
-				}
-				else {
-					AND32ItoM((u32)&ipuRegs->ctrl._u32, 0x8000ffff);
-					OR32ItoM((u32)&ipuRegs->ctrl._u32, c);
-				}
-			}
-			else {
-				if( mmreg & MEM_XMMTAG ) SSE2_MOVD_XMM_to_R(EAX, mmreg&0xf);
-				else if( mmreg & MEM_MMXTAG ) MOVD32MMXtoR(EAX, mmreg&0xf);
-				else POP32R(EAX);
-
-				MOV32MtoR(ECX, (u32)&ipuRegs->ctrl._u32);
-				AND32ItoR(EAX, 0x47f30000);
-				AND32ItoR(ECX, 0x8000ffff);
-				OR32RtoR(EAX, ECX);
-				MOV32RtoM((u32)&ipuRegs->ctrl._u32, EAX);
-
-				TEST32ItoR(EAX, 0x40000000);
-				j8Ptr[5] = JZ8(0);
-
-				// reset
-				CALLFunc((u32)ipuSoftReset);
-
-				x86SetJ8( j8Ptr[5] );
-			}
-
-			break;
-		default:
-			if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) POP32R(mmreg);
-			_eeWriteConstMem32((u32)((u8*)ipuRegs + (mem&0xfff)), mmreg);
-			break;
-	}
-}
-
-void ipuConstWrite64(u32 mem, int mmreg)
-{
-	iFlushCall(0);
-	CALLFunc((u32)IPUProcessInterrupt);
-
-	switch (mem){
-		case 0x10002000:
-			_recPushReg(mmreg);
-			CALLFunc((u32)IPUCMD_WRITE);
-			ADD32ItoR(ESP, 4);
-			break;
-
-		default:
-			_eeWriteConstMem64( (u32)((u8*)ipuRegs + (mem&0xfff)), mmreg);
-			break;
-	}
-}
diff --git a/pcsx2/x86/iPsxHw.cpp b/pcsx2/x86/iPsxHw.cpp
deleted file mode 100644
index 84c617dc0d..0000000000
--- a/pcsx2/x86/iPsxHw.cpp
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
- *  Copyright (C) 2002-2009  Pcsx2 Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include "PrecompiledHeader.h"
-
-#include "PsxCommon.h"
-#include "iR5900.h"
-
-extern int g_pbufi;
-extern s8 g_pbuf[1024];
-
-#define CONSTREAD8_CALL(name) { \
-	iFlushCall(0); \
-	CALLFunc((uptr)name); \
-	if( sign ) MOVSX32R8toR(EAX, EAX); \
-	else MOVZX32R8toR(EAX, EAX); \
-} \
-
-static u32 s_16 = 0x10;
-
-int psxHwConstRead8(u32 x86reg, u32 add, u32 sign) {
-	
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		PUSH32I(add);
-		CONSTREAD8_CALL(USBread8);
-		// since calling from different dll, esp already changed
-		return 1;
-	}
-
-	switch (add) {
-		case 0x1f801040:
-			CONSTREAD8_CALL(sioRead8);
-			return 1;
-      //  case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now
-
-#ifdef PCSX2_DEVBUILD
-		case 0x1f801100:
-		case 0x1f801104:
-		case 0x1f801108:
-		case 0x1f801110:
-		case 0x1f801114:
-		case 0x1f801118:
-		case 0x1f801120:
-		case 0x1f801124:
-		case 0x1f801128:
-		case 0x1f801480:
-		case 0x1f801484:
-		case 0x1f801488:
-		case 0x1f801490:
-		case 0x1f801494:
-		case 0x1f801498:
-		case 0x1f8014a0:
-		case 0x1f8014a4:
-		case 0x1f8014a8:
-			SysPrintf("8bit counter read %x\n", add);
-			_eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign);
-			return 0;
-#endif
-
-		case 0x1f80146e: // DEV9_R_REV
-			PUSH32I(add);
-			CONSTREAD8_CALL(DEV9read8);
-			return 1;
-
-		case 0x1f801800: CONSTREAD8_CALL(cdrRead0); return 1;
-		case 0x1f801801: CONSTREAD8_CALL(cdrRead1); return 1;
-		case 0x1f801802: CONSTREAD8_CALL(cdrRead2); return 1;
-		case 0x1f801803: CONSTREAD8_CALL(cdrRead3); return 1;
-
-		case 0x1f803100: // PS/EE/IOP conf related
-			if( IS_XMMREG(x86reg) ) SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&s_16);
-			MMXONLY(else if( IS_MMXREG(x86reg) ) MOVDMtoMMX(x86reg&0xf, (uptr)&s_16);)
-			else MOV32ItoR(x86reg, 0x10);
-			return 0;
-
-		case 0x1F808264: //sio2 serial data feed/fifo_out
-			CONSTREAD8_CALL(sio2_fifoOut);
-			return 1;
-
-		default:
-			_eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign);
-			return 0;
-	}
-}
-
-#define CONSTREAD16_CALL(name) { \
-	iFlushCall(0); \
-	CALLFunc((uptr)name); \
-	if( sign ) MOVSX32R16toR(EAX, EAX); \
-	else MOVZX32R16toR(EAX, EAX); \
-} \
-
-void psxConstReadCounterMode16(int x86reg, int index, int sign)
-{
-	if( IS_MMXREG(x86reg) ) {
-		MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode);
-		MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode - 2);)
-	}
-	else {
-		if( sign ) MOVSX32M16toR(ECX, (uptr)&psxCounters[index].mode);
-		else MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode);
-
-		MOV32RtoR(x86reg, ECX);
-	}
-
-	AND16ItoR(ECX, ~0x1800);
-	OR16ItoR(ECX, 0x400);
-	MOV16RtoM((uptr)&psxCounters[index].mode, ECX);
-}
-
-int psxHwConstRead16(u32 x86reg, u32 add, u32 sign) {
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		PUSH32I(add);
-		CONSTREAD16_CALL(USBread16);
-		return 1;
-	}
-
-	switch (add) {
-
-		case 0x1f801040:
-			iFlushCall(0);
-			CALLFunc((uptr)sioRead8);
-            PUSHR(EAX);
-			CALLFunc((uptr)sioRead8);
-			POPR(ECX);
-			AND32ItoR(ECX, 0xff);
-			SHL32ItoR(EAX, 8);
-			OR32RtoR(EAX, ECX);
-			if( sign ) MOVSX32R16toR(EAX, EAX);
-			else MOVZX32R16toR(EAX, EAX);
-			return 1;
-
-		case 0x1f801044:
-			_eeReadConstMem16(x86reg, (uptr)&sio.StatReg, sign);
-			return 0;
-
-		case 0x1f801048:
-			_eeReadConstMem16(x86reg, (uptr)&sio.ModeReg, sign);
-			return 0;
-
-		case 0x1f80104a:
-			_eeReadConstMem16(x86reg, (uptr)&sio.CtrlReg, sign);
-			return 0;
-
-		case 0x1f80104e:
-			_eeReadConstMem16(x86reg, (uptr)&sio.BaudReg, sign);
-			return 0;
-
-		// counters[0]
-		case 0x1f801100:
-			PUSH32I(0);
-			CONSTREAD16_CALL(psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801104:
-			psxConstReadCounterMode16(x86reg, 0, sign);
-			return 0;
-
-		case 0x1f801108:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[0].target, sign);
-			return 0;
-
-		// counters[1]
-		case 0x1f801110:
-			PUSH32I(1);
-			CONSTREAD16_CALL(psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801114:
-			psxConstReadCounterMode16(x86reg, 1, sign);
-			return 0;
-
-		case 0x1f801118:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[1].target, sign);
-			return 0;
-
-		// counters[2]
-		case 0x1f801120:
-			PUSH32I(2);
-			CONSTREAD16_CALL(psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801124:
-			psxConstReadCounterMode16(x86reg, 2, sign);
-			return 0;
-
-		case 0x1f801128:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[2].target, sign);
-			return 0;
-
-		case 0x1f80146e: // DEV9_R_REV
-			PUSH32I(add);
-			CONSTREAD16_CALL(DEV9read16);
-			return 1;
-
-		// counters[3]
-		case 0x1f801480:
-			PUSH32I(3);
-			CONSTREAD16_CALL(psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f801484:
-			psxConstReadCounterMode16(x86reg, 3, sign);
-			return 0;
-
-		case 0x1f801488:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[3].target, sign);
-			return 0;
-
-		// counters[4]
-		case 0x1f801490:
-			PUSH32I(4);
-			CONSTREAD16_CALL(psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f801494:
-			psxConstReadCounterMode16(x86reg, 4, sign);
-			return 0;
-			
-		case 0x1f801498:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[4].target, sign);
-			return 0;
-
-		// counters[5]
-		case 0x1f8014a0:
-			PUSH32I(5);
-			CONSTREAD16_CALL(psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f8014a4:
-			psxConstReadCounterMode16(x86reg, 5, sign);
-			return 0;
-
-		case 0x1f8014a8:
-			_eeReadConstMem16(x86reg, (uptr)&psxCounters[5].target, sign);
-			return 0;
-
-		default:			
-			if (add>=0x1f801c00 && add<0x1f801e00) {
-			
-				PUSH32I(add);
-				CONSTREAD16_CALL(SPU2read);
-				return 1;
-			} else {
-				_eeReadConstMem16(x86reg, (uptr)&psxH[(add) & 0xffff], sign);
-				return 0;
-			}
-	}
-}
-
-void psxConstReadCounterMode32(int x86reg, int index)
-{
-	if( IS_MMXREG(x86reg) ) {
-		MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode);
-		MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode);)
-	}
-	else {
-		MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode);
-		MOV32RtoR(x86reg, ECX);
-	}
-
-	//AND16ItoR(ECX, ~0x1800);
-	//OR16ItoR(ECX, 0x400);
-	//MOV16RtoM((uptr)&psxCounters[index].mode, ECX);
-}
-
-static u32 s_tempsio;
-int psxHwConstRead32(u32 x86reg, u32 add) {
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)USBread32);
-		return 1;
-	}
-	if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess..
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)FWread32);
-		return 1;
-	}
-
-	switch (add) {
-		case 0x1f801040:
-			iFlushCall(0);
-			CALLFunc((uptr)sioRead8);
-			AND32ItoR(EAX, 0xff);
-			MOV32RtoM((uptr)&s_tempsio, EAX);
-			CALLFunc((uptr)sioRead8);
-			AND32ItoR(EAX, 0xff);
-			SHL32ItoR(EAX, 8);
-			OR32RtoM((uptr)&s_tempsio, EAX);
-
-			// 3rd
-			CALLFunc((uptr)sioRead8);
-			AND32ItoR(EAX, 0xff);
-			SHL32ItoR(EAX, 16);
-			OR32RtoM((uptr)&s_tempsio, EAX);
-
-			// 4th
-			CALLFunc((uptr)sioRead8);
-			SHL32ItoR(EAX, 24);
-			OR32MtoR(EAX, (uptr)&s_tempsio);
-			return 1;
-			
-		//case 0x1f801050: hard = serial_read32(); break;//serial port
-		case 0x1f801078:
-			PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078));
-			_eeReadConstMem32(x86reg, (uptr)&psxH[add&0xffff]);
-			MOV32ItoM((uptr)&psxH[add&0xffff], 0);
-			return 0;
-		
-			// counters[0]
-		case 0x1f801100:
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801104:
-			psxConstReadCounterMode32(x86reg, 0);
-			return 0;
-
-		case 0x1f801108:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[0].target);
-			return 0;
-
-		// counters[1]
-		case 0x1f801110:
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801114:
-			psxConstReadCounterMode32(x86reg, 1);
-			return 0;
-
-		case 0x1f801118:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[1].target);
-			return 0;
-
-		// counters[2]
-		case 0x1f801120:
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)psxRcntRcount16);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		case 0x1f801124:
-			psxConstReadCounterMode32(x86reg, 2);
-			return 0;
-
-		case 0x1f801128:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[2].target);
-			return 0;
-
-		// counters[3]
-		case 0x1f801480:
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f801484:
-			psxConstReadCounterMode32(x86reg, 3);
-			return 0;
-
-		case 0x1f801488:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[3].target);
-			return 0;
-
-		// counters[4]
-		case 0x1f801490:
-			iFlushCall(0);
-			PUSH32I(4);
-			CALLFunc((uptr)psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f801494:
-			psxConstReadCounterMode32(x86reg, 4);
-			return 0;
-			
-		case 0x1f801498:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[4].target);
-			return 0;
-
-		// counters[5]
-		case 0x1f8014a0:
-			iFlushCall(0);
-			PUSH32I(5);
-			CALLFunc((uptr)psxRcntRcount32);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1f8014a4:
-			psxConstReadCounterMode32(x86reg, 5);
-			return 0;
-
-		case 0x1f8014a8:
-			_eeReadConstMem32(x86reg, (uptr)&psxCounters[5].target);
-			return 0;
-
-		case 0x1F808200:
-		case 0x1F808204:
-		case 0x1F808208:
-		case 0x1F80820C:
-		case 0x1F808210:
-		case 0x1F808214:
-		case 0x1F808218:
-		case 0x1F80821C:
-		case 0x1F808220:
-		case 0x1F808224:
-		case 0x1F808228:
-		case 0x1F80822C:
-		case 0x1F808230:
-		case 0x1F808234:
-		case 0x1F808238:
-		case 0x1F80823C:
-			iFlushCall(0);
-			PUSH32I((add-0x1F808200)/4);
-			CALLFunc((uptr)sio2_getSend3);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1F808240:
-		case 0x1F808248:
-		case 0x1F808250:
-		case 0x1F80825C:
-			iFlushCall(0);
-			PUSH32I((add-0x1F808240)/8);
-			CALLFunc((uptr)sio2_getSend1);
-			ADD32ItoR(ESP, 4);
-			return 1;
-		
-		case 0x1F808244:
-		case 0x1F80824C:
-		case 0x1F808254:
-		case 0x1F808258:
-			iFlushCall(0);
-			PUSH32I((add-0x1F808244)/8);
-			CALLFunc((uptr)sio2_getSend2);
-			ADD32ItoR(ESP, 4);
-			return 1;
-
-		case 0x1F808268:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_getCtrl);
-			return 1;
-			
-		case 0x1F80826C:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_getRecv1);
-			return 1;
-
-		case 0x1F808270:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_getRecv2);
-			return 1;
-
-		case 0x1F808274:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_getRecv3);
-			return 1;
-
-		case 0x1F808278:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_get8278);
-			return 1;
-
-		case 0x1F80827C:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_get827C);
-			return 1;
-
-		case 0x1F808280:
-			iFlushCall(0);
-			CALLFunc((uptr)sio2_getIntr);
-			return 1;
-
-		case 0x1F801C00:
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)SPU2ReadMemAddr);
-			return 1;
-
-		case 0x1F801500:
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)SPU2ReadMemAddr);
-			return 1;
-
-		default:
-			_eeReadConstMem32(x86reg, (uptr)&psxH[(add) & 0xffff]);
-			return 0;
-	}
-}
-
-#define CONSTWRITE_CALL(name) { \
-	_recPushReg(mmreg); \
-	iFlushCall(0); \
-	CALLFunc((uptr)name); \
-	ADD32ItoR(ESP, 4); \
-} \
-
-void Write8PrintBuffer(u8 value)
-{
-	if (value == '\r') return;
-	if (value == '\n' || g_pbufi >= 1023) {
-		g_pbuf[g_pbufi++] = 0; g_pbufi = 0;
-		SysPrintf("%s\n", g_pbuf); return;
-	}
-	g_pbuf[g_pbufi++] = value;
-}
-
-void psxHwConstWrite8(u32 add, int mmreg)
-{
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)USBwrite8);
-		return;
-	}
-
-	switch (add) {
-		case 0x1f801040:
-			CONSTWRITE_CALL(sioWrite8); break;
-		//case 0x1f801050: serial_write8(value); break;//serial port
-		case 0x1f801100:
-		case 0x1f801104:
-		case 0x1f801108:
-		case 0x1f801110:
-		case 0x1f801114:
-		case 0x1f801118:
-		case 0x1f801120:
-		case 0x1f801124:
-		case 0x1f801128:
-		case 0x1f801480:
-		case 0x1f801484:
-		case 0x1f801488:
-		case 0x1f801490:
-		case 0x1f801494:
-		case 0x1f801498:
-		case 0x1f8014a0:
-		case 0x1f8014a4:
-		case 0x1f8014a8:
-			SysPrintf("8bit counter write %x\n", add);
-			_eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg);
-			return;
-		case 0x1f801800: CONSTWRITE_CALL(cdrWrite0); break;
-		case 0x1f801801: CONSTWRITE_CALL(cdrWrite1); break;
-		case 0x1f801802: CONSTWRITE_CALL(cdrWrite2); break;
-		case 0x1f801803: CONSTWRITE_CALL(cdrWrite3); break;
-		case 0x1f80380c: CONSTWRITE_CALL(Write8PrintBuffer); break;
-		case 0x1F808260: CONSTWRITE_CALL(sio2_serialIn); break;
-
-		default:
-			_eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg);
-			return;
-	}
-}
-
-void psxHwConstWrite16(u32 add, int mmreg) {
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)USBwrite16);
-		return;
-	}
-
-	switch (add) {
-		case 0x1f801040:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 1);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 3);
-			return;
-		case 0x1f801044:
-			return;
-		case 0x1f801048:
-			_eeWriteConstMem16((uptr)&sio.ModeReg, mmreg);
-			return;
-		case 0x1f80104a: // control register
-			CONSTWRITE_CALL(sioWriteCtrl16);
-			return;
-		case 0x1f80104e: // baudrate register
-			_eeWriteConstMem16((uptr)&sio.BaudReg, mmreg);
-			return;
-
-		case 0x1f801070:
-			_eeWriteConstMem16OP((uptr)&psxHu32(0x1070), mmreg, 0);		// AND operation
-			return;
-
-		case 0x1f801074:
-			_eeWriteConstMem16((uptr)&psxHu32(0x1074), mmreg);
-			iFlushCall(0);
-			CALLFunc( (uptr)&iopTestIntc );
-			return;
-
-		case 0x1f801078:
-			//According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p
-			_eeWriteConstMem16((uptr)&psxHu32(0x1078), mmreg);
-			iFlushCall(0);
-			CALLFunc( (uptr)&iopTestIntc );
-			return;
-
-		// counters[0]
-		case 0x1f801100:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-		case 0x1f801104:
-			CONSTWRITE_CALL(psxRcnt0Wmode);
-			return;
-		case 0x1f801108:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[1]
-		case 0x1f801110:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801114:
-			CONSTWRITE_CALL(psxRcnt1Wmode);
-			return;
-
-		case 0x1f801118:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[2]
-		case 0x1f801120:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801124:
-			CONSTWRITE_CALL(psxRcnt2Wmode);
-			return;
-
-		case 0x1f801128:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[3]
-		case 0x1f801480:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801484:
-			CONSTWRITE_CALL(psxRcnt3Wmode);
-			return;
-
-		case 0x1f801488:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[4]
-		case 0x1f801490:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(4);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801494:
-			CONSTWRITE_CALL(psxRcnt4Wmode);
-			return;
-
-		case 0x1f801498:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(4);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[5]
-		case 0x1f8014a0:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(5);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f8014a4:
-			CONSTWRITE_CALL(psxRcnt5Wmode);
-			return;
-
-		case 0x1f8014a8:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(5);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		default:
-			if (add>=0x1f801c00 && add<0x1f801e00) {
-				_recPushReg(mmreg);
-				iFlushCall(0);
-				PUSH32I(add);
-            	CALLFunc((uptr)SPU2write);
-				// leave esp alone
-				return;
-			}
-
-			_eeWriteConstMem16((uptr)&psxH[(add) & 0xffff], mmreg);
-			return;
-	}
-}
-
-#define recDmaExec(n) { \
-	iFlushCall(0); \
-	if( n > 6 ) TEST32ItoM((uptr)&HW_DMA_PCR2, 8 << (((n<<2)-28)&0x1f)); \
-	else 		TEST32ItoM((uptr)&HW_DMA_PCR,  8 << (((n<<2))&0x1f)); \
-	j8Ptr[5] = JZ8(0); \
-	MOV32MtoR(EAX, (uptr)&HW_DMA##n##_CHCR); \
-	TEST32ItoR(EAX, 0x01000000); \
-	j8Ptr[6] = JZ8(0); \
-	\
-    _callFunctionArg3((uptr)psxDma##n, MEM_MEMORYTAG, MEM_MEMORYTAG, MEM_X86TAG, (uptr)&HW_DMA##n##_MADR, (uptr)&HW_DMA##n##_BCR, EAX); \
-	\
-	x86SetJ8( j8Ptr[5] ); \
-	x86SetJ8( j8Ptr[6] ); \
-} \
-
-#define CONSTWRITE_CALL32(name) { \
-	iFlushCall(0); \
-	_recPushReg(mmreg); \
-	CALLFunc((uptr)name); \
-	ADD32ItoR(ESP, 4); \
-} \
-
-void psxHwConstWrite32(u32 add, int mmreg)
-{
-	if (add >= 0x1f801600 && add < 0x1f801700) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)USBwrite32);
-		return;
-	}
-	if (add >= 0x1f808400 && add <= 0x1f808550) {
-		_recPushReg(mmreg);
-		iFlushCall(0);
-		PUSH32I(add);
-		CALLFunc((uptr)FWwrite32);
-		return;
-	}
-
-	switch (add) {
-	    case 0x1f801040:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 1);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 1);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 1);
-			CALLFunc((uptr)sioWrite8);
-			ADD32ItoR(ESP, 1);
-			return;
-
-		case 0x1f801070:
-			_eeWriteConstMem32OP((uptr)&psxHu32(0x1070), mmreg, 0); // and
-			return;
-
-		case 0x1f801074:
-			_eeWriteConstMem32((uptr)&psxHu32(0x1074), mmreg);
-			iFlushCall(0);
-			CALLFunc( (uptr)&iopTestIntc );
-			return;
-
-		case 0x1f801078:
-			//According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p
-			_eeWriteConstMem32((uptr)&psxHu32(0x1078), mmreg);
-			iFlushCall(0);
-			CALLFunc( (uptr)&iopTestIntc );
-			return;
-
-//		case 0x1f801088:
-//			HW_DMA0_CHCR = value;        // DMA0 chcr (MDEC in DMA)
-////			DmaExec(0);
-//			return;
-
-//		case 0x1f801098:
-//			HW_DMA1_CHCR = value;        // DMA1 chcr (MDEC out DMA)
-////			DmaExec(1);
-//			return;
-		
-		case 0x1f8010a8:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(2);
-			return;
-
-		case 0x1f8010b8:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(3);
-			return;
-
-		case 0x1f8010c8:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(4);
-			return;
-
-		case 0x1f8010e8:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(6);
-			return;
-
-		case 0x1f801508:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(7);
-			return;
-
-		case 0x1f801518:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(8);
-			return;
-
-		case 0x1f801528:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(9);
-			return;
-
-		case 0x1f801538:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(10);
-			return;
-
-		case 0x1f801548:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(11);
-			return;
-
-		case 0x1f801558:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			recDmaExec(12);
-			return;
-
-		case 0x1f8010f4:
-		case 0x1f801574:
-		{
-			// u32 tmp = (~value) & HW_DMA_ICR;
-			_eeMoveMMREGtoR(EAX, mmreg);
-			MOV32RtoR(ECX, EAX);
-			NOT32R(ECX);
-			AND32MtoR(ECX, (uptr)&psxH[(add) & 0xffff]);
-
-			// HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp;
-			XOR32RtoR(EAX, ECX);
-			AND32ItoR(EAX, 0xffffff);
-			XOR32RtoR(EAX, ECX);
-			MOV32RtoM((uptr)&psxH[(add) & 0xffff], EAX);
-			return;
-		}
-
-		// counters[0]
-		case 0x1f801100:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-		case 0x1f801104:
-			CONSTWRITE_CALL32(psxRcnt0Wmode);
-			return;
-		case 0x1f801108:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[1]
-		case 0x1f801110:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801114:
-			CONSTWRITE_CALL32(psxRcnt1Wmode);
-			return;
-
-		case 0x1f801118:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[2]
-		case 0x1f801120:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)psxRcntWcount16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801124:
-			CONSTWRITE_CALL32(psxRcnt2Wmode);
-			return;
-
-		case 0x1f801128:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(2);
-			CALLFunc((uptr)psxRcntWtarget16);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[3]
-		case 0x1f801480:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801484:
-			CONSTWRITE_CALL32(psxRcnt3Wmode);
-			return;
-
-		case 0x1f801488:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(3);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[4]
-		case 0x1f801490:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(4);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f801494:
-			CONSTWRITE_CALL32(psxRcnt4Wmode);
-			return;
-
-		case 0x1f801498:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(4);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		// counters[5]
-		case 0x1f8014a0:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(5);
-			CALLFunc((uptr)psxRcntWcount32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f8014a4:
-			CONSTWRITE_CALL32(psxRcnt5Wmode);
-			return;
-
-		case 0x1f8014a8:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(5);
-			CALLFunc((uptr)psxRcntWtarget32);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1f8014c0:
-			SysPrintf("RTC_HOLDMODE 32bit write\n");
-			break;
-
-		case 0x1F808200:
-		case 0x1F808204:
-		case 0x1F808208:
-		case 0x1F80820C:
-		case 0x1F808210:
-		case 0x1F808214:
-		case 0x1F808218:
-		case 0x1F80821C:
-		case 0x1F808220:
-		case 0x1F808224:
-		case 0x1F808228:
-		case 0x1F80822C:
-		case 0x1F808230:
-		case 0x1F808234:
-		case 0x1F808238:
-		case 0x1F80823C:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I((add-0x1F808200)/4);
-			CALLFunc((uptr)sio2_setSend3);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1F808240:
-		case 0x1F808248:
-		case 0x1F808250:
-		case 0x1F808258:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I((add-0x1F808240)/8);
-			CALLFunc((uptr)sio2_setSend1);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1F808244:
-		case 0x1F80824C:
-		case 0x1F808254:
-		case 0x1F80825C:
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I((add-0x1F808244)/8);
-			CALLFunc((uptr)sio2_setSend2);
-			ADD32ItoR(ESP, 8);
-			return;
-
-		case 0x1F808268: CONSTWRITE_CALL32(sio2_setCtrl); return;
-		case 0x1F808278: CONSTWRITE_CALL32(sio2_set8278);	return;
-		case 0x1F80827C: CONSTWRITE_CALL32(sio2_set827C);	return;
-		case 0x1F808280: CONSTWRITE_CALL32(sio2_setIntr);	return;
-		
-		case 0x1F8010C0:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(0);
-			CALLFunc((uptr)SPU2WriteMemAddr);
-			return;
-
-		case 0x1F801500:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			_recPushReg(mmreg);
-			iFlushCall(0);
-			PUSH32I(1);
-			CALLFunc((uptr)SPU2WriteMemAddr);
-			return;
-		default:
-			_eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg);
-			return;
-	}
-}
-
-int psxHw4ConstRead8(u32 x86reg, u32 add, u32 sign) {
-	switch (add) {
-		case 0x1f402004: CONSTREAD8_CALL((uptr)cdvdRead04); return 1;
-		case 0x1f402005: CONSTREAD8_CALL((uptr)cdvdRead05); return 1;
-		case 0x1f402006: CONSTREAD8_CALL((uptr)cdvdRead06); return 1;
-		case 0x1f402007: CONSTREAD8_CALL((uptr)cdvdRead07); return 1;
-		case 0x1f402008: CONSTREAD8_CALL((uptr)cdvdRead08); return 1;
-		case 0x1f40200A: CONSTREAD8_CALL((uptr)cdvdRead0A); return 1;
-		case 0x1f40200B: CONSTREAD8_CALL((uptr)cdvdRead0B); return 1;
-		case 0x1f40200C: CONSTREAD8_CALL((uptr)cdvdRead0C); return 1;
-		case 0x1f40200D: CONSTREAD8_CALL((uptr)cdvdRead0D); return 1;
-		case 0x1f40200E: CONSTREAD8_CALL((uptr)cdvdRead0E); return 1;
-		case 0x1f40200F: CONSTREAD8_CALL((uptr)cdvdRead0F); return 1;
-		case 0x1f402013: CONSTREAD8_CALL((uptr)cdvdRead13); return 1;
-		case 0x1f402015: CONSTREAD8_CALL((uptr)cdvdRead15); return 1;
-		case 0x1f402016: CONSTREAD8_CALL((uptr)cdvdRead16); return 1;
-		case 0x1f402017: CONSTREAD8_CALL((uptr)cdvdRead17); return 1;
-		case 0x1f402018: CONSTREAD8_CALL((uptr)cdvdRead18); return 1;
-		case 0x1f402020: CONSTREAD8_CALL((uptr)cdvdRead20); return 1;
-		case 0x1f402021: CONSTREAD8_CALL((uptr)cdvdRead21); return 1;
-		case 0x1f402022: CONSTREAD8_CALL((uptr)cdvdRead22); return 1;
-		case 0x1f402023: CONSTREAD8_CALL((uptr)cdvdRead23); return 1;
-		case 0x1f402024: CONSTREAD8_CALL((uptr)cdvdRead24); return 1;
-		case 0x1f402028: CONSTREAD8_CALL((uptr)cdvdRead28); return 1;
-		case 0x1f402029: CONSTREAD8_CALL((uptr)cdvdRead29); return 1;
-		case 0x1f40202A: CONSTREAD8_CALL((uptr)cdvdRead2A); return 1;
-		case 0x1f40202B: CONSTREAD8_CALL((uptr)cdvdRead2B); return 1;
-		case 0x1f40202C: CONSTREAD8_CALL((uptr)cdvdRead2C); return 1;
-		case 0x1f402030: CONSTREAD8_CALL((uptr)cdvdRead30); return 1;
-		case 0x1f402031: CONSTREAD8_CALL((uptr)cdvdRead31); return 1;
-		case 0x1f402032: CONSTREAD8_CALL((uptr)cdvdRead32); return 1;
-		case 0x1f402033: CONSTREAD8_CALL((uptr)cdvdRead33); return 1;
-		case 0x1f402034: CONSTREAD8_CALL((uptr)cdvdRead34); return 1;
-		case 0x1f402038: CONSTREAD8_CALL((uptr)cdvdRead38); return 1;
-		case 0x1f402039: CONSTREAD8_CALL((uptr)cdvdRead39); return 1;
-		case 0x1f40203A: CONSTREAD8_CALL((uptr)cdvdRead3A); return 1;
-		default:
-			Console::Notice("*Unknown 8bit read at address %lx", params add);
-			XOR32RtoR(x86reg, x86reg);
-			return 0;
-	}
-}
-
-void psxHw4ConstWrite8(u32 add, int mmreg) {
-	switch (add) {
-		case 0x1f402004: CONSTWRITE_CALL(cdvdWrite04); return;
-		case 0x1f402005: CONSTWRITE_CALL(cdvdWrite05); return;
-		case 0x1f402006: CONSTWRITE_CALL(cdvdWrite06); return;
-		case 0x1f402007: CONSTWRITE_CALL(cdvdWrite07); return;
-		case 0x1f402008: CONSTWRITE_CALL(cdvdWrite08); return;
-		case 0x1f40200A: CONSTWRITE_CALL(cdvdWrite0A); return;
-		case 0x1f40200F: CONSTWRITE_CALL(cdvdWrite0F); return;
-		case 0x1f402014: CONSTWRITE_CALL(cdvdWrite14); return;
-		case 0x1f402016: 
-			MMXONLY(_freeMMXregs();)
-			CONSTWRITE_CALL(cdvdWrite16);
-			return;
-		case 0x1f402017: CONSTWRITE_CALL(cdvdWrite17); return;
-		case 0x1f402018: CONSTWRITE_CALL(cdvdWrite18); return;
-		case 0x1f40203A: CONSTWRITE_CALL(cdvdWrite3A); return;
-		default:
-			Console::Notice("*Unknown 8bit write at address %lx", params add);
-			return;
-	}
-}
diff --git a/pcsx2/x86/iR5900CoissuedLoadStore.cpp b/pcsx2/x86/iR5900CoissuedLoadStore.cpp
deleted file mode 100644
index 7ca346bc9a..0000000000
--- a/pcsx2/x86/iR5900CoissuedLoadStore.cpp
+++ /dev/null
@@ -1,1738 +0,0 @@
-/*  Pcsx2 - Pc Ps2 Emulator
-*  Copyright (C) 2002-2008  Pcsx2 Team
-*
-*  This program is free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*  
-*  This program is distributed in the hope that it will be useful,
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*  GNU General Public License for more details.
-*  
-*  You should have received a copy of the GNU General Public License
-*  along with this program; if not, write to the Free Software
-*  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-*/
-
-#include "PrecompiledHeader.h"
-
-#ifdef PCSX2_VM_COISSUE
-
-#include "Common.h"
-#include "R5900OpcodeTables.h"
-#include "iR5900LoadStore.h"
-#include "iR5900.h"
-
-namespace R5900 { 
-namespace Dynarec { 
-namespace OpcodeImpl {
-
-#define _Imm_co_ (*(s16*)PSM(pc))
-
-int _eePrepareReg_coX(int gprreg, int num)
-{
-	int mmreg = _eePrepareReg(gprreg);
-
-	if( (mmreg&MEM_MMXTAG) && num == 7 ) {
-		if( mmxregs[mmreg&0xf].mode & MODE_WRITE ) {
-			MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg], mmreg&0xf);
-			mmxregs[mmreg&0xf].mode &= ~MODE_WRITE;
-			mmxregs[mmreg&0xf].needed = 0;
-		}
-	}
-
-	return mmreg;
-}
-
-void recLoad32_co(u32 bit, u32 sign)
-{
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-	int mmreg1 = -1, mmreg2 = -1;
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		int ineax = 0;
-		u32 written = 0;
-
-		_eeOnLoadWrite(_Rt_);
-		_eeOnLoadWrite(nextrt);
-
-		if( bit == 32 ) {
-			mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE);
-			if( mmreg1 >= 0 ) mmreg1 |= MEM_MMXTAG;
-			else mmreg1 = EBX;
-
-			mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE);
-			if( mmreg2 >= 0 ) mmreg2 |= MEM_MMXTAG;
-			else mmreg2 = EAX;
-		}
-		else {
-			_deleteEEreg(_Rt_, 0);
-			_deleteEEreg(nextrt, 0);
-			mmreg1 = EBX;
-			mmreg2 = EAX;
-		}
-
-		// do const processing
-		switch(bit) {
-			case 8:
-				if( recMemConstRead8(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) {
-					if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0;
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-					written = 1;
-				}
-				ineax = recMemConstRead8(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign);
-				break;
-			case 16:
-				if( recMemConstRead16(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) {
-					if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0;
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-					written = 1;
-				}
-				ineax = recMemConstRead16(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign);
-				break;
-			case 32:
-				assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 );
-				if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) {
-					if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0;
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-					written = 1;
-				}
-				ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_);
-				break;
-		}
-
-		if( !written && _Rt_ ) {
-			if( mmreg1&MEM_MMXTAG ) {
-				assert( mmxregs[mmreg1&0xf].mode & MODE_WRITE );
-				if( sign ) _signExtendGPRtoMMX(mmreg1&0xf, _Rt_, 32-bit);
-				else if( bit < 32 ) PSRLDItoR(mmreg1&0xf, 32-bit);
-			}
-			else recTransferX86ToReg(mmreg1, _Rt_, sign);
-		}
-		if( nextrt ) {
-			g_pCurInstInfo++;
-			if( !ineax && (mmreg2 & MEM_MMXTAG) ) {
-				assert( mmxregs[mmreg2&0xf].mode & MODE_WRITE );
-				if( sign ) _signExtendGPRtoMMX(mmreg2&0xf, nextrt, 32-bit);
-				else if( bit < 32 ) PSRLDItoR(mmreg2&0xf, 32-bit);
-			}
-			else {
-				if( mmreg2&MEM_MMXTAG ) mmxregs[mmreg2&0xf].inuse = 0;
-				recTransferX86ToReg(mmreg2, nextrt, sign);
-			}
-			g_pCurInstInfo--;
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-		assert( !REC_FORCEMMX );
-
-		_eeOnLoadWrite(_Rt_);
-		_eeOnLoadWrite(nextrt);
-		_deleteEEreg(_Rt_, 0);
-		_deleteEEreg(nextrt, 0);
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0);
-
-		switch(bit) {
-			case 8:
-				if( sign ) {
-					MOVSX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-					MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				}
-				else {
-					MOVZX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-					MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				}
-				break;
-			case 16:
-				if( sign ) {
-					MOVSX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-					MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				}
-				else {
-					MOVZX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-					MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				}
-				break;
-			case 32:
-				MOV32RmtoROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-				MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				break;
-		}
-
-		if ( _Rt_ ) recTransferX86ToReg(EBX, _Rt_, sign);
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			switch(bit) {
-				case 8:
-					MOV32RtoM((u32)&s_tempaddr, ECX);
-					CALLFunc( (int)recMemRead8 );
-					if( sign ) MOVSX32R8toR(EAX, EAX);
-					MOV32MtoR(ECX, (u32)&s_tempaddr);
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-
-					ADD32ItoR(ECX, _Imm_co_-_Imm_);
-					CALLFunc( (int)recMemRead8 );
-					if( sign ) MOVSX32R8toR(EAX, EAX);
-					break;
-				case 16:
-					MOV32RtoM((u32)&s_tempaddr, ECX);
-					CALLFunc( (int)recMemRead16 );
-					if( sign ) MOVSX32R16toR(EAX, EAX);
-					MOV32MtoR(ECX, (u32)&s_tempaddr);
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-
-					ADD32ItoR(ECX, _Imm_co_-_Imm_);
-					CALLFunc( (int)recMemRead16 );
-					if( sign ) MOVSX32R16toR(EAX, EAX);
-					break;
-				case 32:
-					MOV32RtoM((u32)&s_tempaddr, ECX);
-					iMemRead32Check();
-					CALLFunc( (int)recMemRead32 );
-					MOV32MtoR(ECX, (u32)&s_tempaddr);
-					if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign);
-
-					ADD32ItoR(ECX, _Imm_co_-_Imm_);
-					iMemRead32Check();
-					CALLFunc( (int)recMemRead32 );
-					break;
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]);
-			else x86SetJ8(j8Ptr[2]);
-		}
-
-		if( nextrt ) {
-			g_pCurInstInfo++;
-			recTransferX86ToReg(EAX, nextrt, sign);
-			g_pCurInstInfo--;
-		}
-	}
-}
-
-void recLB_co( void ) { recLoad32_co(8, 1); }
-void recLBU_co( void ) { recLoad32_co(8, 0); }
-void recLH_co( void ) { recLoad32_co(16, 1); }
-void recLHU_co( void ) { recLoad32_co(16, 0); }
-void recLW_co( void ) { recLoad32_co(32, 1); }
-void recLWU_co( void ) { recLoad32_co(32, 0); }
-void recLDL_co(void) { recLoad64(_Imm_-7, 0); }
-void recLDR_co(void) { recLoad64(_Imm_, 0); }
-void recLWL_co(void) { recLoad32(32, _Imm_-3, 1); }	// paired with LWR
-void recLWR_co(void) { recLoad32(32, _Imm_, 1); }	// paired with LWL
-
-void recLD_co( void )
-{
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		recLD();
-		g_pCurInstInfo++;
-		cpuRegs.code = *(u32*)PSM(pc);
-		recLD();
-		g_pCurInstInfo--; // incremented later
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-		int mmreg1 = -1, mmreg2 = -1, t0reg = -1, t1reg = -1;
-		int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-
-		if( _Rt_ ) _eeOnWriteReg(_Rt_, 0);
-		if( nextrt ) _eeOnWriteReg(nextrt, 0);
-
-		if( _Rt_ ) {
-			mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE);
-			if( mmreg1 < 0 ) {
-				mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ);
-				if( mmreg1 >= 0 ) mmreg1 |= 0x8000;
-			}
-
-			if( mmreg1 < 0 && _hasFreeMMXreg() ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE);
-		}
-
-		if( nextrt ) {
-			mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE);
-			if( mmreg2 < 0 ) {
-				mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE|MODE_READ);
-				if( mmreg2 >= 0 ) mmreg2 |= 0x8000;
-			}
-
-			if( mmreg2 < 0 && _hasFreeMMXreg() ) mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_WRITE);
-		}
-
-		if( mmreg1 < 0 || mmreg2 < 0 ) {
-			t0reg = _allocMMXreg(-1, MMX_TEMP, 0);
-
-			if( mmreg1 < 0 && mmreg2 < 0 && _hasFreeMMXreg() ) {
-				t1reg = _allocMMXreg(-1, MMX_TEMP, 0);
-			}
-			else t1reg = t0reg;
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 1, 0);
-
-		if( mmreg1 >= 0 ) {
-			if( mmreg1 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-			else MOVQRmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-		else {
-			if( _Rt_ ) {
-				MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-				MOVQRtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], t0reg);
-			}
-		}
-
-		if( mmreg2 >= 0 ) {
-			if( mmreg2 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			else MOVQRmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-		}
-		else {
-			if( nextrt ) {
-				MOVQRmtoROffset(t1reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				MOVQRtoM((int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ], t1reg);
-			}
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			if( mmreg1 >= 0 ) {
-				PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] );
-				CALLFunc( (int)recMemRead64 );
-
-				if( mmreg1 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]);
-				else MOVQMtoR(mmreg1, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]);
-			}
-			else {
-				if( _Rt_ ) {
-					_deleteEEreg(_Rt_, 0);
-					PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] );
-				}
-				else PUSH32I( (int)&retValues[0] );
-
-				CALLFunc( (int)recMemRead64 );
-			}
-
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-
-			if( mmreg2 >= 0 ) {
-				MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 );
-				ADD32ItoR(ECX, _Imm_co_-_Imm_);
-				CALLFunc( (int)recMemRead64 );
-
-				if( mmreg2 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]);
-				else MOVQMtoR(mmreg2, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]);
-			}
-			else {
-				if( nextrt ) {
-					_deleteEEreg(nextrt, 0);
-					MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 );
-				}
-				else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 );
-
-				ADD32ItoR(ECX, _Imm_co_-_Imm_);
-				CALLFunc( (int)recMemRead64 );
-			}
-
-			ADD32ItoR(ESP, 4);
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-
-		if( mmreg1 < 0 || mmreg2 < 0 || !(mmreg1&0x8000) || !(mmreg2&0x8000) ) SetMMXstate();
-
-		if( t0reg >= 0 ) _freeMMXreg(t0reg);
-		if( t0reg != t1reg && t1reg >= 0 ) _freeMMXreg(t1reg);
-
-		_clearNeededMMXregs();
-		_clearNeededXMMregs();
-	}
-}
-
-void recLD_coX( int num )
-{
-	int i;
-	int mmreg = -1;
-	int mmregs[XMMREGS];
-	int nextrts[XMMREGS];
-
-	assert( num > 1 && num < XMMREGS );
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		recLD();
-
-		for(i = 0; i < num; ++i) {
-			g_pCurInstInfo++;
-			cpuRegs.code = *(u32*)PSM(pc+i*4);
-			recLD();
-		}
-
-		g_pCurInstInfo -= num; // incremented later
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregS = _eePrepareReg_coX(_Rs_, num);
-
-		if( _Rt_ ) _eeOnWriteReg(_Rt_, 0);
-		for(i = 0; i < num; ++i) {
-			nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-			_eeOnWriteReg(nextrts[i], 0);
-		}
-
-		if( _Rt_ ) {
-			mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE);
-			if( mmreg < 0 ) {
-				mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ);
-				if( mmreg >= 0 ) mmreg |= MEM_XMMTAG;
-				else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG;
-			}
-			else mmreg |= MEM_MMXTAG;
-		}
-
-		for(i = 0; i < num; ++i) {
-			mmregs[i] = _allocCheckGPRtoMMX(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE);
-			if( mmregs[i] < 0 ) {
-				mmregs[i] = _allocCheckGPRtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE|MODE_READ);
-				if( mmregs[i] >= 0 ) mmregs[i] |= MEM_XMMTAG;
-				else mmregs[i] = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_WRITE)|MEM_MMXTAG;
-			}
-			else mmregs[i] |= MEM_MMXTAG;
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 1, 0);
-
-		if( mmreg >= 0 ) {
-			if( mmreg & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-			else MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-
-		for(i = 0; i < num; ++i) {
-			u32 off = PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_;
-
-			if( mmregs[i] >= 0 ) {
-				if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmregs[i]&0xf, ECX, off);
-				else MOVQRmtoROffset(mmregs[i]&0xf, ECX, off);
-			}
-		}
-
-		if( dohw ) {
-			if( (s_bCachingMem & 2) || num > 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			if( mmreg >= 0 ) {
-				PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] );
-				CALLFunc( (int)recMemRead64 );
-
-				if( mmreg & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]);
-				else MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]);
-			}
-			else {
-				PUSH32I( (int)&retValues[0] );
-				CALLFunc( (int)recMemRead64 );
-			}
-
-			for(i = 0; i < num; ++i ) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_);
-
-				if( mmregs[i] >= 0 ) {
-					MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0);
-					CALLFunc( (int)recMemRead64 );
-
-					if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]);
-					else MOVQMtoR(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]);
-				}
-				else {
-					MOV32ItoRmOffset(ESP, (int)&retValues[0], 0);
-					CALLFunc( (int)recMemRead64 );
-				}
-			}
-
-			ADD32ItoR(ESP, 4);
-
-			if( (s_bCachingMem & 2) || num > 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-
-		_clearNeededMMXregs();
-		_clearNeededXMMregs();
-	}
-}
-
-void recLQ_co( void )
-{
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		recLQ();
-		g_pCurInstInfo++;
-		cpuRegs.code = *(u32*)PSM(pc);
-		recLQ();
-		g_pCurInstInfo--; // incremented later
-	}
-	else
-#endif
-	{
-		int dohw;
-		int t0reg = -1;
-		int mmregs = _eePrepareReg(_Rs_);
-
-		int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-		int mmreg1 = -1, mmreg2 = -1;
-
-		if( _Rt_ ) {
-			_eeOnWriteReg(_Rt_, 0);
-
-			if( _hasFreeMMXreg() ) {
-				mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE);
-				if( mmreg1 >= 0 ) {
-					mmreg1 |= MEM_MMXTAG;
-					if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0);
-				}
-			}
-			else _deleteMMXreg(MMX_GPR+_Rt_, 2);
-
-			if( mmreg1 < 0 ) {
-				mmreg1 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE);
-				if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG;
-			}
-		}
-
-		if( nextrt ) {
-			_eeOnWriteReg(nextrt, 0);
-
-			if( _hasFreeMMXreg() ) {
-				mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE);
-				if( mmreg2 >= 0 ) {
-					mmreg2 |= MEM_MMXTAG;
-					if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0);
-				}
-			}
-			else _deleteMMXreg(MMX_GPR+nextrt, 2);
-
-			if( mmreg2 < 0 ) {
-				mmreg2 = _allocGPRtoXMMreg(-1, nextrt, MODE_WRITE);
-				if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG;
-			}
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0);
-
-		if( _Rt_ ) {
-			if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) {
-				MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8);
-				MOVQRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-				MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg);
-			}
-			else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) {
-				SSEX_MOVDQARmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-			}
-			else {
-				_recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset);
-			}
-		}
-
-		if( nextrt ) {
-			if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) {
-				MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8);
-				MOVQRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				MOVQRtoM((u32)&cpuRegs.GPR.r[nextrt].UL[2], t0reg);
-			}
-			else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) {
-				SSEX_MOVDQARmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			}
-			else {
-				_recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[nextrt].UL[0], PS2MEM_BASE_+s_nAddMemOffset);
-			}
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-			if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
-			else PUSH32I( (int)&retValues[0] );
-			CALLFunc( (int)recMemRead128 );
-
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			if( nextrt ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrt].UL[0], 0);
-			else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0);
-			ADD32ItoR(ECX, _Imm_co_-_Imm_);
-			CALLFunc( (int)recMemRead128 );
-
-			if( _Rt_) {
-				if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) MOVQMtoR(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]);
-				else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
-			}
-			if( nextrt ) {
-				if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) MOVQMtoR(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ]);
-				else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ] );
-			}
-			ADD32ItoR(ESP, 4);
-
-			if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]);
-			else x86SetJ8(j8Ptr[2]);
-		}
-
-		if( t0reg >= 0 ) _freeMMXreg(t0reg);
-	}
-}
-
-// coissues more than 2 LQs
-void recLQ_coX(int num)
-{
-	int i;
-	int mmreg = -1;
-	int mmregs[XMMREGS];
-	int nextrts[XMMREGS];
-
-	assert( num > 1 && num < XMMREGS );
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		recLQ();
-
-		for(i = 0; i < num; ++i) {
-			g_pCurInstInfo++;
-			cpuRegs.code = *(u32*)PSM(pc+i*4);
-			recLQ();
-		}
-
-		g_pCurInstInfo -= num; // incremented later
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregS = _eePrepareReg_coX(_Rs_, num);
-
-
-		if( _Rt_ ) _deleteMMXreg(MMX_GPR+_Rt_, 2);
-		for(i = 0; i < num; ++i) {
-			nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-			if( nextrts[i] ) _deleteMMXreg(MMX_GPR+nextrts[i], 2);
-		}
-
-		if( _Rt_ ) {
-			_eeOnWriteReg(_Rt_, 0);
-			mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE);
-		}
-
-		for(i = 0; i < num; ++i) {
-			if( nextrts[i] ) {
-				_eeOnWriteReg(nextrts[i], 0);
-				mmregs[i] = _allocGPRtoXMMreg(-1, nextrts[i], MODE_WRITE);
-			}
-			else mmregs[i] = -1;
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 2, 1);
-
-		if( _Rt_ ) SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-
-		for(i = 0; i < num; ++i) {
-			u32 off = s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_;
-			if( nextrts[i] ) SSEX_MOVDQARmtoROffset(mmregs[i], ECX, PS2MEM_BASE_+off&~0xf);
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
-			else PUSH32I( (int)&retValues[0] );
-			CALLFunc( (int)recMemRead128 );
-			if( _Rt_) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
-
-			for(i = 0; i < num; ++i) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_);
-
-				if( nextrts[i] ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0);
-				else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0);
-				CALLFunc( (int)recMemRead128 );		
-				if( nextrts[i] ) SSEX_MOVDQA_M128_to_XMM(mmregs[i], (int)&cpuRegs.GPR.r[ nextrts[i] ].UL[ 0 ] );
-			}
-
-			ADD32ItoR(ESP, 4);
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-	}
-}
-
-void recStore_co(int bit, int align)
-{
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		u32 addr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_;
-		u32 coaddr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_;
-		int mmreg, t0reg = -1, mmreg2;
-		int doclear = 0;
-
-		switch(bit) {
-			case 8:
-				if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16));
-				else {
-					_eeMoveGPRtoR(EAX, _Rt_);
-					doclear |= recMemConstWrite8(addr, EAX);
-				}
-				if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite8(coaddr, MEM_EECONSTTAG|(nextrt<<16));
-				else {
-					_eeMoveGPRtoR(EAX, nextrt);
-					doclear |= recMemConstWrite8(coaddr, EAX);
-				}
-				break;
-			case 16:
-				assert( (addr)%2 == 0 );
-				assert( (coaddr)%2 == 0 );
-
-				if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16));
-				else {
-					_eeMoveGPRtoR(EAX, _Rt_);
-					doclear |= recMemConstWrite16(addr, EAX);
-				}
-
-				if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite16(coaddr, MEM_EECONSTTAG|(nextrt<<16));
-				else {
-					_eeMoveGPRtoR(EAX, nextrt);
-					doclear |= recMemConstWrite16(coaddr, EAX);
-				}
-				break;
-			case 32:
-				assert( (addr)%4 == 0 );
-				if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16));
-				else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG,  _Rt_, MODE_READ)) >= 0 ) {
-					doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16));
-				}
-				else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) {
-					doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16));
-				}
-				else {
-					_eeMoveGPRtoR(EAX, _Rt_);
-					doclear = recMemConstWrite32(addr, EAX);
-				}
-
-				if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite32(coaddr, MEM_EECONSTTAG|(nextrt<<16));
-				else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) {
-					doclear |= recMemConstWrite32(coaddr, mmreg|MEM_XMMTAG|(nextrt<<16));
-				}
-				else if( (mmreg = _checkMMXreg(MMX_GPR+nextrt, MODE_READ)) >= 0 ) {
-					doclear |= recMemConstWrite32(coaddr, mmreg|MEM_MMXTAG|(nextrt<<16));
-				}
-				else {
-					_eeMoveGPRtoR(EAX, nextrt);
-					doclear |= recMemConstWrite32(coaddr, EAX);
-				}
-
-				break;
-			case 64:
-				{
-					int mask = align ? ~7 : ~0;
-					//assert( (addr)%8 == 0 );
-
-					if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16);
-					else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG,  _Rt_, MODE_READ)) >= 0 ) {
-						mmreg |= MEM_XMMTAG|(_Rt_<<16);
-					}
-					else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16);
-
-					if( GPR_IS_CONST1(nextrt) ) mmreg2 = MEM_EECONSTTAG|(nextrt<<16);
-					else if( (mmreg2 = _checkXMMreg(XMMTYPE_GPRREG,  nextrt, MODE_READ)) >= 0 ) {
-						mmreg2 |= MEM_XMMTAG|(nextrt<<16);
-					}
-					else mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_READ)|MEM_MMXTAG|(nextrt<<16);
-
-					doclear = recMemConstWrite64((addr)&mask, mmreg);
-					doclear |= recMemConstWrite64((coaddr)&mask, mmreg2);
-					doclear <<= 1;
-					break;
-				}
-			case 128:
-				assert( (addr)%16 == 0 );
-
-				mmreg = _eePrepConstWrite128(_Rt_);
-				mmreg2 = _eePrepConstWrite128(nextrt);
-				doclear = recMemConstWrite128((addr)&~15, mmreg);
-				doclear |= recMemConstWrite128((coaddr)&~15, mmreg2);
-				doclear <<= 2;
-				break;
-		}
-
-		if( doclear ) {
-			u8* ptr;
-			CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+(_Imm_ < _Imm_co_ ? _Imm_ : _Imm_co_));
-			ptr = JB8(0);
-			recMemConstClear((addr)&~(doclear*4-1), doclear);
-			recMemConstClear((coaddr)&~(doclear*4-1), doclear);
-			x86SetJ8A(ptr);
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-		int off = _Imm_co_-_Imm_;
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align ? bit/64 : 0, bit==128);
-
-		recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset);
-		recStore_raw(g_pCurInstInfo+1, bit, EBX, nextrt, s_nAddMemOffset+off);
-
-		// clear the writes, do only one camera (with the lowest addr)
-		if( off < 0 ) ADD32ItoR(ECX, s_nAddMemOffset+off);
-		else if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset);
-		CMP32MtoR(ECX, (u32)&maxrecmem);
-
-		if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0);
-		else j8Ptr[1] = JAE8(0);
-
-		MOV32RtoM((u32)&s_tempaddr, ECX);
-
-		if( bit < 32 ) AND8ItoR(ECX, 0xfc);
-		if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32);
-		else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64);
-		else CALLFunc((uptr)recWriteMemClear128);
-
-		MOV32MtoR(ECX, (u32)&s_tempaddr);
-		if( off < 0 ) ADD32ItoR(ECX, -off);
-		else ADD32ItoR(ECX, off);
-
-		if( bit < 32 ) AND8ItoR(ECX, 0xfc);
-		if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32);
-		else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64);
-		else CALLFunc((uptr)recWriteMemClear128);
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-			recStore_call(bit, _Rt_, s_nAddMemOffset);
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			recStore_call(bit, nextrt, s_nAddMemOffset+_Imm_co_-_Imm_);
-
-			if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]);
-			else x86SetJ8(j8Ptr[2]);
-		}
-
-		if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]);
-		else x86SetJ8(j8Ptr[1]);
-	}
-
-	_clearNeededMMXregs(); // needed since allocing
-	_clearNeededXMMregs(); // needed since allocing
-}
-
-void recSB_co( void ) { recStore_co(8, 1); }
-void recSH_co( void ) { recStore_co(16, 1); }
-void recSW_co( void ) { recStore_co(32, 1); }
-void recSD_co( void ) { recStore_co(64, 1); }
-void recSQ_co( void ) {	recStore_co(128, 1); }
-
-void recSWL_co(void) { recStore(32, _Imm_-3, 0); }
-void recSWR_co(void) { recStore(32, _Imm_, 0); }
-void recSDL_co(void) { recStore(64, _Imm_-7, 0); }
-void recSDR_co(void) { recStore(64, _Imm_, 0); }
-
-// coissues more than 2 SDs
-void recSD_coX(int num, int align) 
-{	
-	int i;
-	int mmreg = -1;
-	int nextrts[XMMREGS];
-	u32 mask = align ? ~7 : ~0;
-
-	assert( num > 1 && num < XMMREGS );
-
-	for(i = 0; i < num; ++i) {
-		nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-	}
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		int minimm = _Imm_;
-		int t0reg = -1;
-		int doclear = 0;
-
-		if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16);
-		else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG,  _Rt_, MODE_READ)) >= 0 ) {
-			mmreg |= MEM_XMMTAG|(_Rt_<<16);
-		}
-		else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16);
-		doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&mask, mmreg);
-
-		for(i = 0; i < num; ++i) {
-			int imm = (*(s16*)PSM(pc+i*4));
-			if( minimm > imm ) minimm = imm;
-
-			if( GPR_IS_CONST1(nextrts[i]) ) mmreg = MEM_EECONSTTAG|(nextrts[i]<<16);
-			else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG,  nextrts[i], MODE_READ)) >= 0 ) {
-				mmreg |= MEM_XMMTAG|(nextrts[i]<<16);
-			}
-			else mmreg = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_READ)|MEM_MMXTAG|(nextrts[i]<<16);
-			doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&mask, mmreg);
-		}
-
-		if( doclear ) {
-			u32* ptr;
-			CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm);
-			ptr = JB32(0);
-			recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~7, 4);
-
-			for(i = 0; i < num; ++i) {
-				recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~7, 2);
-			}
-			x86SetJ32A(ptr);
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg_coX(_Rs_, num);
-		int minoff = 0;
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align, 1);
-
-		recStore_raw(g_pCurInstInfo, 64, EAX, _Rt_, s_nAddMemOffset);
-
-		for(i = 0; i < num; ++i) {
-			recStore_raw(g_pCurInstInfo+i+1, 64, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-		}
-
-		// clear the writes
-		minoff = _Imm_;
-		for(i = 0; i < num; ++i) {
-			if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4));
-		}
-
-		if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_);
-		CMP32MtoR(ECX, (u32)&maxrecmem);
-		if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0);
-		else j8Ptr[1] = JAE8(0);
-
-		MOV32RtoM((u32)&s_tempaddr, ECX);
-		if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff);
-		CALLFunc((uptr)recWriteMemClear64);
-
-		for(i = 0; i < num; ++i) {
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff);
-			CALLFunc((uptr)recWriteMemClear64);
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-			recStore_call(64, _Rt_, s_nAddMemOffset);
-			for(i = 0; i < num; ++i) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				recStore_call(64, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]);
-			else x86SetJ8(j8Ptr[2]);
-		}
-
-		if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]);
-		else x86SetJ8(j8Ptr[1]);
-
-		_clearNeededMMXregs(); // needed since allocing
-		_clearNeededXMMregs(); // needed since allocing
-	}
-}
-
-// coissues more than 2 SQs
-void recSQ_coX(int num) 
-{	
-	int i;
-	int mmreg = -1;
-	int nextrts[XMMREGS];
-
-	assert( num > 1 && num < XMMREGS );
-
-	for(i = 0; i < num; ++i) {
-		nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-	}
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		int minimm = _Imm_;
-		int t0reg = -1;
-		int doclear = 0;
-
-		mmreg = _eePrepConstWrite128(_Rt_);
-		doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg);
-
-		for(i = 0; i < num; ++i) {
-			int imm = (*(s16*)PSM(pc+i*4));
-			if( minimm > imm ) minimm = imm;
-
-			mmreg = _eePrepConstWrite128(nextrts[i]);
-			doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+imm)&~15, mmreg);
-		}
-
-		if( doclear ) {
-			u32* ptr;
-			CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm);
-			ptr = JB32(0);
-			recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, 4);
-
-			for(i = 0; i < num; ++i) {
-				recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~15, 4);
-			}
-			x86SetJ32A(ptr);
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg_coX(_Rs_, num);
-		int minoff = 0;
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 1);
-
-		recStore_raw(g_pCurInstInfo, 128, EAX, _Rt_, s_nAddMemOffset);
-
-		for(i = 0; i < num; ++i) {
-			recStore_raw(g_pCurInstInfo+i+1, 128, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-		}
-
-		// clear the writes
-		minoff = _Imm_;
-		for(i = 0; i < num; ++i) {
-			if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4));
-		}
-
-		if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_);
-		CMP32MtoR(ECX, (u32)&maxrecmem);
-		if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0);
-		else j8Ptr[1] = JAE8(0);
-
-		MOV32RtoM((u32)&s_tempaddr, ECX);
-		if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff);
-		CALLFunc((uptr)recWriteMemClear128);
-
-		for(i = 0; i < num; ++i) {
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff);
-			CALLFunc((uptr)recWriteMemClear128);
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-			recStore_call(128, _Rt_, s_nAddMemOffset);
-			for(i = 0; i < num; ++i) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				recStore_call(128, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]);
-			else x86SetJ8(j8Ptr[2]);
-		}
-
-		if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]);
-		else x86SetJ8(j8Ptr[1]);
-
-		_clearNeededMMXregs(); // needed since allocing
-		_clearNeededXMMregs(); // needed since allocing
-	}
-}
-
-void recLWC1_co( void )
-{
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		u32 written = 0;
-		int ineax, mmreg1, mmreg2;
-
-		mmreg1 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE);
-		if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG;
-		else mmreg1 = EBX;
-
-		mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE);
-		if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG;
-		else mmreg2 = EAX;
-
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 );
-		if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) {
-			if( mmreg1&MEM_XMMTAG ) xmmregs[mmreg1&0xf].inuse = 0;
-			MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX );
-			written = 1;
-		}
-		ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_);
-
-		if( !written ) {
-			if( !(mmreg1&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX );
-		}
-
-		if( ineax || !(mmreg2 & MEM_XMMTAG) ) {
-			if( mmreg2&MEM_XMMTAG ) xmmregs[mmreg2&0xf].inuse = 0;
-			MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX );
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int regt, regtnext;
-		int mmregs = _eePrepareReg(_Rs_);
-
-		_deleteMMXreg(MMX_FPU+_Rt_, 2);
-		regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE);
-		regtnext = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE);
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0);
-
-		if( regt >= 0 ) {
-			SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-		else {
-			MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-			MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX );
-		}
-
-		if( regtnext >= 0 ) {
-			SSEX_MOVD_RmOffset_to_XMM(regtnext, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-		}
-		else {
-			MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX );
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			PUSH32R(ECX);
-			CALLFunc( (int)recMemRead32 );
-			POP32R(ECX);
-
-			if( regt >= 0 ) {
-				SSE2_MOVD_R_to_XMM(regt, EAX);
-			}
-			else {
-				MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX );
-			}
-
-			ADD32ItoR(ECX, _Imm_co_-_Imm_);
-			CALLFunc( (int)recMemRead32 );
-
-			if( regtnext >= 0 ) {
-				SSE2_MOVD_R_to_XMM(regtnext, EAX);
-			}
-			else {
-				MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX );
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-	}
-}
-
-void recLWC1_coX(int num)
-{
-	int i;
-	int mmreg = -1;
-	int mmregs[XMMREGS];
-	int nextrts[XMMREGS];
-
-	assert( num > 1 && num < XMMREGS );
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		int ineax;
-		u32 written = 0;
-		mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE);
-		if( mmreg >= 0 ) mmreg |= MEM_XMMTAG;
-		else mmreg = EAX;
-
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 );
-		if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) {
-			if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0;
-			MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX );
-			written = 1;
-		}
-		else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX );
-
-		// recompile two at a time
-		for(i = 0; i < num-1; i += 2) {
-			nextrts[0] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-			nextrts[1] = ((*(u32*)(PSM(pc+i*4+4)) >> 16) & 0x1F);
-
-			written = 0;
-			mmregs[0] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[0], MODE_WRITE);
-			if( mmregs[0] >= 0 ) mmregs[0] |= MEM_XMMTAG;
-			else mmregs[0] = EBX;
-
-			mmregs[1] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+2, nextrts[1], MODE_WRITE);
-			if( mmregs[1] >= 0 ) mmregs[1] |= MEM_XMMTAG;
-			else mmregs[1] = EAX;
-
-			assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 );
-			if( recMemConstRead32(mmregs[0], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) {
-				if( mmregs[0]&MEM_XMMTAG ) xmmregs[mmregs[0]&0xf].inuse = 0;
-				MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX );
-				written = 1;
-			}
-			ineax = recMemConstRead32(mmregs[1], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4+4)));
-
-			if( !written ) {
-				if( !(mmregs[0]&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX );
-			}
-
-			if( ineax || !(mmregs[1] & MEM_XMMTAG) ) {
-				if( mmregs[1]&MEM_XMMTAG ) xmmregs[mmregs[1]&0xf].inuse = 0;
-				MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[1] ].UL, EAX );
-			}
-		}
-
-		if( i < num ) {
-			// one left
-			int nextrt = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-
-			mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrt, MODE_WRITE);
-			if( mmreg >= 0 ) mmreg |= MEM_XMMTAG;
-			else mmreg = EAX;
-
-			assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 );
-			if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) {
-				if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0;
-				MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EBX );
-				written = 1;
-			}
-			else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX );
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregS = _eePrepareReg_coX(_Rs_, num);
-
-
-		_deleteMMXreg(MMX_FPU+_Rt_, 2);
-		for(i = 0; i < num; ++i) {
-			nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-			_deleteMMXreg(MMX_FPU+nextrts[i], 2);
-		}
-
-		mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE);
-
-		for(i = 0; i < num; ++i) {
-			mmregs[i] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE);
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1);
-
-		if( mmreg >= 0 ) {
-			SSEX_MOVD_RmOffset_to_XMM(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-		else {
-			MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-			MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX );
-		}
-
-		for(i = 0; i < num; ++i) {
-			if( mmregs[i] >= 0 ) {
-				SSEX_MOVD_RmOffset_to_XMM(mmregs[i], ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-			}
-			else {
-				MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-				MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX );
-			}
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-			CALLFunc( (int)recMemRead32 );
-
-			if( mmreg >= 0 ) SSE2_MOVD_R_to_XMM(mmreg, EAX);
-			else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX );
-
-			for(i = 0; i < num; ++i) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_);
-				CALLFunc( (int)recMemRead32 );
-
-				if( mmregs[i] >= 0 ) SSE2_MOVD_R_to_XMM(mmregs[i], EAX);
-				else MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX );
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-	}
-}
-
-void recSWC1_co( void )
-{
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		int mmreg;
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 );
-
-		mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ);
-		if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16);
-		else {
-			MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-			mmreg = EAX;
-		}
-		recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg);
-
-		mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ);
-		if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrt<<16);
-		else {
-			MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL);
-			mmreg = EAX;
-		}
-		recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, mmreg);
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-
-		int mmreg1, mmreg2;
-		assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 );
-		assert( _checkMMXreg(MMX_FPU+nextrt, MODE_READ) == -1 );
-
-		mmreg1 = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ);
-		mmreg2 = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ);
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0);
-
-		if(mmreg1 >= 0 ) {
-			if( mmreg2 >= 0 ) {
-				SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset);
-				SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			}
-			else {
-				MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL);
-				SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			}
-		}
-		else {
-			if( mmreg2 >= 0 ) {
-				MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-				SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset);
-			}
-			else {
-				MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-				MOV32MtoR(EDX, (int)&fpuRegs.fpr[ nextrt ].UL);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset);
-				MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-			}
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			// some type of hardware write
-			if( mmreg1 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg1);
-			else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-			CALLFunc( (int)recMemWrite32 );
-
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			ADD32ItoR(ECX, _Imm_co_-_Imm_);
-			if( mmreg2 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg2);
-			else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL);
-			CALLFunc( (int)recMemWrite32 );
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-	}
-}
-
-void recSWC1_coX(int num)
-{
-	int i;
-	int mmreg = -1;
-	int mmregs[XMMREGS];
-	int nextrts[XMMREGS];
-
-	assert( num > 1 && num < XMMREGS );
-
-	for(i = 0; i < num; ++i) {
-		nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F);
-	}
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 );
-
-		mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ);
-		if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16);
-		else {
-			MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-			mmreg = EAX;
-		}
-		recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg);
-
-		for(i = 0; i < num; ++i) {
-			mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ);
-			if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrts[i]<<16);
-			else {
-				MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL);
-				mmreg = EAX;
-			}
-			recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)), mmreg);
-		}
-	}
-	else
-#endif
-	{
-		int dohw;
-		int mmregS = _eePrepareReg_coX(_Rs_, num);
-
-		assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 );
-		mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ);
-
-		for(i = 0; i < num; ++i) {
-			assert( _checkMMXreg(MMX_FPU+nextrts[i], MODE_READ) == -1 );
-			mmregs[i] = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ);
-		}
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1);
-
-		if( mmreg >= 0) {
-			SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-		else {
-			MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-			MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-
-		for(i = 0; i < num; ++i) {
-			if( mmregs[i] >= 0) {
-				SSEX_MOVD_XMM_to_RmOffset(ECX, mmregs[i], PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-			}
-			else {
-				MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_);
-			}
-		}
-
-		if( dohw ) {
-			if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0);
-			else j8Ptr[2] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			// some type of hardware write
-			if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg);
-			else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL);
-			CALLFunc( (int)recMemWrite32 );
-
-			for(i = 0; i < num; ++i) {
-				MOV32MtoR(ECX, (u32)&s_tempaddr);
-				ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_);
-				if( mmregs[i] >= 0 && (xmmregs[mmregs[i]].mode&MODE_WRITE) ) SSE2_MOVD_XMM_to_R(EAX, mmregs[i]);
-				else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL);
-				CALLFunc( (int)recMemWrite32 );
-			}
-
-			if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]);
-			else x86SetJ8A(j8Ptr[2]);
-		}
-	}
-}
-
-void recLQC2_co( void ) 
-{
-	int mmreg1 = -1, mmreg2 = -1, t0reg = -1;
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-
-#ifdef REC_SLOWREAD
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 );
-
-		if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE);
-		else t0reg = _allocTempXMMreg(XMMT_FPS, -1);
-		recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1 >= 0 ? mmreg1 : t0reg);
-
-		if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE);
-		else if( t0reg < 0 ) t0reg = _allocTempXMMreg(XMMT_FPS, -1);
-		recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2 >= 0 ? mmreg2 : t0reg);
-
-		if( t0reg >= 0 ) _freeXMMreg(t0reg);
-	}
-	else
-#endif
-	{
-		u8* rawreadptr;
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-
-		if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE);
-		if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE);
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0);
-
-		rawreadptr = x86Ptr[0];
-		if( mmreg1 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset);
-		if( mmreg2 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-
-		if( dohw ) {
-			j8Ptr[1] = JMP8(0);
-			SET_HWLOC_R5900();
-
-			// check if writing to VUs
-			CMP32ItoR(ECX, 0x11000000);
-			JAE8(rawreadptr - (x86Ptr[0]+2));
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			if( _Ft_ ) PUSH32I( (int)&VU0.VF[_Ft_].UD[0] );
-			else PUSH32I( (int)&retValues[0] );
-			CALLFunc( (int)recMemRead128 );
-
-			if( mmreg1 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0] );
-
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			ADD32ItoR(ECX, _Imm_co_-_Imm_);
-
-			if( nextrt ) MOV32ItoRmOffset(ESP, (int)&VU0.VF[nextrt].UD[0], 0 );
-			else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 );
-			CALLFunc( (int)recMemRead128 );
-
-			if( mmreg2 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0] );
-
-			ADD32ItoR(ESP, 4);
-			x86SetJ8(j8Ptr[1]);
-		}
-	}
-
-	_clearNeededXMMregs(); // needed since allocing
-}
-
-void recSQC2_co( void ) 
-{
-	int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F);
-	int mmreg1, mmreg2;
-
-#ifdef REC_SLOWWRITE
-	_flushConstReg(_Rs_);
-#else
-	if( GPR_IS_CONST1( _Rs_ ) ) {
-		assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 );
-
-		mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG;
-		mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_READ)|MEM_XMMTAG;
-		recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1);
-		recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2);
-	}
-	else
-#endif
-	{
-		u8* rawreadptr;
-		int dohw;
-		int mmregs = _eePrepareReg(_Rs_);
-
-		mmreg1 = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ);
-		mmreg2 = _checkXMMreg(XMMTYPE_VFREG, nextrt, MODE_READ);
-
-		dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0);
-
-		rawreadptr = x86Ptr[0];
-
-		if( mmreg1 >= 0 ) {
-			SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset);
-		}
-		else {	
-			if( _hasFreeXMMreg() ) {
-				mmreg1 = _allocTempXMMreg(XMMT_FPS, -1);
-				SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0]);
-				SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset);
-				_freeXMMreg(mmreg1);
-			}
-			else if( _hasFreeMMXreg() ) {
-				mmreg1 = _allocMMXreg(-1, MMX_TEMP, 0);
-				MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UD[0]);
-				MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset);
-				MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UL[2]);
-				MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset+8);
-				SetMMXstate();
-				_freeMMXreg(mmreg1);
-			}
-			else {
-				MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]);
-				MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset);
-				MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4);
-				MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]);
-				MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8);
-				MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12);
-			}
-		}
-
-		if( mmreg2 >= 0 ) {
-			SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-		}
-		else {	
-			if( _hasFreeXMMreg() ) {
-				mmreg2 = _allocTempXMMreg(XMMT_FPS, -1);
-				SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0]);
-				SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				_freeXMMreg(mmreg2);
-			}
-			else if( _hasFreeMMXreg() ) {
-				mmreg2 = _allocMMXreg(-1, MMX_TEMP, 0);
-				MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UD[0]);
-				MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UL[2]);
-				MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8);
-				SetMMXstate();
-				_freeMMXreg(mmreg2);
-			}
-			else {
-				MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[0]);
-				MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[1]);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_);
-				MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+4);
-				MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[2]);
-				MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[3]);
-				MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8);
-				MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+12);
-			}
-		}
-
-		if( dohw ) {
-			j8Ptr[1] = JMP8(0);
-
-			SET_HWLOC_R5900();
-
-			// check if writing to VUs
-			CMP32ItoR(ECX, 0x11000000);
-			JAE8(rawreadptr - (x86Ptr[0]+2));
-
-			// some type of hardware write
-			if( mmreg1 >= 0) {
-				if( xmmregs[mmreg1].mode & MODE_WRITE ) {
-					SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg1);
-				}
-			}
-
-			MOV32RtoM((u32)&s_tempaddr, ECX);
-
-			MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]);
-			CALLFunc( (int)recMemWrite128 );
-
-			if( mmreg2 >= 0) {
-				if( xmmregs[mmreg2].mode & MODE_WRITE ) {
-					SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[nextrt].UD[0], mmreg2);
-				}
-			}
-
-			MOV32MtoR(ECX, (u32)&s_tempaddr);
-			ADD32ItoR(ECX, _Imm_co_-_Imm_);
-
-			MOV32ItoR(EAX, (int)&VU0.VF[nextrt].UD[0]);
-			CALLFunc( (int)recMemWrite128 );
-
-			x86SetJ8A(j8Ptr[1]);
-		}
-	}
-}
-
-#endif	// PCSX2_VM_COISSUE