packages feed

libriscv-0.1.0.0: lib/LibRISCV/Semantics/RV_M/Default.hs

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

module LibRISCV.Semantics.RV_M.Default where

import Control.Monad.Freer
import Data.Function (on)
import LibRISCV.Effects.Decoding.Language (Decoding)
import LibRISCV.Effects.Expressions.Expr
import LibRISCV.Effects.Expressions.Language (ExprEval, ifExprM)
import LibRISCV.Effects.Logging.Language (LogInstructionFetch)
import LibRISCV.Effects.Operations.Language (Operations (..))
import LibRISCV.Internal.Decoder.Opcodes (RV_M (..))
import LibRISCV.Semantics.Utils

instrSemantics ::
    forall v r.
    ( Member (Operations v) r
    , Member LogInstructionFetch r
    , Member (Decoding v) r
    , Member (ExprEval v) r
    ) =>
    Int ->
    RV_M ->
    Eff r ()
instrSemantics width =
    let
        fromUInt :: Integer -> Expr v
        fromUInt = FromInt width

        immEqInt :: v -> Integer -> Expr v
        immEqInt imm int = FromImm imm `Eq` fromUInt int

        mask1 :: Expr v
        mask1 = FromInt width (2 ^ width - 1)

        extract32 :: Int -> Expr v -> Expr v
        extract32 = flip Extract 32

        mostNegative :: Integer
        mostNegative = 2 ^ (width - 1)

        -- Signed division overflow occurs when the most-negative integer is divided by -1.
        sdivOverflow :: v -> v -> Expr v
        sdivOverflow n divisor = (n `immEqInt` mostNegative) `And` (divisor `immEqInt` (-1))
     in
        \case
            MUL -> do
                (r1, r2, rd) <- decodeAndReadRType
                let
                    multRes = (Mul `on` sextImm 32) r1 r2
                    res = extract32 0 multRes
                writeRegister rd res
            MULH -> do
                (r1, r2, rd) <- decodeAndReadRType
                let
                    multRes = (Mul `on` sextImm 32) r1 r2
                    res = extract32 32 multRes
                writeRegister rd res
            MULHU -> do
                (r1, r2, rd) <- decodeAndReadRType
                let
                    multRes = (Mul `on` zextImm 32) r1 r2
                    res = extract32 32 multRes
                writeRegister rd res
            MULHSU -> do
                (r1, r2, rd) <- decodeAndReadRType
                let
                    multRes = sextImm 32 r1 `Mul` zextImm 32 r2
                    res = extract32 32 multRes
                writeRegister rd res
            DIV -> do
                (r1, r2, rd) <- decodeAndReadRType
                ifExprM
                    (r2 `immEqInt` 0)
                    do writeRegister rd mask1
                    do
                        ifExprM
                            (sdivOverflow r1 r2)
                            do writeRegister rd $ FromImm r1
                            do writeRegister rd $ r1 `sdiv` r2
            DIVU -> do
                (r1, r2, rd) <- decodeAndReadRType
                ifExprM
                    (r2 `immEqInt` 0)
                    do writeRegister rd mask1
                    do writeRegister rd $ r1 `udiv` r2
            REM -> do
                (r1, r2, rd) <- decodeAndReadRType
                ifExprM
                    (r2 `immEqInt` 0)
                    do writeRegister rd $ FromImm r1
                    do
                        ifExprM
                            (sdivOverflow r1 r2)
                            do writeRegister rd $ fromUInt 0
                            do writeRegister rd $ r1 `srem` r2
            REMU -> do
                (r1, r2, rd) <- decodeAndReadRType
                ifExprM
                    (r2 `immEqInt` 0)
                    do writeRegister rd $ FromImm r1
                    do writeRegister rd $ r1 `urem` r2