libriscv-0.1.0.0: lib/LibRISCV/Effects/Operations/Default/Machine/Register.hs
{-# LANGUAGE FlexibleContexts #-}
-- | Provides a polymorphic implementation of a register file. This module is
-- intended to be used internally by interpreters for the
-- 'LibRISCV.Effects.Operations.Operations' effect. This register file
-- implementation also provides facilities for storing a concrete program
-- counter.
module LibRISCV.Effects.Operations.Default.Machine.Register where
import Control.Monad (unless)
import Data.Array.IO (
MArray (newArray),
getElems,
readArray,
writeArray,
)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Word (Word32)
import LibRISCV
-- | Register file addressed by 'RegIdx'. The type is parameterized over an array
-- implementation (such as 'Data.Array.IO.IOUArray') and a generic value type
-- (used to represent instruction operands).
data RegisterFile t a = RegisterFile
{ pc :: IORef Word32
-- ^ The current program counter (always concrete in this implementation).
, regs :: t RegIdx a
-- ^ The underlying array to store the register values.
}
-- | Create a new register file, initializing all registers with the given default
-- value. This value /must/ represent the zero value in the chosen value type.
mkRegFile :: (MArray t a IO) => a -> IO (RegisterFile t a)
mkRegFile defValue = RegisterFile <$> newIORef 0 <*> newArray (minBound, maxBound) defValue
-- | Dump the current register file state as a 'String'.
dumpRegs :: (MArray t a IO) => (a -> ShowS) -> RegisterFile t a -> IO String
dumpRegs sh =
fmap
( foldr (\(a, v) s -> show a ++ "\t= 0x" ++ sh v "\n" ++ s) ""
. zip [(minBound :: RegIdx) .. maxBound]
)
. getElems
. regs
------------------------------------------------------------------------
-- | Read register value at given register index. For the 'Zero' register index, the
-- zero/default value (as passed to 'mkRegFile' is always returned.
readRegister :: (MArray t a IO) => RegisterFile t a -> RegIdx -> IO a
readRegister = readArray . regs
-- | Write register at given register index. Writes to the 'Zero' register are ignored.
writeRegister :: (MArray t a IO) => RegisterFile t a -> RegIdx -> a -> IO ()
writeRegister RegisterFile{regs = r} idx val = unless (idx == Zero) $ writeArray r idx val
------------------------------------------------------------------------
-- | Returs the current program counter value.
readPC :: RegisterFile t a -> IO Word32
readPC = readIORef . pc
-- | Write a new program counter value.
writePC :: RegisterFile t a -> Word32 -> IO ()
writePC = writeIORef . pc