// TODO: Switch to builder pattern.
            public void Register(ushort address, IMemorySource source)
            {
                Asserts.True(source.Size > 0,
                             $"Source at {ByteFormatter.ToHex16(address)} is empty!");
                Asserts.True(address + source.Size <= this.Size,
                             $"Source at {ByteFormatter.ToHex16(address)} hangs off right end of mapper!");
                Asserts.True(address + source.Size <= this.Size,
                             $"Source at {ByteFormatter.ToHex16(address)} hangs off right end of mapper!");

                var newStartAddress = address;
                var newEndAddress   = newStartAddress + (source.Size - 1);

                foreach (var existingKvp in this.sourcesBuilder_)
                {
                    var existingStartAddress = existingKvp.Key;
                    var existingEndAddress   =
                        existingStartAddress + (existingKvp.Value.Size - 1);
                    if (newStartAddress <= existingEndAddress &&
                        newEndAddress >= existingStartAddress)
                    {
                        Assert.Fail(
                            $"New source at {ByteFormatter.ToHex16(address)} intersects with old source!");
                    }
                }

                this.sourcesBuilder_.Add(address,
                                         new MemoryMapperSource(address, source));
            }
            public byte this[ushort address] {
                get {
                    var source = this.At_(address);
                    if (source == null)
                    {
                        Asserts.Fail(
                            $"Expected source at {ByteFormatter.ToHex16(address)} to be nonnull!");
                    }
                    var relativeAddress = (ushort)(address - source !.Address);
                    return(source[relativeAddress]);
                }

                set {
                    var source = this.At_(address);
                    if (source == null)
                    {
                        Asserts.Fail(
                            $"Expected source at {ByteFormatter.ToHex16(address)} to be nonnull!");
                    }
                    var relativeAddress = (ushort)(address - source !.Address);
                    source[relativeAddress] = value;
                }
            }
        private void RenderForOrthographicCamera_(
            RenderForOrthographicCameraTickEvent evt)
        {
            var g = evt.Graphics;

            this.RenderLcd_(g);

            g.Primitives.VertexColor(Color.White);

            var registers   = this.mmu_.Registers;
            var memoryMap   = this.mmu_.MemoryMap;
            var ioAddresses = memoryMap.IoAddresses;

            var lX = 202;
            var bY = 145;

            var t = g.Text;
            var i = 0;

            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "pc: " + ByteFormatter.ToHex16(registers.Pc.Value));

            i++;
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "af: " + ByteFormatter.ToHex16(registers.Af.Value));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "bc: " + ByteFormatter.ToHex16(registers.Bc.Value));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "de: " + ByteFormatter.ToHex16(registers.De.Value));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "hl: " + ByteFormatter.ToHex16(registers.Hl.Value));
            i++;

            lX = 320;
            i  = 0;

            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "ppu: " + ByteFormatter.ToHex8((byte)this.cpu_.PpuMode));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "ly: " +
                   ByteFormatter.ToHex8(this.mmu_.MemoryMap.IoAddresses.Ly.Value));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   "dma: " +
                   ByteFormatter.ToHex16(this.mmu_.MemoryMap.IoAddresses
                                         .LastDmaAddress));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   ByteFormatter.ToHex8(ioAddresses.Lcdc.Value));
            t.Draw(lX,
                   20 * i++,
                   16,
                   16,
                   ByteFormatter.ToHex8(this.cpu_.ScanlineLcdc));

            var oam = memoryMap.Oam;

            for (i = 0; i < 40; i++)
            {
                var oamAddress = (ushort)(i * 4);
                var y          = (byte)(oam[oamAddress] - 16);
                var x          = (byte)(oam[(ushort)(oamAddress + 1)] - 8);

                var nPerRow = 7;
                var c       = i % nPerRow;
                var r       = (i - c) / nPerRow;

                t.Draw(c * 90,
                       bY + r * 20,
                       16,
                       16,
                       "(" +
                       ByteFormatter.ToHex8(x) +
                       ", " +
                       ByteFormatter.ToHex8(y) +
                       ")");
            }
        }