summaryrefslogtreecommitdiff
path: root/fig-emulator-gb/src/Fig/Emulator/GB/Bus.hs
blob: 2b71f2f2acb463b2d436341fa0ceb9ea2e448bed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
module Fig.Emulator.GB.Bus
  ( Addr(..)
  , Component(..)
  , Bus(..)
  , update
  , write
  , read
  ) where

import Fig.Prelude

import Numeric (showHex)

import qualified Data.List as List
import Data.Word (Word16, Word8)

newtype Addr = Addr { unAddr :: Word16 }
  deriving (Show, Num, Eq, Ord)
instance Pretty Addr where
  pretty (Addr w) = "$" <> pack (showHex w "")

data Component = forall (s :: Type). Component
  { compState :: !s
  , compMatches :: !(Addr -> Bool)
  , compUpdate :: !(s -> Word16 -> IO s)
  , compWrite :: !(s -> Addr -> Word8 -> IO s)
  , compRead :: !(s -> Addr -> IO Word8)
  }

newtype Bus = Bus { busComponents :: [Component] }

update :: Word16 -> Bus -> IO Bus
update t b = Bus <$> forM (busComponents b) \Component{..} -> do
  s <- compUpdate compState t
  pure Component { compState = s, ..}

write :: Bus -> Addr -> Word8 -> IO Bus
write b a v = Bus <$> forM (busComponents b) \c@Component{..} ->
  if compMatches a
  then do
    s <- compWrite compState a v
    pure Component { compState = s, ..}
  else pure c

read :: Bus -> Addr -> IO (Maybe Word8)
read b a = case List.find (`compMatches` a) $ busComponents b of
  Nothing -> pure Nothing
  Just Component{..} -> Just <$> compRead compState a