+++ /dev/null
-$NetBSD: patch-source_core_NstMemory.hpp,v 1.2 2014/05/04 03:25:15 othyro Exp $
-
-Use SwapBank() instead of Source().
-
---- source/core/NstMemory.hpp.orig 2013-07-29 23:43:11.000000000 +0000
-+++ source/core/NstMemory.hpp
-@@ -1,775 +1,775 @@
--////////////////////////////////////////////////////////////////////////////////////////\r
--//\r
--// Nestopia - NES/Famicom emulator written in C++\r
--//\r
--// Copyright (C) 2003-2008 Martin Freij\r
--//\r
--// This file is part of Nestopia.\r
--//\r
--// Nestopia is free software; you can redistribute it and/or modify\r
--// it under the terms of the GNU General Public License as published by\r
--// the Free Software Foundation; either version 2 of the License, or\r
--// (at your option) any later version.\r
--//\r
--// Nestopia is distributed in the hope that it will be useful,\r
--// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
--// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
--// GNU General Public License for more details.\r
--//\r
--// You should have received a copy of the GNU General Public License\r
--// along with Nestopia; if not, write to the Free Software\r
--// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
--//\r
--////////////////////////////////////////////////////////////////////////////////////////\r
--\r
--#ifndef NST_MEMORY_H\r
--#define NST_MEMORY_H\r
--\r
--#include "NstRam.hpp"\r
--\r
--#ifdef NST_PRAGMA_ONCE\r
--#pragma once\r
--#endif\r
--\r
--namespace Nes\r
--{\r
-- namespace Core\r
-- {\r
-- template<typename T> class Pointer : public ImplicitBool< Pointer<T> >\r
-- {\r
-- Pointer(const Pointer&);\r
--\r
-- T* const ptr;\r
--\r
-- public:\r
--\r
-- explicit Pointer(T* t)\r
-- : ptr(t) {}\r
--\r
-- ~Pointer()\r
-- {\r
-- typedef char TypeComplete[sizeof(T)];\r
-- delete ptr;\r
-- }\r
--\r
-- T* operator -> () const\r
-- {\r
-- return ptr;\r
-- }\r
--\r
-- T& operator * () const\r
-- {\r
-- return *ptr;\r
-- }\r
--\r
-- bool operator ! () const\r
-- {\r
-- return !ptr;\r
-- }\r
-- };\r
--\r
-- namespace State\r
-- {\r
-- class Saver;\r
-- class Loader;\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V>\r
-- class Memory;\r
--\r
-- template<>\r
-- class Memory<0,0,0>\r
-- {\r
-- protected:\r
--\r
-- enum\r
-- {\r
-- MAX_SOURCES = 2\r
-- };\r
--\r
-- void SaveState\r
-- (\r
-- State::Saver&,\r
-- dword,\r
-- const Ram* NST_RESTRICT,\r
-- uint,\r
-- const byte* NST_RESTRICT,\r
-- uint\r
-- ) const;\r
--\r
-- bool LoadState\r
-- (\r
-- State::Loader&,\r
-- Ram* NST_RESTRICT,\r
-- uint,\r
-- byte* NST_RESTRICT,\r
-- uint\r
-- ) const;\r
--\r
-- template<uint N> struct Pages\r
-- {\r
-- byte* mem[N];\r
-- byte ref[N];\r
-- };\r
--\r
-- template<uint OFFSET,uint COUNT,uint SIZE,uint I=COUNT>\r
-- struct Unroller\r
-- {\r
-- template<typename Pages>\r
-- static NST_FORCE_INLINE void SwapBank\r
-- (\r
-- Pages* const NST_RESTRICT pages,\r
-- byte* const NST_RESTRICT mem,\r
-- const dword mask,\r
-- const dword bank,\r
-- const uint offset=0,\r
-- const uint source=0\r
-- )\r
-- {\r
-- pages->mem[OFFSET+COUNT-I+offset] = mem + (bank & mask);\r
-- pages->ref[OFFSET+COUNT-I+offset] = source;\r
--\r
-- Unroller<OFFSET,COUNT,SIZE,I-1>::SwapBank( pages, mem, mask, bank + SIZE, offset, source );\r
-- }\r
--\r
-- template<typename Pages>\r
-- static NST_FORCE_INLINE void SwapBanks\r
-- (\r
-- Pages* const NST_RESTRICT pages,\r
-- byte* const NST_RESTRICT mem,\r
-- const dword mask,\r
-- const dword bank0,\r
-- const dword bank1,\r
-- const uint offset=0\r
-- )\r
-- {\r
-- Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );\r
-- Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );\r
-- }\r
--\r
-- template<typename Pages>\r
-- static NST_FORCE_INLINE void SwapBanks\r
-- (\r
-- Pages* const NST_RESTRICT pages,\r
-- byte* const NST_RESTRICT mem,\r
-- const dword mask,\r
-- const dword bank0,\r
-- const dword bank1,\r
-- const dword bank2,\r
-- const dword bank3,\r
-- const uint offset=0\r
-- )\r
-- {\r
-- Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );\r
-- Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );\r
-- Unroller<OFFSET+COUNT*2,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank2, offset );\r
-- Unroller<OFFSET+COUNT*3,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank3, offset );\r
-- }\r
--\r
-- template<typename Pages>\r
-- static NST_FORCE_INLINE void SwapBanks\r
-- (\r
-- Pages* const NST_RESTRICT pages,\r
-- byte* const NST_RESTRICT mem,\r
-- const dword mask,\r
-- const dword bank0,\r
-- const dword bank1,\r
-- const dword bank2,\r
-- const dword bank3,\r
-- const dword bank4,\r
-- const dword bank5,\r
-- const dword bank6,\r
-- const dword bank7,\r
-- const uint offset=0\r
-- )\r
-- {\r
-- Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );\r
-- Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );\r
-- Unroller<OFFSET+COUNT*2,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank2, offset );\r
-- Unroller<OFFSET+COUNT*3,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank3, offset );\r
-- Unroller<OFFSET+COUNT*4,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank4, offset );\r
-- Unroller<OFFSET+COUNT*5,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank5, offset );\r
-- Unroller<OFFSET+COUNT*6,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank6, offset );\r
-- Unroller<OFFSET+COUNT*7,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank7, offset );\r
-- }\r
-- };\r
-- };\r
--\r
-- template<>\r
-- struct Memory<0,0,0>::Pages<1>\r
-- {\r
-- byte* mem[1];\r
-- dword ref[1];\r
-- };\r
--\r
-- template<>\r
-- struct Memory<0,0,0>::Pages<2>\r
-- {\r
-- byte* mem[2];\r
-- word ref[2];\r
-- };\r
--\r
-- template<uint OFFSET,uint COUNT,uint SIZE>\r
-- struct Memory<0,0,0>::Unroller<OFFSET,COUNT,SIZE,0U>\r
-- {\r
-- template<typename Pages>\r
-- static NST_FORCE_INLINE void SwapBank(Pages*,byte*,dword,dword,uint,uint) {}\r
-- };\r
--\r
-- template<dword SPACE,uint U,uint V=1>\r
-- class Memory : Memory<0,0,0>\r
-- {\r
-- public:\r
--\r
-- enum\r
-- {\r
-- NUM_SOURCES = V\r
-- };\r
--\r
-- private:\r
--\r
-- NST_COMPILE_ASSERT\r
-- (\r
-- ((SPACE & (SPACE-1)) == 0) &&\r
-- ((U & (U-1)) == 0) &&\r
-- (SPACE % U == 0) &&\r
-- (V >= 1 && V <= MAX_SOURCES)\r
-- );\r
--\r
-- enum\r
-- {\r
-- MEM_PAGE_SIZE = U,\r
-- MEM_PAGE_SHIFT = ValueBits<MEM_PAGE_SIZE>::VALUE-1,\r
-- MEM_PAGE_MASK = MEM_PAGE_SIZE - 1,\r
-- MEM_NUM_PAGES = SPACE / U\r
-- };\r
--\r
-- typedef Memory<0,0,0>::Pages<MEM_NUM_PAGES> Pages;\r
--\r
-- Pages pages;\r
-- Ram sources[NUM_SOURCES];\r
--\r
-- public:\r
--\r
-- bool Readable(uint page) const\r
-- {\r
-- return sources[pages.ref[page]].Readable();\r
-- }\r
--\r
-- bool Writable(uint page) const\r
-- {\r
-- return sources[pages.ref[page]].Writable();\r
-- }\r
--\r
-- const byte& Peek(uint address) const\r
-- {\r
-- return pages.mem[address >> MEM_PAGE_SHIFT][address & MEM_PAGE_MASK];\r
-- }\r
--\r
-- byte* operator [] (uint page)\r
-- {\r
-- return pages.mem[page];\r
-- }\r
--\r
-- const byte* operator [] (uint page) const\r
-- {\r
-- return pages.mem[page];\r
-- }\r
--\r
-- void Poke(uint address,uint data)\r
-- {\r
-- const uint page = address >> MEM_PAGE_SHIFT;\r
-- NST_VERIFY( Writable( page ) );\r
--\r
-- if (Writable( page ))\r
-- pages.mem[page][address & MEM_PAGE_MASK] = data;\r
-- }\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- void SwapBank(dword);\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- void SwapBanks(dword,dword);\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- void SwapBanks(dword,dword,dword,dword);\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- void SwapBanks(dword,dword,dword,dword,dword,dword,dword,dword);\r
--\r
-- template<uint SIZE>\r
-- void SwapBank(uint,dword);\r
--\r
-- template<uint SIZE>\r
-- void SwapBanks(uint,dword,dword);\r
--\r
-- template<uint SIZE>\r
-- void SwapBanks(uint,dword,dword,dword,dword);\r
--\r
-- template<uint SIZE>\r
-- void SwapBanks(uint,dword,dword,dword,dword,dword,dword,dword,dword);\r
--\r
-- template<uint SIZE,uint A,uint B>\r
-- void SwapPages();\r
--\r
-- void SaveState(State::Saver&,dword) const;\r
-- void LoadState(State::Loader&);\r
--\r
-- class SourceProxy\r
-- {\r
-- typedef Memory<SPACE,U,V> Ref;\r
--\r
-- const uint source;\r
-- Ref& ref;\r
--\r
-- public:\r
--\r
-- SourceProxy(uint s,Ref& r)\r
-- : source(s), ref(r)\r
-- {\r
-- NST_ASSERT( s < NUM_SOURCES );\r
-- }\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- void SwapBank(dword) const;\r
--\r
-- template<uint SIZE>\r
-- void SwapBank(uint,dword) const;\r
--\r
-- void ReadEnable(bool read) const\r
-- {\r
-- ref.sources[source].ReadEnable( read );\r
-- }\r
--\r
-- void WriteEnable(bool write) const\r
-- {\r
-- ref.sources[source].WriteEnable( write );\r
-- }\r
--\r
-- void SetSecurity(bool read,bool write) const\r
-- {\r
-- ref.sources[source].SetSecurity( read, write );\r
-- }\r
--\r
-- bool Readable() const\r
-- {\r
-- return ref.sources[source].Readable();\r
-- }\r
--\r
-- bool Writable() const\r
-- {\r
-- return ref.sources[source].Writable();\r
-- }\r
--\r
-- Ram::Type GetType() const\r
-- {\r
-- return ref.sources[source].GetType();\r
-- }\r
--\r
-- void Set(Ram::Type type,bool read,bool write,dword size,byte* mem) const\r
-- {\r
-- ref.sources[source].Set( type, read, write, size, mem );\r
-- }\r
--\r
-- void Set(Ram::Type type,bool read,bool write,dword size) const\r
-- {\r
-- ref.sources[source].Set( type, read, write, size );\r
-- }\r
--\r
-- void Set(const Ram& ram) const\r
-- {\r
-- ref.sources[source] = ram;\r
-- }\r
--\r
-- void Fill(uint value) const\r
-- {\r
-- ref.sources[source].Fill( value );\r
-- }\r
--\r
-- byte* Mem(dword offset=0) const\r
-- {\r
-- return ref.sources[source].Mem(offset);\r
-- }\r
--\r
-- byte& operator [] (dword i) const\r
-- {\r
-- return ref.sources[source][i];\r
-- }\r
--\r
-- dword Size() const\r
-- {\r
-- return ref.sources[source].Size();\r
-- }\r
--\r
-- dword Masking() const\r
-- {\r
-- return ref.sources[source].Masking();\r
-- }\r
--\r
-- bool Empty() const\r
-- {\r
-- return ref.sources[source].Size() == 0;\r
-- }\r
--\r
-- const Ram& Reference() const\r
-- {\r
-- return ref.sources[source];\r
-- }\r
-- };\r
--\r
-- public:\r
--\r
-- const SourceProxy Source(uint i=0)\r
-- {\r
-- NST_ASSERT( i < NUM_SOURCES );\r
-- return SourceProxy( i, *this );\r
-- }\r
--\r
-- const Ram& Source(uint i=0) const\r
-- {\r
-- NST_ASSERT( i < NUM_SOURCES );\r
-- return sources[i];\r
-- }\r
--\r
-- Memory()\r
-- {\r
-- }\r
--\r
-- Memory(byte* mem,dword size,bool read,bool write)\r
-- {\r
-- Source().Set( mem, size, read, write );\r
-- }\r
--\r
-- Memory(dword size,bool read,bool write)\r
-- {\r
-- Source().Set( size, read, write );\r
-- }\r
--\r
-- template<uint SIZE,uint ADDRESS>\r
-- dword GetBank() const\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) && (SPACE >= ADDRESS + SIZE) );\r
--\r
-- enum {MEM_PAGE = ADDRESS >> MEM_PAGE_SHIFT};\r
-- return dword(pages.mem[MEM_PAGE] - sources[pages.ref[MEM_PAGE]].Mem()) >> (ValueBits<SIZE>::VALUE-1);\r
-- }\r
--\r
-- template<uint SIZE>\r
-- dword GetBank(uint address) const\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE );\r
--\r
-- address >>= MEM_PAGE_SHIFT;\r
-- return dword(pages.mem[address] - sources[pages.ref[address]].Mem()) >> (ValueBits<SIZE>::VALUE-1);\r
-- }\r
-- };\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>\r
-- void Memory<SPACE,U,V>::SwapBank(dword bank)\r
-- {\r
-- NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank << MEM_OFFSET\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE>\r
-- void Memory<SPACE,U,V>::SwapBank(uint address,dword bank)\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank << MEM_OFFSET,\r
-- address >> MEM_PAGE_SHIFT\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>\r
-- void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1)\r
-- {\r
-- NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 2) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>\r
-- void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3)\r
-- {\r
-- NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET,\r
-- bank2 << MEM_OFFSET,\r
-- bank3 << MEM_OFFSET\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>\r
-- void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7)\r
-- {\r
-- NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET,\r
-- bank2 << MEM_OFFSET,\r
-- bank3 << MEM_OFFSET,\r
-- bank4 << MEM_OFFSET,\r
-- bank5 << MEM_OFFSET,\r
-- bank6 << MEM_OFFSET,\r
-- bank7 << MEM_OFFSET\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE>\r
-- void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1)\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE * 2 );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET,\r
-- address >> MEM_PAGE_SHIFT\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE>\r
-- void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3)\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE * 4 );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET,\r
-- bank2 << MEM_OFFSET,\r
-- bank3 << MEM_OFFSET,\r
-- address >> MEM_PAGE_SHIFT\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE>\r
-- void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7)\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE * 4 );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks\r
-- (\r
-- &pages,\r
-- sources[0].Mem(),\r
-- sources[0].Masking(),\r
-- bank0 << MEM_OFFSET,\r
-- bank1 << MEM_OFFSET,\r
-- bank2 << MEM_OFFSET,\r
-- bank3 << MEM_OFFSET,\r
-- bank4 << MEM_OFFSET,\r
-- bank5 << MEM_OFFSET,\r
-- bank6 << MEM_OFFSET,\r
-- bank7 << MEM_OFFSET,\r
-- address >> MEM_PAGE_SHIFT\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>\r
-- void Memory<SPACE,U,V>::SourceProxy::SwapBank(dword bank) const\r
-- {\r
-- NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank\r
-- (\r
-- &ref.pages,\r
-- ref.sources[source].Mem(),\r
-- ref.sources[source].Masking(),\r
-- bank << MEM_OFFSET,\r
-- 0,\r
-- source\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE>\r
-- void Memory<SPACE,U,V>::SourceProxy::SwapBank(uint address,dword bank) const\r
-- {\r
-- NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );\r
-- NST_ASSERT( SPACE >= address + SIZE );\r
--\r
-- enum\r
-- {\r
-- MEM_OFFSET = ValueBits<SIZE>::VALUE-1,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank\r
-- (\r
-- &ref.pages,\r
-- ref.sources[source].Mem(),\r
-- ref.sources[source].Masking(),\r
-- bank << MEM_OFFSET,\r
-- address >> MEM_PAGE_SHIFT,\r
-- source\r
-- );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V> template<uint SIZE,uint A,uint B>\r
-- void Memory<SPACE,U,V>::SwapPages()\r
-- {\r
-- NST_COMPILE_ASSERT\r
-- (\r
-- (A != B) &&\r
-- (SPACE >= A + SIZE) &&\r
-- (SPACE >= B + SIZE) &&\r
-- (SIZE && (SIZE % MEM_PAGE_SIZE) == 0)\r
-- );\r
--\r
-- enum\r
-- {\r
-- MEM_A_BEGIN = A / MEM_PAGE_SIZE,\r
-- MEM_B_BEGIN = B / MEM_PAGE_SIZE,\r
-- MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE\r
-- };\r
--\r
-- for (uint i=0; i < MEM_PAGE_COUNT; ++i)\r
-- {\r
-- byte* const mem = pages.mem[MEM_A_BEGIN+i];\r
-- const byte ref = pages.ref[MEM_A_BEGIN+i];\r
--\r
-- pages.mem[MEM_A_BEGIN+i] = pages.mem[MEM_B_BEGIN+i];\r
-- pages.ref[MEM_A_BEGIN+i] = pages.ref[MEM_B_BEGIN+i];\r
--\r
-- pages.mem[MEM_B_BEGIN+i] = mem;\r
-- pages.ref[MEM_B_BEGIN+i] = ref;\r
-- }\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V>\r
-- void Memory<SPACE,U,V>::SaveState(State::Saver& state,const dword baseChunk) const\r
-- {\r
-- byte pageData[MEM_NUM_PAGES*3];\r
--\r
-- for (uint i=0; i < MEM_NUM_PAGES; ++i)\r
-- {\r
-- const uint bank = GetBank<MEM_PAGE_SIZE>( i * MEM_PAGE_SIZE );\r
--\r
-- pageData[i*3+0] = pages.ref[i];\r
-- pageData[i*3+1] = bank & 0xFF;\r
-- pageData[i*3+2] = bank >> 8;\r
-- }\r
--\r
-- Memory<0,0,0>::SaveState( state, baseChunk, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES );\r
-- }\r
--\r
-- template<dword SPACE,uint U,uint V>\r
-- void Memory<SPACE,U,V>::LoadState(State::Loader& state)\r
-- {\r
-- byte pageData[MEM_NUM_PAGES*3];\r
--\r
-- if (Memory<0,0,0>::LoadState( state, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES ))\r
-- {\r
-- for (uint i=0; i < MEM_NUM_PAGES; ++i)\r
-- {\r
-- if (pageData[i*3+0] < NUM_SOURCES)\r
-- Source( pageData[i*3+0] ).template SwapBank<MEM_PAGE_SIZE>( i * MEM_PAGE_SIZE, pageData[i*3+1] | uint(pageData[i*3+2]) << 8 );\r
-- else\r
-- throw RESULT_ERR_CORRUPT_FILE;\r
-- }\r
-- }\r
-- }\r
-- }\r
--}\r
--\r
--#endif\r
-+////////////////////////////////////////////////////////////////////////////////////////
-+//
-+// Nestopia - NES/Famicom emulator written in C++
-+//
-+// Copyright (C) 2003-2008 Martin Freij
-+//
-+// This file is part of Nestopia.
-+//
-+// Nestopia 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.
-+//
-+// Nestopia 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 Nestopia; if not, write to the Free Software
-+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+//
-+////////////////////////////////////////////////////////////////////////////////////////
-+
-+#ifndef NST_MEMORY_H
-+#define NST_MEMORY_H
-+
-+#include "NstRam.hpp"
-+
-+#ifdef NST_PRAGMA_ONCE
-+#pragma once
-+#endif
-+
-+namespace Nes
-+{
-+ namespace Core
-+ {
-+ template<typename T> class Pointer : public ImplicitBool< Pointer<T> >
-+ {
-+ Pointer(const Pointer&);
-+
-+ T* const ptr;
-+
-+ public:
-+
-+ explicit Pointer(T* t)
-+ : ptr(t) {}
-+
-+ ~Pointer()
-+ {
-+ typedef char TypeComplete[sizeof(T)];
-+ delete ptr;
-+ }
-+
-+ T* operator -> () const
-+ {
-+ return ptr;
-+ }
-+
-+ T& operator * () const
-+ {
-+ return *ptr;
-+ }
-+
-+ bool operator ! () const
-+ {
-+ return !ptr;
-+ }
-+ };
-+
-+ namespace State
-+ {
-+ class Saver;
-+ class Loader;
-+ }
-+
-+ template<dword SPACE,uint U,uint V>
-+ class Memory;
-+
-+ template<>
-+ class Memory<0,0,0>
-+ {
-+ protected:
-+
-+ enum
-+ {
-+ MAX_SOURCES = 2
-+ };
-+
-+ void SaveState
-+ (
-+ State::Saver&,
-+ dword,
-+ const Ram* NST_RESTRICT,
-+ uint,
-+ const byte* NST_RESTRICT,
-+ uint
-+ ) const;
-+
-+ bool LoadState
-+ (
-+ State::Loader&,
-+ Ram* NST_RESTRICT,
-+ uint,
-+ byte* NST_RESTRICT,
-+ uint
-+ ) const;
-+
-+ template<uint N> struct Pages
-+ {
-+ byte* mem[N];
-+ byte ref[N];
-+ };
-+
-+ template<uint OFFSET,uint COUNT,uint SIZE,uint I=COUNT>
-+ struct Unroller
-+ {
-+ template<typename Pages>
-+ static NST_FORCE_INLINE void SwapBank
-+ (
-+ Pages* const NST_RESTRICT pages,
-+ byte* const NST_RESTRICT mem,
-+ const dword mask,
-+ const dword bank,
-+ const uint offset=0,
-+ const uint source=0
-+ )
-+ {
-+ pages->mem[OFFSET+COUNT-I+offset] = mem + (bank & mask);
-+ pages->ref[OFFSET+COUNT-I+offset] = source;
-+
-+ Unroller<OFFSET,COUNT,SIZE,I-1>::SwapBank( pages, mem, mask, bank + SIZE, offset, source );
-+ }
-+
-+ template<typename Pages>
-+ static NST_FORCE_INLINE void SwapBanks
-+ (
-+ Pages* const NST_RESTRICT pages,
-+ byte* const NST_RESTRICT mem,
-+ const dword mask,
-+ const dword bank0,
-+ const dword bank1,
-+ const uint offset=0
-+ )
-+ {
-+ Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );
-+ Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );
-+ }
-+
-+ template<typename Pages>
-+ static NST_FORCE_INLINE void SwapBanks
-+ (
-+ Pages* const NST_RESTRICT pages,
-+ byte* const NST_RESTRICT mem,
-+ const dword mask,
-+ const dword bank0,
-+ const dword bank1,
-+ const dword bank2,
-+ const dword bank3,
-+ const uint offset=0
-+ )
-+ {
-+ Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );
-+ Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );
-+ Unroller<OFFSET+COUNT*2,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank2, offset );
-+ Unroller<OFFSET+COUNT*3,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank3, offset );
-+ }
-+
-+ template<typename Pages>
-+ static NST_FORCE_INLINE void SwapBanks
-+ (
-+ Pages* const NST_RESTRICT pages,
-+ byte* const NST_RESTRICT mem,
-+ const dword mask,
-+ const dword bank0,
-+ const dword bank1,
-+ const dword bank2,
-+ const dword bank3,
-+ const dword bank4,
-+ const dword bank5,
-+ const dword bank6,
-+ const dword bank7,
-+ const uint offset=0
-+ )
-+ {
-+ Unroller<OFFSET+COUNT*0,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank0, offset );
-+ Unroller<OFFSET+COUNT*1,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank1, offset );
-+ Unroller<OFFSET+COUNT*2,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank2, offset );
-+ Unroller<OFFSET+COUNT*3,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank3, offset );
-+ Unroller<OFFSET+COUNT*4,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank4, offset );
-+ Unroller<OFFSET+COUNT*5,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank5, offset );
-+ Unroller<OFFSET+COUNT*6,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank6, offset );
-+ Unroller<OFFSET+COUNT*7,COUNT,SIZE,I>::SwapBank( pages, mem, mask, bank7, offset );
-+ }
-+ };
-+ };
-+
-+ template<>
-+ struct Memory<0,0,0>::Pages<1>
-+ {
-+ byte* mem[1];
-+ dword ref[1];
-+ };
-+
-+ template<>
-+ struct Memory<0,0,0>::Pages<2>
-+ {
-+ byte* mem[2];
-+ word ref[2];
-+ };
-+
-+ template<uint OFFSET,uint COUNT,uint SIZE>
-+ struct Memory<0,0,0>::Unroller<OFFSET,COUNT,SIZE,0U>
-+ {
-+ template<typename Pages>
-+ static NST_FORCE_INLINE void SwapBank(Pages*,byte*,dword,dword,uint,uint) {}
-+ };
-+
-+ template<dword SPACE,uint U,uint V=1>
-+ class Memory : Memory<0,0,0>
-+ {
-+ public:
-+
-+ enum
-+ {
-+ NUM_SOURCES = V
-+ };
-+
-+ private:
-+
-+ NST_COMPILE_ASSERT
-+ (
-+ ((SPACE & (SPACE-1)) == 0) &&
-+ ((U & (U-1)) == 0) &&
-+ (SPACE % U == 0) &&
-+ (V >= 1 && V <= MAX_SOURCES)
-+ );
-+
-+ enum
-+ {
-+ MEM_PAGE_SIZE = U,
-+ MEM_PAGE_SHIFT = ValueBits<MEM_PAGE_SIZE>::VALUE-1,
-+ MEM_PAGE_MASK = MEM_PAGE_SIZE - 1,
-+ MEM_NUM_PAGES = SPACE / U
-+ };
-+
-+ typedef Memory<0,0,0>::Pages<MEM_NUM_PAGES> Pages;
-+
-+ Pages pages;
-+ Ram sources[NUM_SOURCES];
-+
-+ public:
-+
-+ bool Readable(uint page) const
-+ {
-+ return sources[pages.ref[page]].Readable();
-+ }
-+
-+ bool Writable(uint page) const
-+ {
-+ return sources[pages.ref[page]].Writable();
-+ }
-+
-+ const byte& Peek(uint address) const
-+ {
-+ return pages.mem[address >> MEM_PAGE_SHIFT][address & MEM_PAGE_MASK];
-+ }
-+
-+ byte* operator [] (uint page)
-+ {
-+ return pages.mem[page];
-+ }
-+
-+ const byte* operator [] (uint page) const
-+ {
-+ return pages.mem[page];
-+ }
-+
-+ void Poke(uint address,uint data)
-+ {
-+ const uint page = address >> MEM_PAGE_SHIFT;
-+ NST_VERIFY( Writable( page ) );
-+
-+ if (Writable( page ))
-+ pages.mem[page][address & MEM_PAGE_MASK] = data;
-+ }
-+
-+ template<uint SIZE,uint ADDRESS>
-+ void SwapBank(dword);
-+
-+ template<uint SIZE,uint ADDRESS>
-+ void SwapBanks(dword,dword);
-+
-+ template<uint SIZE,uint ADDRESS>
-+ void SwapBanks(dword,dword,dword,dword);
-+
-+ template<uint SIZE,uint ADDRESS>
-+ void SwapBanks(dword,dword,dword,dword,dword,dword,dword,dword);
-+
-+ template<uint SIZE>
-+ void SwapBank(uint,dword);
-+
-+ template<uint SIZE>
-+ void SwapBanks(uint,dword,dword);
-+
-+ template<uint SIZE>
-+ void SwapBanks(uint,dword,dword,dword,dword);
-+
-+ template<uint SIZE>
-+ void SwapBanks(uint,dword,dword,dword,dword,dword,dword,dword,dword);
-+
-+ template<uint SIZE,uint A,uint B>
-+ void SwapPages();
-+
-+ void SaveState(State::Saver&,dword) const;
-+ void LoadState(State::Loader&);
-+
-+ class SourceProxy
-+ {
-+ typedef Memory<SPACE,U,V> Ref;
-+
-+ const uint source;
-+ Ref& ref;
-+
-+ public:
-+
-+ SourceProxy(uint s,Ref& r)
-+ : source(s), ref(r)
-+ {
-+ NST_ASSERT( s < NUM_SOURCES );
-+ }
-+
-+ template<uint SIZE,uint ADDRESS>
-+ void SwapBank(dword) const;
-+
-+ template<uint SIZE>
-+ void SwapBank(uint,dword) const;
-+
-+ void ReadEnable(bool read) const
-+ {
-+ ref.sources[source].ReadEnable( read );
-+ }
-+
-+ void WriteEnable(bool write) const
-+ {
-+ ref.sources[source].WriteEnable( write );
-+ }
-+
-+ void SetSecurity(bool read,bool write) const
-+ {
-+ ref.sources[source].SetSecurity( read, write );
-+ }
-+
-+ bool Readable() const
-+ {
-+ return ref.sources[source].Readable();
-+ }
-+
-+ bool Writable() const
-+ {
-+ return ref.sources[source].Writable();
-+ }
-+
-+ Ram::Type GetType() const
-+ {
-+ return ref.sources[source].GetType();
-+ }
-+
-+ void Set(Ram::Type type,bool read,bool write,dword size,byte* mem) const
-+ {
-+ ref.sources[source].Set( type, read, write, size, mem );
-+ }
-+
-+ void Set(Ram::Type type,bool read,bool write,dword size) const
-+ {
-+ ref.sources[source].Set( type, read, write, size );
-+ }
-+
-+ void Set(const Ram& ram) const
-+ {
-+ ref.sources[source] = ram;
-+ }
-+
-+ void Fill(uint value) const
-+ {
-+ ref.sources[source].Fill( value );
-+ }
-+
-+ byte* Mem(dword offset=0) const
-+ {
-+ return ref.sources[source].Mem(offset);
-+ }
-+
-+ byte& operator [] (dword i) const
-+ {
-+ return ref.sources[source][i];
-+ }
-+
-+ dword Size() const
-+ {
-+ return ref.sources[source].Size();
-+ }
-+
-+ dword Masking() const
-+ {
-+ return ref.sources[source].Masking();
-+ }
-+
-+ bool Empty() const
-+ {
-+ return ref.sources[source].Size() == 0;
-+ }
-+
-+ const Ram& Reference() const
-+ {
-+ return ref.sources[source];
-+ }
-+ };
-+
-+ public:
-+
-+ const SourceProxy Source(uint i=0)
-+ {
-+ NST_ASSERT( i < NUM_SOURCES );
-+ return SourceProxy( i, *this );
-+ }
-+
-+ const Ram& Source(uint i=0) const
-+ {
-+ NST_ASSERT( i < NUM_SOURCES );
-+ return sources[i];
-+ }
-+
-+ Memory()
-+ {
-+ }
-+
-+ Memory(byte* mem,dword size,bool read,bool write)
-+ {
-+ Source().Set( mem, size, read, write );
-+ }
-+
-+ Memory(dword size,bool read,bool write)
-+ {
-+ Source().Set( size, read, write );
-+ }
-+
-+ template<uint SIZE,uint ADDRESS>
-+ dword GetBank() const
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) && (SPACE >= ADDRESS + SIZE) );
-+
-+ enum {MEM_PAGE = ADDRESS >> MEM_PAGE_SHIFT};
-+ return dword(pages.mem[MEM_PAGE] - sources[pages.ref[MEM_PAGE]].Mem()) >> (ValueBits<SIZE>::VALUE-1);
-+ }
-+
-+ template<uint SIZE>
-+ dword GetBank(uint address) const
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE );
-+
-+ address >>= MEM_PAGE_SHIFT;
-+ return dword(pages.mem[address] - sources[pages.ref[address]].Mem()) >> (ValueBits<SIZE>::VALUE-1);
-+ }
-+ };
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>
-+ void Memory<SPACE,U,V>::SwapBank(dword bank)
-+ {
-+ NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank << MEM_OFFSET
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE>
-+ void Memory<SPACE,U,V>::SwapBank(uint address,dword bank)
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank << MEM_OFFSET,
-+ address >> MEM_PAGE_SHIFT
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>
-+ void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1)
-+ {
-+ NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 2) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>
-+ void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3)
-+ {
-+ NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET,
-+ bank2 << MEM_OFFSET,
-+ bank3 << MEM_OFFSET
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>
-+ void Memory<SPACE,U,V>::SwapBanks(dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7)
-+ {
-+ NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE * 4) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET,
-+ bank2 << MEM_OFFSET,
-+ bank3 << MEM_OFFSET,
-+ bank4 << MEM_OFFSET,
-+ bank5 << MEM_OFFSET,
-+ bank6 << MEM_OFFSET,
-+ bank7 << MEM_OFFSET
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE>
-+ void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1)
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE * 2 );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET,
-+ address >> MEM_PAGE_SHIFT
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE>
-+ void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3)
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE * 4 );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET,
-+ bank2 << MEM_OFFSET,
-+ bank3 << MEM_OFFSET,
-+ address >> MEM_PAGE_SHIFT
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE>
-+ void Memory<SPACE,U,V>::SwapBanks(uint address,dword bank0,dword bank1,dword bank2,dword bank3,dword bank4,dword bank5,dword bank6,dword bank7)
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE * 4 );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBanks
-+ (
-+ &pages,
-+ sources[0].Mem(),
-+ sources[0].Masking(),
-+ bank0 << MEM_OFFSET,
-+ bank1 << MEM_OFFSET,
-+ bank2 << MEM_OFFSET,
-+ bank3 << MEM_OFFSET,
-+ bank4 << MEM_OFFSET,
-+ bank5 << MEM_OFFSET,
-+ bank6 << MEM_OFFSET,
-+ bank7 << MEM_OFFSET,
-+ address >> MEM_PAGE_SHIFT
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint ADDRESS>
-+ void Memory<SPACE,U,V>::SourceProxy::SwapBank(dword bank) const
-+ {
-+ NST_COMPILE_ASSERT( (SPACE >= ADDRESS + SIZE) && SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_BEGIN = ADDRESS / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<MEM_PAGE_BEGIN,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank
-+ (
-+ &ref.pages,
-+ ref.sources[source].Mem(),
-+ ref.sources[source].Masking(),
-+ bank << MEM_OFFSET,
-+ 0,
-+ source
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE>
-+ void Memory<SPACE,U,V>::SourceProxy::SwapBank(uint address,dword bank) const
-+ {
-+ NST_COMPILE_ASSERT( SIZE && (SIZE % MEM_PAGE_SIZE == 0) );
-+ NST_ASSERT( SPACE >= address + SIZE );
-+
-+ enum
-+ {
-+ MEM_OFFSET = ValueBits<SIZE>::VALUE-1,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ Memory<0,0,0>::Unroller<0,MEM_PAGE_COUNT,MEM_PAGE_SIZE>::SwapBank
-+ (
-+ &ref.pages,
-+ ref.sources[source].Mem(),
-+ ref.sources[source].Masking(),
-+ bank << MEM_OFFSET,
-+ address >> MEM_PAGE_SHIFT,
-+ source
-+ );
-+ }
-+
-+ template<dword SPACE,uint U,uint V> template<uint SIZE,uint A,uint B>
-+ void Memory<SPACE,U,V>::SwapPages()
-+ {
-+ NST_COMPILE_ASSERT
-+ (
-+ (A != B) &&
-+ (SPACE >= A + SIZE) &&
-+ (SPACE >= B + SIZE) &&
-+ (SIZE && (SIZE % MEM_PAGE_SIZE) == 0)
-+ );
-+
-+ enum
-+ {
-+ MEM_A_BEGIN = A / MEM_PAGE_SIZE,
-+ MEM_B_BEGIN = B / MEM_PAGE_SIZE,
-+ MEM_PAGE_COUNT = SIZE / MEM_PAGE_SIZE
-+ };
-+
-+ for (uint i=0; i < MEM_PAGE_COUNT; ++i)
-+ {
-+ byte* const mem = pages.mem[MEM_A_BEGIN+i];
-+ const byte ref = pages.ref[MEM_A_BEGIN+i];
-+
-+ pages.mem[MEM_A_BEGIN+i] = pages.mem[MEM_B_BEGIN+i];
-+ pages.ref[MEM_A_BEGIN+i] = pages.ref[MEM_B_BEGIN+i];
-+
-+ pages.mem[MEM_B_BEGIN+i] = mem;
-+ pages.ref[MEM_B_BEGIN+i] = ref;
-+ }
-+ }
-+
-+ template<dword SPACE,uint U,uint V>
-+ void Memory<SPACE,U,V>::SaveState(State::Saver& state,const dword baseChunk) const
-+ {
-+ byte pageData[MEM_NUM_PAGES*3];
-+
-+ for (uint i=0; i < MEM_NUM_PAGES; ++i)
-+ {
-+ const uint bank = GetBank<MEM_PAGE_SIZE>( i * MEM_PAGE_SIZE );
-+
-+ pageData[i*3+0] = pages.ref[i];
-+ pageData[i*3+1] = bank & 0xFF;
-+ pageData[i*3+2] = bank >> 8;
-+ }
-+
-+ Memory<0,0,0>::SaveState( state, baseChunk, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES );
-+ }
-+
-+ template<dword SPACE,uint U,uint V>
-+ void Memory<SPACE,U,V>::LoadState(State::Loader& state)
-+ {
-+ byte pageData[MEM_NUM_PAGES*3];
-+
-+ if (Memory<0,0,0>::LoadState( state, sources, NUM_SOURCES, pageData, MEM_NUM_PAGES ))
-+ {
-+ for (uint i=0; i < MEM_NUM_PAGES; ++i)
-+ {
-+ if (pageData[i*3+0] < NUM_SOURCES)
-+ SwapBank<MEM_PAGE_SIZE>( i * MEM_PAGE_SIZE, pageData[i*3+1] | uint(pageData[i*3+2]) << 8 );
-+ else
-+ throw RESULT_ERR_CORRUPT_FILE;
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+#endif