-- | General tools for PowerPC programs. module Language.PowerPC.Simulator ( simulate ) where import Control.Monad import Data.Bits import qualified Data.IntMap as M import Text.Printf import Language.PowerPC.Syntax data Machine = Machine { program :: M.IntMap Instruction , pc :: Int , lr :: Int , ctr :: Int , gprs :: [Int] , xer :: Int } instance Show Machine where show m = printf "program counter = 0x%08X\n" $ pc m simulate :: Int -> Int -> Program -> IO () simulate base start p = loop Machine { program = M.fromList $ zip [base, base + 4 ..] p , pc = start , lr = 0 , ctr = 0 , gprs = replicate 32 0 , xer = 0 } where loop :: Machine -> IO () loop m = when (not $ done m) $ do printf "program counter = 0x%08X\n" $ pc m loop $ step m done :: Machine -> Bool done m | pc m < base || pc m > base + (length p + 1) * 4 = error $ printf "program counter out of range: 0x%08X" $ pc m | otherwise = pc m == base + length p * 4 step :: Machine -> Machine step m = case program m M.! pc m of ADDI d GPR0 i -> set d i n ADDI d a i -> set d (r a + i) n B a -> m { pc = pc m + a } BA a -> m { pc = a } BL a -> m { pc = pc m + a, lr = pc m + 4 } BLA a -> m { pc = a, lr = pc m + 4 } MTSPR a CTR -> n { ctr = r a } MTSPR a LR -> n { lr = r a } MTSPR a XER -> n { xer = r a } MTSPR _ SRInvalid -> n Unknown a b c -> error $ printf "unknown instruction: address: 0x%08X instruction: 0x%08X opcode: %d extended opcode: %d" (pc m) a b c where n = m { pc = pc m + 4 } r :: GPR -> Int r a = gprs m !! gprIndex a set :: GPR -> Int -> Machine -> Machine set r v m = m { gprs = replace (gprIndex r) v (gprs m) } replace :: Int -> a -> [a] -> [a] replace _ a [] = [a] replace i a (b:c) | i <= 0 = a : c | otherwise = b : replace (i - 1) a c