{-# LANGUAGE TemplateHaskell #-}

module Nes.Bus.State (
    BusState (..),
    newBusState,

    -- * Lenses
    cpuVram,
    cartridge,
    controller,
    cycles,
    unsleptCycles,
    cycleCallback,
    lastSleepTime,
    ppuState,
    ppuPointers,
    onNewFrame,
    dataBus,
    apuState,
    pollControls,
    cpuInterrupt,
) where

import Control.Lens (makeLenses)
import Nes.APU.State (APUState, newAPUState)
import Nes.APU.State.Filter.Constants (Sample)
import Nes.APU.State.Filter.Thread (FilterThread)
import Nes.Controller
import Nes.Interrupt
import Nes.Memory
import Nes.Memory.Internal
import Nes.Memory.Unsafe ()
import Nes.PPU.Constants
import Nes.PPU.Pointers (PPUPointers, newPPUPointers)
import Nes.PPU.State (PPUState, newPPUState)
import Nes.Rom (Rom (..))

-- | Interface for the CPU that allows it to read/write to RAM
data BusState = BusState
    { BusState -> MemoryPointer
_cpuVram :: {-# UNPACK #-} !MemoryPointer
    -- ^ Pointer to writeable memory
    , BusState -> Rom
_cartridge :: !Rom
    -- ^ Read-only memory, see 'Rom'
    , BusState -> ControllerState
_controller :: !ControllerState
    -- ^ Aka Joypad
    , BusState -> Integer
_cycles :: {-# UNPACK #-} !Integer
    , BusState -> Int
_unsleptCycles :: {-# UNPACK #-} !Int
    -- ^ The number of cycles that we need to call 'threadDelay' for
    , BusState -> Double -> Int -> IO (Double, Int)
_cycleCallback :: Double -> Int -> IO (Double, Int)
    -- ^ The function to call 'threadDelay' according to 'unsleptCycles' (> 'unsleptCyclesThreshold')
    -- The return value is the new number of unslept cycles
    , BusState -> Double
_lastSleepTime :: {-# UNPACK #-} !Double
    , BusState -> PPUState
_ppuState :: !PPUState
    -- ^ The state of the PPU
    , BusState -> PPUPointers
_ppuPointers :: !PPUPointers
    -- ^ Memory dedicated to PPU
    , BusState -> BusState -> IO ()
_onNewFrame :: BusState -> IO ()
    , BusState -> ControllerState -> IO ControllerState
_pollControls :: ControllerState -> IO ControllerState
    , BusState -> Byte
_dataBus :: {-# UNPACK #-} !Byte
    -- ^ Last read/written byte
    , BusState -> APUState
_apuState :: !APUState
    , BusState -> InterruptStatus
_cpuInterrupt :: {-# UNPACK #-} !InterruptStatus
    }

newBusState ::
    Rom ->
    -- | Callback on new frame
    (BusState -> IO ()) ->
    -- | Callback to poll controller inputs
    (ControllerState -> IO ControllerState) ->
    -- | Callback when a sample is ready
    (Sample -> IO ()) ->
    -- | Callback when a cycle ends
    (Double -> Int -> IO (Double, Int)) ->
    FilterThread ->
    IO BusState
newBusState :: Rom
-> (BusState -> IO ())
-> (ControllerState -> IO ControllerState)
-> (Sample -> IO ())
-> (Double -> Int -> IO (Double, Int))
-> FilterThread
-> IO BusState
newBusState Rom
_cartridge BusState -> IO ()
_onNewFrame ControllerState -> IO ControllerState
_pollControls Sample -> IO ()
pushSample Double -> Int -> IO (Double, Int)
_cycleCallback FilterThread
filterThread = do
    MemoryPointer
_cpuVram <- Int -> IO MemoryPointer
callocForeignPtr Int
vramSize
    PPUPointers
_ppuPointers <- IO PPUPointers
newPPUPointers
    let _controller :: ControllerState
_controller = ControllerState
newControllerState
        _ppuState :: PPUState
_ppuState = Mirroring -> PPUState
newPPUState (Rom -> Mirroring
mirroring Rom
_cartridge)
        _cycles :: Integer
_cycles = Integer
0
        _unsleptCycles :: Int
_unsleptCycles = Int
0
        _lastSleepTime :: Double
_lastSleepTime = Double
0
        _dataBus :: Byte
_dataBus = Byte
0
        _apuState :: APUState
_apuState = (Sample -> IO ()) -> FilterThread -> APUState
newAPUState Sample -> IO ()
pushSample FilterThread
filterThread
        _cpuInterrupt :: InterruptStatus
_cpuInterrupt = Maybe IRQSource -> Bool -> InterruptStatus
MkIS Maybe IRQSource
forall a. Maybe a
Nothing Bool
False
    BusState -> IO BusState
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BusState -> IO BusState) -> BusState -> IO BusState
forall a b. (a -> b) -> a -> b
$ BusState{Double
Int
Integer
MemoryPointer
InterruptStatus
Byte
ControllerState
APUState
PPUPointers
Rom
PPUState
Double -> Int -> IO (Double, Int)
ControllerState -> IO ControllerState
BusState -> IO ()
_cpuVram :: MemoryPointer
_cartridge :: Rom
_controller :: ControllerState
_cycles :: Integer
_unsleptCycles :: Int
_cycleCallback :: Double -> Int -> IO (Double, Int)
_lastSleepTime :: Double
_ppuState :: PPUState
_ppuPointers :: PPUPointers
_onNewFrame :: BusState -> IO ()
_pollControls :: ControllerState -> IO ControllerState
_dataBus :: Byte
_apuState :: APUState
_cpuInterrupt :: InterruptStatus
_cartridge :: Rom
_onNewFrame :: BusState -> IO ()
_pollControls :: ControllerState -> IO ControllerState
_cycleCallback :: Double -> Int -> IO (Double, Int)
_cpuVram :: MemoryPointer
_ppuPointers :: PPUPointers
_controller :: ControllerState
_ppuState :: PPUState
_cycles :: Integer
_unsleptCycles :: Int
_lastSleepTime :: Double
_dataBus :: Byte
_apuState :: APUState
_cpuInterrupt :: InterruptStatus
..}

makeLenses ''BusState