packages feed

libriscv-0.1.0.0: lib/LibRISCV/Effects/Decoding/Default/Interpreter.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}

-- | Provides the default (concrete) interpretation for the decoding effect. This
-- implementation assumes that the 'Decodable' type class can be implemented for
-- the underlying type parameter, that is, it must be possible to convert the
-- type to a fixed-width concrete integer.
module LibRISCV.Effects.Decoding.Default.Interpreter where

import Control.Monad.Freer (type (~>))
import Control.Monad.IO.Class (MonadIO (liftIO))
import Data.BitVector (BV, bitVec)
import Data.Data (Proxy (..))
import Data.IORef (IORef, readIORef, writeIORef)
import Data.Word (Word32)
import LibRISCV.Effects.Decoding.Language (Decoding (..))
import LibRISCV.Internal.Decoder.Instruction (immB, immI, immJ, immS, immU, mkRd, mkRs1, mkRs2, mkShamt)
import LibRISCV.Internal.Decoder.Opcodes (decode)

-- | Decoder state used to implement the stateful 'SetInstr' constructor of the 'Decoding' effect.
type DecoderState = IORef Word32

-- | Type class used to perform conversion from/to a fixed-with concrete integer.
class Decodable a where
    fromWord :: Word32 -> a
    -- ^ Convert from a fixed-with integer to the underlying value type of the interpreter.

    toWord :: a -> Word32
    -- ^ Convert from the underlying value type to a fixed-with integer.

instance Decodable BV where
    fromWord = bitVec 32
    toWord = fromIntegral

-- | Concrete implementation of the decoding effect.
defaultDecoding :: forall v m. (Decodable v, MonadIO m) => DecoderState -> Decoding v ~> m
defaultDecoding instRef =
    let
        decodeAndConvert f = fmap (fromWord . f) . readIORef
     in
        liftIO . \case
            SetInstr v -> writeIORef instRef $ toWord v
            WithInstrType Proxy f -> f . decode <$> readIORef instRef
            DecodeRD -> decodeAndConvert mkRd instRef
            DecodeRS1 -> decodeAndConvert mkRs1 instRef
            DecodeRS2 -> decodeAndConvert mkRs2 instRef
            DecodeImmI -> decodeAndConvert immI instRef
            DecodeImmS -> decodeAndConvert immS instRef
            DecodeImmB -> decodeAndConvert immB instRef
            DecodeImmU -> decodeAndConvert immU instRef
            DecodeImmJ -> decodeAndConvert immJ instRef
            DecodeShamt -> decodeAndConvert mkShamt instRef