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