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