chrLoad :: Mapper s -> MemoryMap s -> Word16 -> ST s Word8
chrLoad (Mapper0 ntMap) mem addr =
    if addr < 0x2000
      then readArray (chr mem) addr
      else do
        ntMap' <- readSTRef ntMap
        case addr .&. 0xC00 of
          0x000 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt0 ntMap'))
          0x400 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt1 ntMap'))
          0x800 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt2 ntMap'))
          _ -> if addr >= 0x3F00 -- includes addr .&. 0xC00 == 0xC00
                 then do
                   let addr' = fromIntegral $ addr .&. 0x1F
                       addr'' = if addr' >= 0x10 && (addr' .&. 0x3 == 0) then addr' - 0x10 else addr'
                   readArray (palette mem) addr''
                 else readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt3 ntMap'))
chrLoad :: Mapper s -> MemoryMap s -> Word16 -> ST s Word8
chrLoad (Mapper0 ntMap) mem addr =
    if addr < 0x2000
      then readArray (chr mem) addr
      else do
        ntMap' <- readSTRef ntMap
        case addr .&. 0xC00 of
          0x000 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt0 ntMap'))
          0x400 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt1 ntMap'))
          0x800 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt2 ntMap'))
          _ -> if addr >= 0x3F00 -- includes addr .&. 0xC00 == 0xC00
                 then do
                   let addr' = fromIntegral $ addr .&. 0x1F
                       addr'' = if addr' >= 0x10 && (addr' .&. 0x3 == 0) then addr' - 0x10 else addr'
                   readArray (palette mem) addr''
                 else readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt3 ntMap'))
chrLoad (Mapper0 ntMap) mem addr =
    if addr < 0x2000
      then readArray (chr mem) addr
      else do
        ntMap' <- readSTRef ntMap
        case addr .&. 0xC00 of
          0x000 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt0 ntMap'))
          0x400 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt1 ntMap'))
          0x800 -> readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt2 ntMap'))
          _ -> if addr >= 0x3F00 -- includes addr .&. 0xC00 == 0xC00
                 then do
                   let addr' = fromIntegral $ addr .&. 0x1F
                       addr'' = if addr' >= 0x10 && (addr' .&. 0x3 == 0) then addr' - 0x10 else addr'
                   readArray (palette mem) addr''
                 else readArray (nametables mem) (addr .&. 0x3FF + nameTableAddress (nt3 ntMap'))