Permalink
Browse files

Run until we crash

  • Loading branch information...
jaspervdj committed Apr 6, 2012
1 parent 82b141b commit 07afdeafd58356e6c8f18f14e96905b1a36b1dc8
Showing with 45 additions and 19 deletions.
  1. +10 −9 README.markdown
  2. +11 −5 src/Emulator.hs
  3. +24 −5 src/Emulator/Main.hs
View
@@ -1,23 +1,24 @@
dcpu16-hs
=========
Implementation of Notch's [dcpu-16] CPU in Haskell.
Implementation of Notch's [dcpu-16] CPU in Haskell. This project includes an
assembler and an emulator.
[dcpu-16]: http://0x10c.com/doc/dcpu-16.txt
Status
------
The assembler can assemble Notch's test program.
We can assemble and compile at least Notch's example program, and this
[fibonacci] example.
It generates worse code than the code generated by Notch's assembler because it
never tries to inline literal values into the first word of an instruction.
[fibonacci]: https://github.com/jazzychad/dcpu-asm/blob/master/fib.d16
The emulator seems to run Notch's test program.
The assembler generates worse code than the code generated by Notch's assembler
because it never tries to inline literal values into the first word of an
instruction.
The current strategy is to simulate 10000 instructions (*not* cycles). A better
strategy would be to stop when PC ends up after the code, but this would not
work for some hacks (e.g. programs that modify themselves).
The emulator just runs until it crashes, there is no stopping strategy for now.
Building
--------
@@ -29,7 +30,7 @@ Running
./dist/build/dcpu16-assembler/dcpu16-assembler examples/notch.s
This produces `a.out`
This produces `a.out`.
./dist/build/dcpu16-emulator/dcpu16-emulator a.out
View
@@ -1,6 +1,7 @@
{-# LANGUAGE BangPatterns, Rank2Types #-}
module Emulator
( EmulatorM
, newEmulatorState
, runEmulatorM
, loadProgram
, step
@@ -10,7 +11,7 @@ module Emulator
import Control.Applicative ((<$>))
import Control.Monad (forM)
import Control.Monad.Reader (ReaderT, ask, runReaderT)
import Control.Monad.ST (ST, runST)
import Control.Monad.ST (ST)
import Control.Monad.Trans (lift)
import Data.Bits (shiftL, shiftR, xor, (.&.), (.|.))
import Data.Word (Word, Word16)
@@ -23,13 +24,18 @@ import Memory (Address, Memory)
import Util
import qualified Memory as Memory
type EmulatorM s = ReaderT (Memory s) (ST s)
type EmulatorState s = Memory s
runEmulatorM :: (forall s. EmulatorM s a) -> a
runEmulatorM program = runST $ do
newEmulatorState :: ST s (EmulatorState s)
newEmulatorState = do
mem <- Memory.new
Memory.store mem Memory.sp 0xffff
runReaderT program mem
return mem
type EmulatorM s = ReaderT (EmulatorState s) (ST s)
runEmulatorM :: EmulatorM s a -> EmulatorState s -> ST s a
runEmulatorM = runReaderT
-- | Load a program from a bytestring
loadProgram :: ByteString -> EmulatorM s ()
View
@@ -1,6 +1,9 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Control.Monad (replicateM_)
import Control.Exception (SomeException, try)
import Control.Monad (forever)
import Control.Monad.ST.Unsafe (unsafeSTToIO)
import System.Environment (getArgs, getProgName)
import System.Exit (exitFailure)
@@ -14,11 +17,27 @@ main = do
args <- getArgs
case args of
[x] -> do
bytes <- B.readFile x
putStr $ runEmulatorM $ do
-- Warning: this code is unsafeSTToIO madness
--
-- Start by loading a new emulator state, loading the program,
-- then step forever
bytes <- B.readFile x
state <- unsafeSTToIO newEmulatorState
result <- try $ unsafeSTToIO $ flip runEmulatorM state $ do
loadProgram bytes
replicateM_ 10000 step
prettify
forever step
-- Check the result
case result of
Left (ex :: SomeException) -> putStrLn $
"Emulator crashed: " ++ show ex
Right () -> putStrLn $ "Emulator somehow managed to stop."
-- Pretty dump
pretty <- unsafeSTToIO $ runEmulatorM prettify state
putStrLn ""
putStr pretty
_ -> do
putStr $ "Usage: " ++ progName ++ " <executable>"
exitFailure

0 comments on commit 07afdea

Please sign in to comment.