Do more state formatting

Registers can now be displayed above the memory content.
This commit is contained in:
Joscha 2019-11-19 16:50:37 +00:00
parent ee7639c1c7
commit a7ef16bc4e
5 changed files with 75 additions and 143 deletions

View file

@ -146,7 +146,7 @@ main :: IO ()
main = doRun_ $ do main = doRun_ $ do
settings <- lift $ execParser opts settings <- lift $ execParser opts
lift $ putStrLn $ "Loading memdump at " ++ infile settings lift $ putStrLn $ "Loading memdump from " ++ infile settings
ms <- loadStateFromFile (infile settings) ms <- loadStateFromFile (infile settings)
flags <- loadFlags settings flags <- loadFlags settings
@ -156,7 +156,7 @@ main = doRun_ $ do
then pure ms then pure ms
else lift $ runMima settings ms flags else lift $ runMima settings ms flags
unless (quiet settings) $ printState ms flags labels settings unless (quiet settings) $ printState ms' flags labels settings
forM_ (outfile settings) $ \path -> do forM_ (outfile settings) $ \path -> do
lift $ putStrLn $ "Saving memdump at " ++ path lift $ putStrLn $ "Saving memdump at " ++ path

View file

@ -1,124 +0,0 @@
{-# LANGUAGE MultiWayIf #-}
module PrintState
( printStateLn
) where
import Control.Monad
import Data.Bits
import qualified Data.Text as T
import qualified Data.Text.IO as T
import System.Console.ANSI
import Mima.Format.Common
import Mima.Instruction
import Mima.State
import Mima.Util
import Mima.Word
printAddress :: Int -> MimaAddress -> IO ()
printAddress n addr = do
T.putStr $ toHex addr
putStr " ("
T.putStr $ T.justifyRight n ' ' $ toDec addr
putStr ")"
printWord :: Int -> MimaWord -> IO ()
printWord n word = do
T.putStr $ toHex word
putStr " ("
T.putStr $ T.justifyRight n ' ' $ toDec word
putStr ")"
-- Color scheme:
-- Red: HALT
-- Yellow: Instructions for accessing other registers
-- Green: Instructions that can modify the IAR (jumps)
-- Blue: Instructions that read from or write to memory
-- Cyan: Logical operations and calculations that modify the ACC
printInstruction :: Instruction -> IO ()
printInstruction (SmallInstruction so lv) = do
setSGR [SetConsoleIntensity BoldIntensity]
if | so `elem` [JMP, JMN, CALL] -> setSGR [SetColor Foreground Dull Green]
| so `elem` [LDC, LDV, STV, LDIV, STIV] -> setSGR [SetColor Foreground Vivid Blue]
| so `elem` [ADD, AND, OR, XOR, EQL, ADC] -> setSGR [SetColor Foreground Vivid Cyan]
| otherwise -> pure ()
T.putStr $ toText so
putStr " "
setSGR [SetColor Foreground Vivid Black]
T.putStr $ toDec lv
setSGR []
printInstruction (LargeInstruction lo sv) = do
setSGR [SetConsoleIntensity BoldIntensity]
if | lo == HALT -> setSGR [SetColor Foreground Vivid Red]
| lo `elem` [LDRA, STRA, LDSP, STSP, LDFP, STFP] -> setSGR [SetColor Foreground Dull Yellow]
| lo == RET -> setSGR [SetColor Foreground Dull Green]
| lo `elem` [LDRS, STRS, LDRF, STRF] -> setSGR [SetColor Foreground Vivid Blue]
| lo `elem` [NOT, RAR] -> setSGR [SetColor Foreground Vivid Cyan]
| otherwise -> pure ()
T.putStr $ toText lo
when (lo `elem` [LDRS, STRS, LDRF, STRF] || sv /= zeroBits) $ do
putStr " "
setSGR [SetColor Foreground Vivid Black]
T.putStr $ toDec sv
setSGR []
printWordWithInstruction :: Int -> MimaWord -> IO ()
printWordWithInstruction n word = do
printWord n word
case wordToInstruction word of
Left _ -> pure ()
Right i -> do
putStr ": "
printInstruction i
printAddressRegister :: MimaState -> MimaAddress -> IO ()
printAddressRegister ms addr = do
printAddress 8 addr
putStr " -> "
printWordWithInstruction 8 $ readAt addr $ msMemory ms
printRegistersLn :: MimaState -> IO ()
printRegistersLn ms = do
putStr "IAR: "
printAddressRegister ms $ msIAR ms
putStrLn ""
putStr "ACC: "
printWord 8 $ msACC ms
putStrLn ""
putStr " RA: "
printAddressRegister ms $ msRA ms
putStrLn ""
putStr " SP: "
printAddressRegister ms $ msSP ms
putStrLn ""
putStr " FP: "
printAddressRegister ms $ msFP ms
putStrLn ""
printMemoryLocationLn :: MimaAddress -> MimaWord -> IO ()
printMemoryLocationLn addr word = do
printAddress 7 addr
putStr " -> "
printWord 8 word
case wordToInstruction word of
Left _ -> pure ()
Right i -> do
putStr ": "
printInstruction i
putStrLn ""
printMemoryLn :: Bool -> MimaMemory -> IO ()
printMemoryLn sparse mem = do
let addresses = if sparse then sparseUsedAddresses mem else usedAddresses mem
forM_ addresses $ \addr -> do
printMemoryLocationLn addr (readAt addr mem)
printStateLn :: Bool -> MimaState -> IO ()
printStateLn sparse ms = do
printRegistersLn ms
printMemoryLn sparse $ msMemory ms

View file

@ -13,6 +13,10 @@ module Mima.Format.State
, fAddress , fAddress
-- * Words -- * Words
, fWord , fWord
-- * Memory
, fMemory
-- * Registers
, fRegisters
-- * The whole state -- * The whole state
, formatState , formatState
) where ) where
@ -30,8 +34,9 @@ import Mima.Word
data FormatConfig = FormatConfig data FormatConfig = FormatConfig
{ fcSparse :: Bool { fcSparse :: Bool
, fcShowRegisterFlags :: Bool , fcShowRegisters :: Bool
, fcShowMemoryFlags :: Bool , fcShowMemoryFlags :: Bool
, fcShowRegisterFlags :: Bool
, fcShowAddressDec :: Bool , fcShowAddressDec :: Bool
, fcShowAddressHex :: Bool , fcShowAddressHex :: Bool
, fcShowAddressBin :: Bool , fcShowAddressBin :: Bool
@ -108,7 +113,7 @@ fAddress a = do
hex = if fcShowAddressHex conf then [fAddressHex] else [] hex = if fcShowAddressHex conf then [fAddressHex] else []
bin = if fcShowAddressBin conf then [fAddressBin] else [] bin = if fcShowAddressBin conf then [fAddressBin] else []
formats = (dec ++ hex ++ bin) <*> pure a formats = (dec ++ hex ++ bin) <*> pure a
pure $ "[" <> T.intercalate "," formats <> "]" pure $ "[" <> T.intercalate ", " formats <> "]"
{- Words -} {- Words -}
@ -129,7 +134,7 @@ fWord a = do
hex = if fcShowWordHex conf then [fWordHex] else [] hex = if fcShowWordHex conf then [fWordHex] else []
bin = if fcShowWordBin conf then [fWordBin] else [] bin = if fcShowWordBin conf then [fWordBin] else []
formats = (dec ++ hex ++ bin) <*> pure a formats = (dec ++ hex ++ bin) <*> pure a
pure $ "{" <> T.intercalate "," formats <> "}" pure $ "{" <> T.intercalate ", " formats <> "}"
{- Memory -} {- Memory -}
@ -143,18 +148,65 @@ fMemoryLn a = do
word <- fWord w word <- fWord w
pure $ flags <> " " <> addr <> " " <> word <> "\n" pure $ flags <> " " <> addr <> " " <> word <> "\n"
fMemory :: Formatter interestingAddresses :: FormatReader (Set.Set MimaAddress)
fMemory = do interestingAddresses = do
env <- ask
let conf = feConf env
s = feState env
pure $ if fcShowRegisterFlags conf
then Set.fromList [msIAR s, msRA s, msSP s, msFP s]
else Set.empty
getAddresses :: FormatReader [MimaAddress]
getAddresses = do
env <- ask env <- ask
let conf = feConf env let conf = feConf env
mem = msMemory $ feState env mem = msMemory $ feState env
addrs = if fcSparse conf then sparseUsedAddresses mem else usedAddresses mem if fcSparse conf
then do
interesting <- interestingAddresses
pure $ Set.toAscList $ Set.union interesting $ Set.fromList $ usedAddresses mem
else pure $ usedAddresses mem
fMemory :: Formatter
fMemory = do
addrs <- getAddresses
mconcat <$> mapM fMemoryLn addrs mconcat <$> mapM fMemoryLn addrs
{- Registers -}
fAddressRegister :: T.Text -> MimaAddress -> Formatter
fAddressRegister name addr = do
addrText <- fAddress addr
pure $ name <> ": " <> addrText <> "\n"
fWordRegister :: T.Text -> MimaWord -> Formatter
fWordRegister name word = do
wordText <- fWord word
pure $ name <> ": " <> wordText <> "\n"
fRegisters :: Formatter
fRegisters = do
env <- ask
let s = feState env
mconcat <$> sequenceA [ fAddressRegister "IAR" (msIAR s)
, fWordRegister "ACC" (msACC s)
, fAddressRegister " RA" (msRA s)
, fAddressRegister " SP" (msSP s)
, fAddressRegister " FP" (msFP s)
]
{- And finally, the whole state -} {- And finally, the whole state -}
fState :: Formatter fState :: Formatter
fState = fMemory fState = do
env <- ask
let conf = feConf env
memText <- ("--< MEMORY >--\n" <>) <$> fMemory
regText <- ("--< REGISTERS >--\n" <>) <$> fRegisters
pure $ if fcShowRegisters conf
then regText <> memText
else memText
formatState :: FormatEnv -> T.Text formatState :: FormatEnv -> T.Text
formatState = runReader fState formatState = runReader fState

View file

@ -36,10 +36,12 @@ formatConfigParser :: Parser FormatConfig
formatConfigParser = FormatConfig formatConfigParser = FormatConfig
<$> hiddenSwitchWithNo "sparse" True <$> hiddenSwitchWithNo "sparse" True
"Omit uninteresting addresses" "Omit uninteresting addresses"
<*> hiddenSwitchWithNo "registers" True
"Show the contents of registers before the memory dump"
<*> hiddenSwitchWithNo "memory-flags" False
"For each address, show all registers currently pointing to that address"
<*> hiddenSwitchWithNo "register-flags" True <*> hiddenSwitchWithNo "register-flags" True
"For each address, show all the memory flags that are active for that address" "For each address, show all the memory flags that are active for that address"
<*> hiddenSwitchWithNo "memory-flags" True
"For each address, show all registers currently pointing to that address"
<*> hiddenSwitchWithNo "address-dec" True <*> hiddenSwitchWithNo "address-dec" True
"Display addresses in decimal" "Display addresses in decimal"
<*> hiddenSwitchWithNo "address-hex" True <*> hiddenSwitchWithNo "address-hex" True

View file

@ -6,8 +6,9 @@ module Mima.State
, mapToMemory , mapToMemory
, wordsToMemory , wordsToMemory
, memoryToWords , memoryToWords
, maxAddress
, usedAddresses , usedAddresses
, sparseUsedAddresses , continuousUsedAddresses
, readAt , readAt
, writeAt , writeAt
, MimaState(..) , MimaState(..)
@ -24,6 +25,7 @@ import Control.Monad.Trans.Except
import Control.Monad.Trans.Reader import Control.Monad.Trans.Reader
import Data.Bits import Data.Bits
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Data.Maybe
import qualified Data.Text as T import qualified Data.Text as T
import Mima.Flag import Mima.Flag
@ -43,16 +45,16 @@ wordsToMemory = mapToMemory
. zip [minBound..] . zip [minBound..]
memoryToWords :: MimaMemory -> [MimaWord] memoryToWords :: MimaMemory -> [MimaWord]
memoryToWords mem = map (\addr -> readAt addr mem) $ usedAddresses mem memoryToWords mem = map (\addr -> readAt addr mem) $ continuousUsedAddresses mem
maxAddress :: MimaMemory -> MimaAddress
maxAddress (MimaMemory m) = fromMaybe minBound $ fst <$> Map.lookupMax m
usedAddresses :: MimaMemory -> [MimaAddress] usedAddresses :: MimaMemory -> [MimaAddress]
usedAddresses (MimaMemory m) = usedAddresses (MimaMemory m) = Map.keys m
case fst <$> Map.lookupMax m of
Nothing -> []
Just maxAddr -> [minBound..maxAddr]
sparseUsedAddresses :: MimaMemory -> [MimaAddress] continuousUsedAddresses :: MimaMemory -> [MimaAddress]
sparseUsedAddresses (MimaMemory m) = Map.keys m continuousUsedAddresses mem = [minBound..maxAddress mem]
readAt :: MimaAddress -> MimaMemory -> MimaWord readAt :: MimaAddress -> MimaMemory -> MimaWord
readAt addr (MimaMemory m) = Map.findWithDefault zeroBits addr m readAt addr (MimaMemory m) = Map.findWithDefault zeroBits addr m