packages feed

libriscv-0.1.0.0: lib/LibRISCV/Semantics/Utils.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

module LibRISCV.Semantics.Utils where

import Control.Applicative
import Control.Monad.Freer
import LibRISCV.Effects.Decoding.Language
import LibRISCV.Effects.Expressions.Expr
import LibRISCV.Effects.Expressions.Language
import LibRISCV.Effects.Operations.Language
import qualified LibRISCV.Effects.Operations.Language as Op

-- TODO add newTypes for type safety
-- decode and read register
decodeAndReadIType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v, v)
decodeAndReadIType = liftA3 (,,) (decodeRS1 >>= Op.readRegister) decodeRD decodeImmI

-- decode and read register
decodeAndReadBType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v, v)
decodeAndReadBType = liftA3 (,,) (decodeRS1 >>= Op.readRegister) (decodeRS2 >>= Op.readRegister) decodeImmB

-- decode and read register
decodeAndReadSType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v, v)
decodeAndReadSType = liftA3 (,,) (decodeRS1 >>= Op.readRegister) (decodeRS2 >>= Op.readRegister) decodeImmS

-- decode and read register
decodeAndReadRType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v, v)
decodeAndReadRType = liftA3 (,,) (decodeRS1 >>= Op.readRegister) (decodeRS2 >>= Op.readRegister) decodeRD

-- decode and read register
decodeJType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v)
decodeJType = liftA2 (,) decodeRD decodeImmJ

decodeUType :: forall v r. (Member (Decoding v) r, Member (Operations v) r) => Eff r (v, v)
decodeUType = liftA2 (,) decodeRD decodeImmU

-- | Write to a register in the register file. The function takes a register index and
-- a value which should be written to the register (represented as an 'Expr'). This function
-- is primarly useful to initialize special registers, e.g. setting the stack pointer to a
-- meaningful value at the very beginning of the free monad AST.
writeRegister :: forall v r. (Member (ExprEval v) r, Member (Operations v) r) => v -> Expr v -> Eff r ()
writeRegister reg e = eval e >>= Op.writeRegister reg

-- | Obtain the current value for a register in the register file. The functions takes a register
-- index (encapsulated in an 'Expr') and returns the value of this register.
readRegister :: forall v r. (Member (ExprEval v) r, Member (Operations v) r) => Expr v -> Eff r v
readRegister e = eval e >>= Op.readRegister

-- | Change the current value of the /Program Counter/ (PC). The new value is the only function
-- argument and is represented as an 'Expr'.
writePC :: forall v r. (Member (ExprEval v) r, Member (Operations v) r) => Expr v -> Eff r ()
writePC e = eval e >>= Op.writePC

-- | Load a fixed-size value from memory. The function takes two arguments: The 'Size' of the
-- value to load and the start address of the value in memory (represented as an 'Expr').
load :: forall v r. (Member (ExprEval v) r, Member (Operations v) r) => Size -> Expr v -> Eff r v
load s e = eval e >>= Op.load s

-- | Store a fixed-size value in memory. The arguments are: The 'Size' of the value, the start
-- address where the value should be stored, and the value itself. The latter two are encapuslated
-- in the 'Expr' abstraction.
store :: forall v r. (Member (ExprEval v) r, Member (Operations v) r) => Size -> Expr v -> Expr v -> Eff r ()
store s r e = do
    reg <- eval r
    v <- eval e
    Op.store s reg v