module Nes.APU.State.FrameCounter (
FrameCounter (..),
newFrameCounter,
SequenceMode (..),
sequenceModeFromBool,
shouldIncrementSequenceStep,
shouldResetSequenceStep,
incrementSequenceStep,
resetSequence,
setCycles,
) where
import Data.List ((!?))
data SequenceMode = FourStep | FiveStep deriving (SequenceMode -> SequenceMode -> Bool
(SequenceMode -> SequenceMode -> Bool)
-> (SequenceMode -> SequenceMode -> Bool) -> Eq SequenceMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SequenceMode -> SequenceMode -> Bool
== :: SequenceMode -> SequenceMode -> Bool
$c/= :: SequenceMode -> SequenceMode -> Bool
/= :: SequenceMode -> SequenceMode -> Bool
Eq, Int -> SequenceMode -> ShowS
[SequenceMode] -> ShowS
SequenceMode -> String
(Int -> SequenceMode -> ShowS)
-> (SequenceMode -> String)
-> ([SequenceMode] -> ShowS)
-> Show SequenceMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SequenceMode -> ShowS
showsPrec :: Int -> SequenceMode -> ShowS
$cshow :: SequenceMode -> String
show :: SequenceMode -> String
$cshowList :: [SequenceMode] -> ShowS
showList :: [SequenceMode] -> ShowS
Show, Int -> SequenceMode
SequenceMode -> Int
SequenceMode -> [SequenceMode]
SequenceMode -> SequenceMode
SequenceMode -> SequenceMode -> [SequenceMode]
SequenceMode -> SequenceMode -> SequenceMode -> [SequenceMode]
(SequenceMode -> SequenceMode)
-> (SequenceMode -> SequenceMode)
-> (Int -> SequenceMode)
-> (SequenceMode -> Int)
-> (SequenceMode -> [SequenceMode])
-> (SequenceMode -> SequenceMode -> [SequenceMode])
-> (SequenceMode -> SequenceMode -> [SequenceMode])
-> (SequenceMode -> SequenceMode -> SequenceMode -> [SequenceMode])
-> Enum SequenceMode
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: SequenceMode -> SequenceMode
succ :: SequenceMode -> SequenceMode
$cpred :: SequenceMode -> SequenceMode
pred :: SequenceMode -> SequenceMode
$ctoEnum :: Int -> SequenceMode
toEnum :: Int -> SequenceMode
$cfromEnum :: SequenceMode -> Int
fromEnum :: SequenceMode -> Int
$cenumFrom :: SequenceMode -> [SequenceMode]
enumFrom :: SequenceMode -> [SequenceMode]
$cenumFromThen :: SequenceMode -> SequenceMode -> [SequenceMode]
enumFromThen :: SequenceMode -> SequenceMode -> [SequenceMode]
$cenumFromTo :: SequenceMode -> SequenceMode -> [SequenceMode]
enumFromTo :: SequenceMode -> SequenceMode -> [SequenceMode]
$cenumFromThenTo :: SequenceMode -> SequenceMode -> SequenceMode -> [SequenceMode]
enumFromThenTo :: SequenceMode -> SequenceMode -> SequenceMode -> [SequenceMode]
Enum)
{-# INLINE sequenceModeFromBool #-}
sequenceModeFromBool :: Bool -> SequenceMode
sequenceModeFromBool :: Bool -> SequenceMode
sequenceModeFromBool = Int -> SequenceMode
forall a. Enum a => Int -> a
toEnum (Int -> SequenceMode) -> (Bool -> Int) -> Bool -> SequenceMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Int
forall a. Enum a => a -> Int
fromEnum
{-# INLINE sequenceModeStepCount #-}
sequenceModeStepCount :: SequenceMode -> Int
sequenceModeStepCount :: SequenceMode -> Int
sequenceModeStepCount = \case
SequenceMode
FourStep -> Int
4
SequenceMode
FiveStep -> Int
5
sequenceStepCycles :: SequenceMode -> [Int]
sequenceStepCycles :: SequenceMode -> [Int]
sequenceStepCycles = \case
SequenceMode
FourStep -> [Int
3728, Int
7456, Int
11185, Int
14914, Int
14915]
SequenceMode
FiveStep -> [Int
3728, Int
7456, Int
11185, Int
14914, Int
18640, Int
18641]
{-# INLINE shouldIncrementSequenceStep #-}
shouldIncrementSequenceStep :: FrameCounter -> Bool
shouldIncrementSequenceStep :: FrameCounter -> Bool
shouldIncrementSequenceStep FrameCounter
fc =
let
table :: [Int]
table = SequenceMode -> [Int]
sequenceStepCycles (SequenceMode -> [Int]) -> SequenceMode -> [Int]
forall a b. (a -> b) -> a -> b
$ FrameCounter -> SequenceMode
sequenceMode FrameCounter
fc
in
case [Int]
table [Int] -> Int -> Maybe Int
forall a. [a] -> Int -> Maybe a
!? FrameCounter -> Int
sequenceStep FrameCounter
fc of
Maybe Int
Nothing -> Bool
False
Just Int
s -> FrameCounter -> Int
cycles FrameCounter
fc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
s
{-# INLINE shouldResetSequenceStep #-}
shouldResetSequenceStep :: FrameCounter -> Bool
shouldResetSequenceStep :: FrameCounter -> Bool
shouldResetSequenceStep FrameCounter
fc =
let
table :: [Int]
table = SequenceMode -> [Int]
sequenceStepCycles (SequenceMode -> [Int]) -> SequenceMode -> [Int]
forall a b. (a -> b) -> a -> b
$ FrameCounter -> SequenceMode
sequenceMode FrameCounter
fc
in
case [Int]
table [Int] -> Int -> Maybe Int
forall a. [a] -> Int -> Maybe a
!? Int
5 of
Maybe Int
Nothing -> Bool
False
Just Int
s -> FrameCounter -> Int
cycles FrameCounter
fc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
s
data FrameCounter = MkFC
{ FrameCounter -> SequenceMode
sequenceMode :: {-# UNPACK #-} !SequenceMode
, FrameCounter -> Bool
frameInterruptFlag :: {-# UNPACK #-} !Bool
, FrameCounter -> Bool
inhibitInterrupt :: {-# UNPACK #-} !Bool
, FrameCounter -> Int
sequenceStep :: {-# UNPACK #-} !Int
, FrameCounter -> Int
cycles :: {-# UNPACK #-} !Int
, FrameCounter -> Maybe Int
delayedWriteSideEffectCycle :: !(Maybe Int)
}
newFrameCounter :: FrameCounter
newFrameCounter :: FrameCounter
newFrameCounter = SequenceMode
-> Bool -> Bool -> Int -> Int -> Maybe Int -> FrameCounter
MkFC SequenceMode
FourStep Bool
False Bool
False Int
0 Int
0 Maybe Int
forall a. Maybe a
Nothing
{-# INLINE resetSequence #-}
resetSequence :: FrameCounter -> FrameCounter
resetSequence :: FrameCounter -> FrameCounter
resetSequence FrameCounter
fc = FrameCounter
fc{cycles = 0, sequenceStep = 0}
{-# INLINE setCycles #-}
setCycles :: (Int -> Int) -> FrameCounter -> FrameCounter
setCycles :: (Int -> Int) -> FrameCounter -> FrameCounter
setCycles Int -> Int
f FrameCounter
fc = FrameCounter
fc{cycles = f $ cycles fc}
{-# INLINE incrementSequenceStep #-}
incrementSequenceStep :: FrameCounter -> FrameCounter
incrementSequenceStep :: FrameCounter -> FrameCounter
incrementSequenceStep FrameCounter
fc =
FrameCounter
fc
{ sequenceStep = nextStep `mod` (maxStep + 1)
}
where
nextStep :: Int
nextStep = FrameCounter -> Int
sequenceStep FrameCounter
fc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
maxStep :: Int
maxStep = SequenceMode -> Int
sequenceModeStepCount (FrameCounter -> SequenceMode
sequenceMode FrameCounter
fc)