{-# OPTIONS -Wall #-} module Language.Pck.Cpu.State ( -- * Evaluation monad (State monad) EvalCpu -- * Cpu state type , CpuState , pcFromCpuState , grFromCpuState , flFromCpuState , imemFromCpuState , dmemFromCpuState , dumpCpuState , initCpuState , initCpuStateMem -- * Result type , ResultStat(..) -- * access for the Cpu state -- ** PC(program counter) , readPc , updatePc , incPc -- ** General purpose registers , readGReg , readGReg2 , updateGReg -- ** Flags , readFlags , updateFlag -- ** Instruction memory , fetchInst -- ** Data memory , readDmem , updateDmem ) where import Control.Monad.State import Language.Pck.Cpu.Config import Language.Pck.Cpu.Instruction import Language.Pck.Cpu.Register import Language.Pck.Cpu.Memory ---------------------------------------- -- cpu state monad ---------------------------------------- -- | the cpu eval monad type EvalCpu a = State CpuState a -- | the result state data ResultStat = RsNormal -- ^ normal result | RsHalt -- ^ cpu halt(stop) | RsDbgBrk -- ^ debugger triggered | RsErr String -- ^ execution error deriving (Show, Eq) ---------------------------------------- -- cpu state type ---------------------------------------- -- | the cpu state (processor internal state) -- -- This is the result type from 'Language.Pck.Cpu.run' function. -- -- get each values by 'pcFromCpuState', 'grFromCpuState', 'flFromCpuState', -- 'imemFromCpuState', 'dmemFromCpuState', 'dumpCpuState' data CpuState = CpuState { state_pc :: Int , state_gr :: GRegArray , state_fl :: FlagArray , state_imem :: ImemArray , state_dmem :: DmemArray } deriving Eq -- accessor -- | -- > > pcFromCpuState $ run [(0,[MOVI R0 7, HALT])] [] -- > 1 -- pcFromCpuState :: CpuState -> Int pcFromCpuState = state_pc -- | -- > > grFromCpuState $ run [(0,[MOVI R0 7, HALT])] [] -- > [7,0,0,0,0,0,0,0] -- grFromCpuState :: CpuState -> [Int] grFromCpuState = getGRegs . state_gr -- | -- > > flFromCpuState $ run [(0,[MOVI R0 7, HALT])] [] -- > [False,False] -- flFromCpuState :: CpuState -> [Bool] flFromCpuState = getFlags . state_fl -- | -- > > imemFromCpuState $ run [(0,[MOVI R0 7, HALT])] [] -- > [(0,[MOVI R0 7,HALT,UNDEF,UNDEF,...])] -- imemFromCpuState :: CpuState -> InstImage imemFromCpuState = getInstImage . state_imem -- | -- > > dmemFromCpuState $ run [(0,[MOVI R0 0, MOVI R1 10, ST R0 R1, HALT])] [] -- > [(0,[10,0,0,0,0,...])] -- dmemFromCpuState :: CpuState -> DataImage dmemFromCpuState = getDataImage . state_dmem -- show instance Show CpuState where show = showCpuState showCpuState :: CpuState -> String showCpuState s = "pc : " ++ show (pcFromCpuState s) ++ "\ngr : " ++ show (grFromCpuState s) ++ "\nfl : " ++ show (flFromCpuState s) ++ "\nim : " ++ show (imemFromCpuState s) ++ "\ndm : " ++ show (dmemFromCpuState s) ++ "\n" -- | dump Cpu state (without instruction image) -- -- > > putStr $ dumpCpuState $ run [(0,[MOVI R0 7, HALT])] [] -- > pc : 1 -- > gr : [7,0,0,0,0,0,0,0] -- > fl : [False,False] -- > dm : [(0,[7,0,0,0,0,...])] -- dumpCpuState :: CpuState -> String dumpCpuState s = "pc : " ++ show (pcFromCpuState s) ++ "\ngr : " ++ show (grFromCpuState s) ++ "\nfl : " ++ show (flFromCpuState s) ++ "\ndm : " ++ show (dmemFromCpuState s) ++ "\n" ---------------------------------------- -- initial state ---------------------------------------- -- | a default CpuState initCpuState :: CpuState initCpuState = CpuState { state_pc = cfgStartPc cpuConfig , state_gr = initGReg , state_fl = initFlag , state_imem = initImem , state_dmem = initDmem } -- | initialize CpuState by inst and data image initCpuStateMem :: InstImage -> DataImage -> CpuState initCpuStateMem insts vals = initCpuState {state_imem = presetImem insts ,state_dmem = presetDmem vals} ---------------------------------------- -- state utility ---------------------------------------- -- | read the pc readPc :: EvalCpu Int readPc = gets state_pc -- | update the pc -- -- Example: -- -- > jumpRI :: Int -> EvalCpu ResultStat -- > jumpRI ad = do pc <- readPc -- > updatePc (pc + ad) -- updatePc :: Int -> EvalCpu ResultStat updatePc pc = do modify $ \s -> s { state_pc = pc } return RsNormal -- | increment the pc incPc :: EvalCpu ResultStat incPc = do pc <- readPc updatePc (pc + 1) -- | read a general purpose register -- -- Example: -- -- > jump :: GReg -> EvalCpu ResultStat -- > jump reg = do ad <- readGReg reg -- > updatePc ad -- readGReg :: GReg -> EvalCpu Int readGReg ra = do gr <- gets state_gr return $ getGReg gr ra -- | read general purpose register pair readGReg2 :: GReg -> GReg -> EvalCpu (Int, Int) readGReg2 ra rb = do gr <- gets state_gr return (getGReg gr ra, getGReg gr rb) -- | update a general purpose register -- -- Example: -- -- > movpc :: GReg -> EvalCpu ResultStat -- > movpc reg = do pc <- readPc -- > updateGReg reg pc -- updateGReg :: GReg -> Int -> EvalCpu () updateGReg reg val = do cpu <- get let gr' = modifyGReg (state_gr cpu) reg val put cpu { state_gr = gr' } -- | read flag registers -- -- Example: -- -- > branchRI :: FCond -> Int -> EvalCpu ResultStat -- > branchRI fcond ad = do flags <- readFlags -- > if judgeFCond flags fcond -- > then jumpRI ad -- > else incPc -- readFlags :: EvalCpu FlagArray readFlags = gets state_fl -- | update a flag -- -- Example: -- -- > cmpRR :: GReg -> GReg -> EvalCpu ResultStat -- > cmpRR ra rb = do (ra', rb') <- readGReg2 ra rb -- > updateFlag FLZ (ra' == rb') -- > updateFlag FLC (ra' < rb') -- updateFlag :: Flag -> Bool -> EvalCpu () updateFlag flag val = do cpu <- get let flags = state_fl cpu fl' = modifyFlag flags flag val put cpu { state_fl = fl' } -- | fetch an instruction from the instruction memory fetchInst :: EvalCpu Inst fetchInst = do imem <- gets state_imem pc <- readPc return $ fetchImem imem pc -- | read a data value from the data memory -- -- Example: -- -- > load :: GReg -> GReg -> EvalCpu ResultStat -- > load ra rb = do rb' <- readGReg rb -- > ra' <- readDmem rb' -- > updateGReg ra ra' -- readDmem :: Int -> EvalCpu Int readDmem ad = do cpu <- get return $ getDmem (state_dmem cpu) ad -- | update the data memory -- -- Example: -- -- > store :: GReg -> GReg -> EvalCpu ResultStat -- > store ra rb = do (ra', rb') <- readGReg2 ra rb -- > updateDmem ra' rb' -- updateDmem :: Int -> Int -> EvalCpu () updateDmem ad val = do cpu <- get let dmem' = modifyDmem (state_dmem cpu) ad val put cpu { state_dmem = dmem' }