libriscv-0.1.0.0: lib/LibRISCV/Semantics/RV_I/Default.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module LibRISCV.Semantics.RV_I.Default where
import Control.Monad.Freer
import LibRISCV.Effects.Decoding.Language (Decoding)
import LibRISCV.Effects.Expressions.Expr
import LibRISCV.Effects.Expressions.Language (ExprEval, unlessExprM, whenExprM)
import LibRISCV.Effects.Logging.Language (LogInstructionFetch)
import LibRISCV.Effects.Operations.Language (Operations (..), Size (..), ebreak, ecall, exception, readPC)
import LibRISCV.Internal.Decoder.Opcodes (RV_I (..))
import LibRISCV.Semantics.Utils
instrSemantics ::
forall v r.
( Member (Operations v) r
, Member LogInstructionFetch r
, Member (Decoding v) r
, Member (ExprEval v) r
) =>
Int ->
v ->
RV_I ->
Eff r ()
instrSemantics width pc =
let
fromUInt :: Integer -> Expr v
fromUInt = FromInt width
-- False if a given address is not aligned at the four-byte boundary.
isMisaligned :: Expr v -> Expr v
isMisaligned addr = (addr `And` fromUInt 0x3) `Uge` fromUInt 1
in
\case
ADDI -> do
(r1, rd, imm) <- decodeAndReadIType @v
writeRegister rd $ r1 `addImm` imm
SLTI -> do
(r1, rd, imm) <- decodeAndReadIType @v
let cond = r1 `slt` imm
writeRegister rd cond
SLTIU -> do
(r1, rd, imm) <- decodeAndReadIType @v
let cond = r1 `ult` imm
writeRegister rd cond
ANDI -> do
(r1, rd, imm) <- decodeAndReadIType @v
writeRegister rd $ r1 `andImm` imm
ORI -> do
(r1, rd, imm) <- decodeAndReadIType @v
writeRegister rd $ r1 `orImm` imm
XORI -> do
(r1, rd, imm) <- decodeAndReadIType @v
writeRegister rd $ r1 `xorImm` imm
LUI -> do
(rd, imm) <- decodeUType @v
writeRegister rd $ FromImm imm
AUIPC -> do
(rd, imm) <- decodeUType
writeRegister rd $ pc `addImm` imm
ADD -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ r1 `addImm` r2
SLT -> do
(r1, r2, rd) <- decodeAndReadRType
let cond = r1 `slt` r2 :: Expr v
writeRegister rd cond
SLTU -> do
(r1, r2, rd) <- decodeAndReadRType
let cond = r1 `ult` r2 :: Expr v
writeRegister rd cond
AND -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ r1 `andImm` r2
OR -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ r1 `orImm` r2
XOR -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ r1 `xorImm` r2
SLL -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ FromImm r1 `LShl` regShamt width (FromImm r2)
SRL -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ FromImm r1 `LShr` regShamt width (FromImm r2)
SUB -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ r1 `sub` r2
SRA -> do
(r1, r2, rd) <- decodeAndReadRType @v
writeRegister rd $ FromImm r1 `AShr` regShamt width (FromImm r2)
JAL -> do
nextInstr <- readPC
(rd, imm) <- decodeJType
let newPC = pc `addImm` imm
writePC newPC
whenExprM (isMisaligned newPC) $
exception pc "misaligned PC"
writeRegister rd (FromImm nextInstr)
JALR -> do
nextInstr <- readPC
(r1, rd, imm) <- decodeAndReadIType
let newPC = (r1 `addImm` imm) `And` fromUInt 0xfffffffe
writePC newPC
whenExprM (isMisaligned newPC) $
exception pc "misaligned PC"
writeRegister rd $ FromImm nextInstr
LB -> do
(r1, rd, imm) <- decodeAndReadIType @v
byte <- load Byte $ r1 `addImm` imm
-- TODO: Alignment handling
writeRegister rd $ sextImm 24 byte
LBU -> do
(r1, rd, imm) <- decodeAndReadIType @v
-- TODO: Alignment handling
byte <- load Byte $ r1 `addImm` imm
writeRegister rd $ zextImm 24 byte
LH -> do
(r1, rd, imm) <- decodeAndReadIType @v
-- TODO: Alignment handling
half <- load Half $ r1 `addImm` imm
writeRegister rd $ sextImm 16 half
LHU -> do
(r1, rd, imm) <- decodeAndReadIType @v
-- TODO: Alignment handling
half <- load Half $ r1 `addImm` imm
writeRegister rd $ zextImm 16 half
LW -> do
(r1, rd, imm) <- decodeAndReadIType @v
-- TODO: Alignment handling
word <- load Word $ r1 `addImm` imm
writeRegister rd $ FromImm word
SB -> do
(r1, r2, imm) <- decodeAndReadSType @v
-- TODO: Alignment handling
store Byte (r1 `addImm` imm) $ FromImm r2
SH -> do
(r1, r2, imm) <- decodeAndReadSType @v
-- TODO: Alignment handling
store Half (r1 `addImm` imm) $ FromImm r2
SW -> do
(r1, r2, imm) <- decodeAndReadSType @v
-- TODO: Alignment handling
store Word (r1 `addImm` imm) $ FromImm r2
BEQ -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
whenExprM (r1 `eq` r2) $ do
writePC addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
BNE -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
unlessExprM (r1 `eq` r2) $ do
writePC addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
BLT -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
whenExprM (r1 `slt` r2) $ do
writePC addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
BLTU -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
whenExprM (r1 `ult` r2) $ do
writePC @v $ addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
BGE -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
whenExprM (r1 `sge` r2) $ do
writePC addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
BGEU -> do
(r1, r2, imm) <- decodeAndReadBType
let addr = pc `add` imm
whenExprM (r1 `uge` r2) $ do
writePC addr
whenExprM (isMisaligned addr) $
exception pc "misaligned PC"
FENCE -> pure () -- XXX: ignore for now
ECALL -> ecall pc
EBREAK -> ebreak pc