module Fig.Emulator.GB where import Prelude (error) import Fig.Prelude import System.IO (withFile, IOMode (WriteMode)) import Control.Lens ((.=), use) import Control.Monad (when) import Control.Monad.State.Strict (StateT(..)) import qualified Data.Vector as V import qualified Data.ByteString as BS import qualified SDL import Fig.Emulator.GB.CPU import Fig.Emulator.GB.CPU.Instruction import Fig.Emulator.GB.Bus (Bus(..), Addr(..)) import Fig.Emulator.GB.Component.RAM import Fig.Emulator.GB.Component.ROM import Fig.Emulator.GB.Component.Video import Fig.Emulator.GB.Component.Joystick import Fig.Emulator.GB.Component.Serial import Fig.Emulator.GB.Component.Misc import Fig.Emulator.GB.Component.Interrupt cpuDMG :: Maybe Handle -> ByteString -> Framebuffer -> CPU cpuDMG serial rom fb = CPU { _lastPC = 0x0 , _lastIns = Nop , _running = True , _regs = initialRegs , _bus = Bus [ compROM rom , compWRAM 0xc000 $ 8 * 1024 , compVideo fb , compJoystick , compSerial serial , compInterrupt , compMisc , compWRAM 0xff80 0x7e -- HRAM ] } testRun :: Maybe FilePath -> ByteString -> IO () testRun serialOut rom = do SDL.initializeAll window <- SDL.createWindow "taking" SDL.defaultWindow fb <- initializeFramebuffer let withSerial f = case serialOut of Nothing -> f Nothing Just p -> withFile p WriteMode $ f . Just liftIO $ withSerial \hserial -> do let cpu = cpuDMG hserial rom fb let loop :: Int -> Emulating () loop cycle = do events <- SDL.pollEvents forM_ events \ev -> case SDL.eventPayload ev of SDL.QuitEvent -> running .= False _else -> pure () pc <- use $ regs . regPC ins <- decode when (pc == 0x2817) do log $ mconcat [ pretty $ Addr pc , ": ", tshow ins ] step ins when (rem cycle 1000000 == 0) do log "1 million" when (rem cycle 300000 == 0) do ws <- SDL.getWindowSurface window SDL.surfaceFillRect ws Nothing $ SDL.V4 0x00 0x00 0x00 0xff void $ SDL.surfaceBlitScaled (fbSurface fb) Nothing ws (Just $ SDL.Rectangle (SDL.P $ SDL.V2 0 0) (SDL.V2 (fromIntegral screenWidth * 4) (fromIntegral screenHeight * 4))) SDL.updateWindowSurface window r <- use running when r . loop $ cycle + 1 void $ flip (runStateT . runEmulating) cpu do loop 0