Permalink
Browse files

Separate ST module, update README a bit

  • Loading branch information...
jaspervdj committed Apr 9, 2012
1 parent e8ff1a3 commit eb73f56095cb9ec31e10924e98e0360a49e325d0
Showing with 70 additions and 34 deletions.
  1. +29 −1 README.markdown
  2. +2 −0 dcpu16-hs.cabal
  3. +1 −1 src/Emulator/Main.hs
  4. +1 −32 src/Emulator/Monad.hs
  5. +36 −0 src/Emulator/Monad/ST.hs
  6. +1 −0 tests/Examples.hs
View
@@ -16,7 +16,8 @@ example, and the stuff in `examples/`.
Like the assembler Notch uses, short form for labels isn't supported yet.
The emulator just runs until it crashes, there is no stopping strategy for now.
The emulator just runs until it crashes (usually when it tries to execute a
0x0000 opcode), there is no stopping strategy for now.
Building
--------
@@ -33,3 +34,30 @@ This produces `a.out`.
./dist/build/dcpu16-emulator/dcpu16-emulator a.out
You should probably redirect the output to a file.
Design
------
We use a homogeneous `Memory` type for all kinds of memory the CPU has access
to:
- Special values such as `SP`, `PC` and `O`
- Custom defined (i.e. not in the spec) values such as `SKIP`, `CYCLES`
- Registers (`A`, `B`...)
- RAM
All these values can be accessed if you know its `Address`, which is statically
known for e.g. `SP`, and can be calculated for e.g. the RAM at `0x1000`.
The core of the design is hence a monadic typeclass:
class Monad m => MonadEmulator m where
load :: Address -> m Word16
store :: Address -> Word16 -> m ()
Currently, there is only one implementation of this class, `STEmulator`, which
is able to simulate programs in a *pure* way (so a program is guaranteed to
always yield the same result!).
When the spec is better defined, an `IOEmulator` will be added which will not be
pure, in order to be able to grab keyboard events and display video.
View
@@ -17,6 +17,8 @@ Executable dcpu16-emulator
Other-modules:
Emulator
Emulator.Monad
Emulator.Monad.ST
Instruction
Memory
Util
View
@@ -7,7 +7,7 @@ import System.Exit (exitFailure)
import qualified Data.ByteString as B
import Emulator
import Emulator.Monad
import Emulator.Monad.ST
main :: IO ()
main = do
View
@@ -1,42 +1,11 @@
{-# LANGUAGE GeneralizedNewtypeDeriving, Rank2Types #-}
module Emulator.Monad
( MonadEmulator (..)
-- * Pure implementation
, STEmulator
, runSTEmulator
) where
import Control.Monad.Reader (ReaderT, ask, runReaderT)
import Control.Monad.ST (ST, runST)
import Control.Monad.Trans (lift)
import Data.Word (Word16)
import Memory (Address, Memory)
import qualified Memory as Memory
import Memory (Address)
class (Functor m, Monad m) => MonadEmulator m where
load :: Address -> m Word16
store :: Address -> Word16 -> m ()
newtype STEmulator s a = STEmulator (ReaderT (Memory s) (ST s) a)
deriving (Functor, Monad)
instance MonadEmulator (STEmulator s) where
load address = STEmulator $ do
mem <- ask
lift $ Memory.load mem address
store address word = STEmulator $ do
mem <- ask
lift $ Memory.store mem address word
runSTEmulator :: (forall s. STEmulator s a) -> a
runSTEmulator emu =
-- If you wonder why this isn't defined as `runST . run`... type magic.
let x = run emu
in runST x
where
run :: STEmulator s a -> ST s a
run (STEmulator reader) = do
mem <- Memory.new
runReaderT reader mem
View
@@ -0,0 +1,36 @@
-- | A pure implementation of the emulator
{-# LANGUAGE GeneralizedNewtypeDeriving, Rank2Types #-}
module Emulator.Monad.ST
( STEmulator
, runSTEmulator
) where
import Control.Monad.Reader (ReaderT, ask, runReaderT)
import Control.Monad.ST (ST, runST)
import Control.Monad.Trans (lift)
import Emulator.Monad
import Memory (Memory)
import qualified Memory as Memory
newtype STEmulator s a = STEmulator (ReaderT (Memory s) (ST s) a)
deriving (Functor, Monad)
instance MonadEmulator (STEmulator s) where
load address = STEmulator $ do
mem <- ask
lift $ Memory.load mem address
store address word = STEmulator $ do
mem <- ask
lift $ Memory.store mem address word
runSTEmulator :: (forall s. STEmulator s a) -> a
runSTEmulator emu =
-- If you wonder why this isn't defined as `runST . run`... type magic.
let x = run emu
in runST x
where
run :: STEmulator s a -> ST s a
run (STEmulator reader) = do
mem <- Memory.new
runReaderT reader mem
View
@@ -14,6 +14,7 @@ import qualified Data.ByteString as B
import Assembler
import Emulator
import Emulator.Monad
import Emulator.Monad.ST
import qualified Memory as Memory
tests :: Test

0 comments on commit eb73f56

Please sign in to comment.