module Language.ArrayForth.Opcode where
import Data.List (elemIndex)
import Data.Word.Odd (Word18)
import Language.ArrayForth.Parse (ParseError (..))
type F18Word = Word18
data Opcode = Ret
| Exec
| Jmp
| Call
| Unext
| Next
| If
| MinusIf
| FetchP
| FetchPlus
| FetchB
| Fetch
| StoreP
| StorePlus
| StoreB
| Store
| MultiplyStep
| Times2
| Div2
| Not
| Plus
| And
| Or
| Drop
| Dup
| Pop
| Over
| ReadA
| Nop
| Push
| SetB
| SetA
deriving (Eq, Bounded, Enum)
names :: [String]
names = [";", "ex", "jump", "call", "unext", "next", "if", "-if", "@p", "@+", "@b", "@",
"!p", "!+", "!b", "!", "+*", "2*", "2/", "-", "+", "and", "or", "drop", "dup",
"pop", "over", "a", ".", "push", "b!", "a!"]
opcodes :: [Opcode]
opcodes = [minBound..maxBound]
instance Show Opcode where show op = names !! fromEnum op
readOpcode :: String -> Either ParseError Opcode
readOpcode token = case elemIndex token names of
Just res -> Right $ toEnum res
Nothing -> Left $ BadOpcode token
instance Read Opcode where readsPrec _ str = case readOpcode str of
Left err -> error $ show err
Right r -> [(r, "")]
toOpcode :: F18Word -> Opcode
toOpcode = toEnum . fromIntegral
fromOpcode :: Opcode -> F18Word
fromOpcode = fromIntegral . fromEnum
isJump :: Opcode -> Bool
isJump = (`elem` [Jmp, Call, Next, If, MinusIf])
slot3 :: Opcode -> Bool
slot3 = (`elem` [Ret, MultiplyStep, Unext, Plus, FetchP, Dup, StoreP, Nop])
opcodeTime :: Opcode -> Double
opcodeTime op = if memoryOp op then 5 else 1.5
where memoryOp = (`elem` [FetchP, FetchPlus, FetchB, Fetch, StoreP,
StorePlus, StoreB, Store])