         @oamAddress = address
 
     readOAMData: ->
-        @objectAttributeMemory[@oamAddress] # Does not increment the address
+        @objectAttributeMemory[@oamAddress] # Read does not increment the address.
 
     writeOAMData: (value) ->
         @objectAttributeMemory[@oamAddress] = value if not @isRenderingInProgress()
-        @oamAddress = (@oamAddress + 1) & 0xFF # Always increments the address
-        value
+        @oamAddress = (@oamAddress + 1) & 0xFF # Write always increments the address.
+        value
+
+    ###########################################################
+    # VRAM access
+    ###########################################################
+
+    writeAddress: (address) ->
+        @writeToogle = not @writeToogle
+        if @writeToogle # 1st write
+            addressHigh = (address & 0x3F) << 8
+            @tempAddress = (@tempAddress & 0x00FF) | addressHigh # High bits [13-8] (bit 14 is cleared)
+        else            # 2nd write
+            addressLow = address
+            @tempAddress = (@tempAddress & 0xFF00) | addressLow  # Low bits  [7-0]
+        address
+
+    readData: ->
+        address = @incrementAddress()
+        oldBufferContent = @vramReadBuffer
+        @vramReadBuffer = @read address                                         # Always increments the address
+        if @isPalleteAddress address then @vramReadBuffer else oldBufferContent # Delayed read outside the pallete memory area
+
+    writeData: (value) ->
+        address = @incrementAddress()                                   # Always increments the address
+        @ppuMemory.write address, value if not @isRenderingInProgress() # Only during VBLANK or disabled rendering
+        value
+
+    incrementAddress: ->
+        previousAddress = @vramAddress
+        @vramAddress = (@vramAddress + @getAddressIncrement()) & 0xFFFF
+        previousAddress
+
+    getAddressIncrement: ->
+        if @bigAddressIncrement then 0x20 else 0x01
+
+
+    ###########################################################
+    # Internal VRAM access
+    ###########################################################
+
+    read: (address) ->
+        value = @ppuMemory.read address
+        if @monochromeMode and @isPalleteAddress address
+            @getMonochromeColor value
+        else
+            value
+
+    write: (address, value) ->
+        @ppuMemory.write address, value
+
+    isPalleteAddress: (address) ->
+        (address & 0x3F00) == 0x3F00
+
+    getMonochromeColor: (index) ->
+        index & 0x30
 
     ###########################################################
     # Scrolling
     ###########################################################
 
+    # Uses the same register as VRAM addressing. 
+    # The register has the following structure: $0yyy.NNYY.YYYX.XXXX
+    #   yyy = fine Y scroll (y position of active row of rendered tile)
+    #    NN = index of active name table
+    # YYYYY = coarse Y scroll (y position of rendered tile in name table)
+    # XXXXX = coarse X scroll (x position of rendered tile in name table)
+
     writeScroll: (value) ->
-        # Uses the same register as VRAM addressing. 
-        # The register has the following structure: $0yyy.NNYY.YYYX.XXXX
-        #   yyy = fine Y scroll (y position of active row of rendered tile)
-        #    NN = index of active name table
-        # YYYYY = coarse Y scroll (y position of rendered tile in name table)
-        # XXXXX = coarse X scroll (x position of rendered tile in name table)
-        @writeAddress value 
+        @writeToogle = not @writeToogle
+        if @writeToogle # 1st write
+            @fineXScroll = value & 0x07
+            coarseXScroll = value >> 3
+            @tempAddress = (@tempAddress & 0xFFE0) | coarseXScroll
+        else            # 2nd write
+            fineYScroll = (value & 0x07) << 12
+            coarseYScroll = (value & 0xF1) << 2
+            @tempAddress = (@tempAddress & 0x18C0) | coarseYScroll | fineYScroll
+        value
+
+    copyHorizontalScrollBits: ->
+        @vramAddress = (@vramAddress & 0x7BE0) | (@tempAddress & 0x041F) # V[10,4-0] = T[10,4-0]
+
+    copyVerticalScrollBits: ->
+        @vramAddress = (@vramAddress & 0x041F) | (@tempAddress & 0x7BE0) # V[14-11,9-5] = T[14-11,9-5]
 
     incrementFineXScroll: ->
         if @fineXScroll is 7

        colorBit1 =  (@colorBit1Row >>> inverseFineXScroll) & 0x01
        colorBit2 = ((@colorBit2Row >>> inverseFineXScroll) & 0x01) << 1
        # Optimization - we compute this only when coarse scroll X was incremented 4 times.
        if (@vramAddress & 0x0003) is 0 or @firstPixelIsRendered
            # We compute pointer to attribute table as $2.NN11.11YY.Y.XXX
            # where YYY and XXX are 3 upper bits of YYYYY and XXXXX.
            # Each attribute applies to area of 4x4 tiles (that's why we removed 2 lower bits of YYYYY and XXXXX).
            attributeTableAddress = 0x2000 | (@vramAddress & 0x0C00) | 0x03C0
            attributeNumber = (@vramAddress >>> 4) & 0x38 | (@vramAddress >>> 2) & 0x07
            attributeAddress = attributeTableAddress + attributeNumber
            attribute = @read attributeAddress


    writeControl: (value) ->
        @setControl value
        @tempAddress = (@vramAddress & 0xF3FF) | (value & 0x03) << 10 # T[11,10] = C[1,0]
        value

    setControl: (value) ->
        @bigAddressIncrement         = (value >>> 2) & 0x01 # C[2]
        @spritesPatternTableIndex    = (value >>> 3) & 0x01 # C[3]
        @backgroundPatternTableIndex = (value >>> 4) & 0x01 # C[4]
        @bigSprites                  = (value >>> 5) & 0x01 # C[5]
        @vblankGeneratesNMI          = (value >>> 7)        # C[7]

    ###########################################################
    # Mask register
