Respect flags during execution
This commit is contained in:
parent
7397a0fecd
commit
564bc44d51
2 changed files with 32 additions and 18 deletions
|
|
@ -16,12 +16,12 @@ main = runOrExit 2 $ do
|
||||||
initialState <- loadMimaState $ inputFile opts
|
initialState <- loadMimaState $ inputFile opts
|
||||||
finalState <- liftIO $ case steps opts of
|
finalState <- liftIO $ case steps opts of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
let (finalState, abortReason, stepsMade) = execute initialState
|
let (finalState, abortReason, stepsMade) = execute mempty initialState
|
||||||
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
||||||
T.putStrLn $ toText abortReason
|
T.putStrLn $ toText abortReason
|
||||||
pure finalState
|
pure finalState
|
||||||
Just n -> do
|
Just n -> do
|
||||||
let (finalState, mAbortReason, stepsMade) = executeN n initialState
|
let (finalState, mAbortReason, stepsMade) = executeN n mempty initialState
|
||||||
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
putStrLn $ "Stopped after " ++ show stepsMade ++ " steps, reason:"
|
||||||
case mAbortReason of
|
case mAbortReason of
|
||||||
Nothing -> putStrLn "Ran out of steps"
|
Nothing -> putStrLn "Ran out of steps"
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,16 @@ module Mima.Vm.State
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.Trans.Class
|
||||||
|
import Control.Monad.Trans.Reader
|
||||||
import Data.Binary
|
import Data.Binary
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
|
||||||
import Mima.Format
|
import Mima.Format
|
||||||
|
import Mima.Vm.Flags
|
||||||
import Mima.Vm.Instruction
|
import Mima.Vm.Instruction
|
||||||
import Mima.Vm.Memory
|
import Mima.Vm.Memory
|
||||||
import Mima.Vm.Word
|
import Mima.Vm.Word
|
||||||
|
|
@ -80,6 +84,7 @@ data AbortReason
|
||||||
| InvalidNextIarAddress
|
| InvalidNextIarAddress
|
||||||
| AddressNotExecutable
|
| AddressNotExecutable
|
||||||
| AddressReadOnly
|
| AddressReadOnly
|
||||||
|
| BreakpointAtAddress
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
instance ToText AbortReason where
|
instance ToText AbortReason where
|
||||||
|
|
@ -88,14 +93,16 @@ instance ToText AbortReason where
|
||||||
toText InvalidNextIarAddress = "Exception: Can't increment IAR: Invalid next address"
|
toText InvalidNextIarAddress = "Exception: Can't increment IAR: Invalid next address"
|
||||||
toText AddressNotExecutable = "Exception: Address is not flagged as excutable"
|
toText AddressNotExecutable = "Exception: Address is not flagged as excutable"
|
||||||
toText AddressReadOnly = "Exception: Address is flagged as read-only"
|
toText AddressReadOnly = "Exception: Address is flagged as read-only"
|
||||||
|
toText BreakpointAtAddress = "Breakpoint hit"
|
||||||
|
|
||||||
{- A fancy monad that helps with stepping the MimaState -}
|
type Execution = ReaderT Flags (Either AbortReason)
|
||||||
|
|
||||||
type Execution a = Either AbortReason a
|
throw :: AbortReason -> Execution a
|
||||||
|
throw = lift . Left
|
||||||
|
|
||||||
incrementIar :: MimaState -> Execution MimaState
|
incrementIar :: MimaState -> Execution MimaState
|
||||||
incrementIar ms
|
incrementIar ms
|
||||||
| addr >= maxBound = Left InvalidNextIarAddress
|
| addr >= maxBound = throw InvalidNextIarAddress
|
||||||
| otherwise = pure ms{msIar = succ addr}
|
| otherwise = pure ms{msIar = succ addr}
|
||||||
where
|
where
|
||||||
addr = msIar ms
|
addr = msIar ms
|
||||||
|
|
@ -104,10 +111,13 @@ decodeInstruction :: MimaWord -> Execution Instruction
|
||||||
decodeInstruction word =
|
decodeInstruction word =
|
||||||
case wordToInstruction word of
|
case wordToInstruction word of
|
||||||
Right instruction -> pure instruction
|
Right instruction -> pure instruction
|
||||||
Left errorMsg -> Left $ InvalidInstruction errorMsg
|
Left errorMsg -> throw $ InvalidInstruction errorMsg
|
||||||
|
|
||||||
storeValue :: MimaAddress -> MimaState -> Execution MimaState
|
storeValue :: MimaAddress -> MimaState -> Execution MimaState
|
||||||
storeValue addr ms = pure ms{msMemory = writeAt addr (msAcc ms) (msMemory ms)}
|
storeValue addr ms = do
|
||||||
|
flags <- ask
|
||||||
|
when (readonlyAt flags addr) $ throw AddressReadOnly
|
||||||
|
pure ms{msMemory = writeAt addr (msAcc ms) (msMemory ms)}
|
||||||
|
|
||||||
loadValue :: MimaAddress -> MimaState -> Execution MimaState
|
loadValue :: MimaAddress -> MimaState -> Execution MimaState
|
||||||
loadValue addr ms = pure ms{msAcc = readAt addr (msMemory ms)}
|
loadValue addr ms = pure ms{msAcc = readAt addr (msMemory ms)}
|
||||||
|
|
@ -132,7 +142,7 @@ doSmallOpcode CALL addr ms@MimaState{..} = pure ms{msRa = msIar, msIar = addr}
|
||||||
doSmallOpcode ADC lv ms@MimaState{..} = pure ms{msAcc = msAcc + signedLargeValueToWord lv}
|
doSmallOpcode ADC lv ms@MimaState{..} = pure ms{msAcc = msAcc + signedLargeValueToWord lv}
|
||||||
|
|
||||||
doLargeOpcode :: LargeOpcode -> SmallValue -> MimaState -> Execution MimaState
|
doLargeOpcode :: LargeOpcode -> SmallValue -> MimaState -> Execution MimaState
|
||||||
doLargeOpcode HALT _ _ = Left Halted
|
doLargeOpcode HALT _ _ = throw Halted
|
||||||
doLargeOpcode NOT _ ms@MimaState{..} = pure ms{msAcc = complement msAcc}
|
doLargeOpcode NOT _ ms@MimaState{..} = pure ms{msAcc = complement msAcc}
|
||||||
doLargeOpcode RAR _ ms@MimaState{..} = pure ms{msAcc = rotateR msAcc 1}
|
doLargeOpcode RAR _ ms@MimaState{..} = pure ms{msAcc = rotateR msAcc 1}
|
||||||
doLargeOpcode RET _ ms@MimaState{..} = pure ms{msIar = msRa}
|
doLargeOpcode RET _ ms@MimaState{..} = pure ms{msIar = msRa}
|
||||||
|
|
@ -147,30 +157,34 @@ doLargeOpcode STRS sv ms@MimaState{..} = storeValue (msSp + signedSmallValueToLa
|
||||||
doLargeOpcode LDRF sv ms@MimaState{..} = loadValue (msFp + signedSmallValueToLargeValue sv) ms
|
doLargeOpcode LDRF sv ms@MimaState{..} = loadValue (msFp + signedSmallValueToLargeValue sv) ms
|
||||||
doLargeOpcode STRF sv ms@MimaState{..} = storeValue (msFp + signedSmallValueToLargeValue sv) ms
|
doLargeOpcode STRF sv ms@MimaState{..} = storeValue (msFp + signedSmallValueToLargeValue sv) ms
|
||||||
|
|
||||||
step :: MimaState -> Execution MimaState
|
step :: Flags -> MimaState -> Either AbortReason MimaState
|
||||||
step ms = do
|
step flags ms = flip runReaderT flags $ do
|
||||||
let addr = msIar ms
|
let addr = msIar ms
|
||||||
word = readAt addr (msMemory ms)
|
when (breakpointAt flags addr) $ throw BreakpointAtAddress
|
||||||
|
unless (executableAt flags addr) $ throw AddressNotExecutable
|
||||||
|
|
||||||
|
let word = readAt addr (msMemory ms)
|
||||||
instruction <- decodeInstruction word
|
instruction <- decodeInstruction word
|
||||||
|
|
||||||
ms' <- incrementIar ms
|
ms' <- incrementIar ms
|
||||||
case instruction of
|
case instruction of
|
||||||
(SmallInstruction so lv) -> doSmallOpcode so lv ms'
|
(SmallInstruction so lv) -> doSmallOpcode so lv ms'
|
||||||
(LargeInstruction lo sv) -> doLargeOpcode lo sv ms'
|
(LargeInstruction lo sv) -> doLargeOpcode lo sv ms'
|
||||||
|
|
||||||
execute :: MimaState -> (MimaState, AbortReason, Integer)
|
execute :: Flags -> MimaState -> (MimaState, AbortReason, Integer)
|
||||||
execute = helper 0
|
execute flags = helper 0
|
||||||
where
|
where
|
||||||
helper completed s =
|
helper completed s =
|
||||||
case step s of
|
case step flags s of
|
||||||
Left e -> (s, e, completed)
|
Left e -> (s, e, completed)
|
||||||
Right s' -> helper (completed + 1) s'
|
Right s' -> helper (completed + 1) s'
|
||||||
|
|
||||||
executeN :: Integer -> MimaState -> (MimaState, Maybe AbortReason, Integer)
|
executeN :: Integer -> Flags -> MimaState -> (MimaState, Maybe AbortReason, Integer)
|
||||||
executeN n = helper 0
|
executeN n flags = helper 0
|
||||||
where
|
where
|
||||||
helper completed s =
|
helper completed s =
|
||||||
if completed >= n
|
if completed >= n
|
||||||
then (s, Nothing, completed)
|
then (s, Nothing, completed)
|
||||||
else case step s of
|
else case step flags s of
|
||||||
Left e -> (s, Just e, completed)
|
Left e -> (s, Just e, completed)
|
||||||
Right s' -> helper (completed + 1) s'
|
Right s' -> helper (completed + 1) s'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue