summaryrefslogtreecommitdiff
path: root/fig-emulator-gb/src/Fig/Emulator/GB.hs
blob: d5ae4e7c19a881e8907180b0d43cd51193c03d4e (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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{-# Language ImplicitParams #-}
module Fig.Emulator.GB where

import Fig.Prelude
import Prelude (fromIntegral)

import System.IO (withFile, IOMode (WriteMode))

import Control.Lens ((.=), use)
import Control.Monad (when)
import Control.Monad.State (StateT(..))

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

cpuDMG :: (MonadIO m, MonadThrow m) => ByteString -> Framebuffer -> CPU m
cpuDMG rom fb = CPU
  { _lastPC = 0x0
  , _lastIns = Nop
  , _running = True
  , _regs = initialRegs
  , _bus = Bus
    [ compROM rom
    , compWRAM 0xc000 $ 8 * 1024
    , compVideo fb
    , compJoystick
    , compSerial
    , compWRAM 0xff80 0x7e -- HRAM
    ]
  }

testRun :: forall m. (MonadIO m, MonadThrow m) => ByteString -> m ()
testRun rom = do
  SDL.initializeAll
  window <- SDL.createWindow "taking" SDL.defaultWindow
  fb <- initializeFramebuffer
  let cpu = cpuDMG rom fb
  let
    loop :: forall m'. Emulating m' => Int -> m' ()
    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
      -- logCPUState
      when (rem cycle 70224 == 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 * 8)
            (fromIntegral screenHeight * 8)))
        SDL.updateWindowSurface window
      r <- use running
      when r . loop $ cycle + 1
  liftIO $ withFile "log.txt" WriteMode \h -> do
    let ?log = h
    void $ flip runStateT cpu do
      -- logCPUState
      loop 0