packages feed

libriscv-0.1.0.0: internal/LibRISCV/Internal/Decoder/Instruction.hs

module LibRISCV.Internal.Decoder.Instruction where

import Data.Bits
import Data.Word

-- Convert to an unsigned word (in two's complement) to a signed number.
fromTwoscomp :: Word32 -> Word32 -> Word32
fromTwoscomp numBits n = fromIntegral $ -(n .&. mask) + (n .&. complement mask)
  where
    mask :: Word32
    mask = 2 ^ (numBits - 1)

-- Extract a bit field from a RISC-V instruction word.
instrField :: Int -> Int -> Word32 -> Word32
instrField start end w = mask start (end + 1) .&. shiftR w start
  where
    -- Create a 32-bit bit mask in the range [start,end-1].
    mask :: Int -> Int -> Word32
    mask start end = complement $ shift (maxBound :: Word32) (end - start)

------------------------------------------------------------------------

immI :: Word32 -> Word32
immI = fromTwoscomp 12 . instrField 20 31

immS :: Word32 -> Word32
immS i =
    fromTwoscomp 12 $
        fromIntegral $
            (instrField 25 31 i `shift` 5) .|. instrField 07 11 i

immU :: Word32 -> Word32
immU i = instrField 12 31 i `shiftL` 12

{- FOURMOLU_DISABLE -}
immB :: Word32 -> Word32
immB i = fromTwoscomp 13 $
         (instrField 31 31 i `shift` 12)
     .|. (instrField 07 07 i `shift` 11)
     .|. (instrField 25 30 i `shift` 05)
     .|. (instrField 08 11 i `shift` 01)

immJ :: Word32 -> Word32
immJ i = fromTwoscomp 21 $
         (instrField 31 31 i `shift` 20)
     .|. (instrField 12 19 i `shift` 12)
     .|. (instrField 20 20 i `shift` 11)
     .|. (instrField 21 30 i `shift` 1)
{- FOURMOLU_ENABLE -}

mkShamt :: Word32 -> Word32
mkShamt = instrField 20 25

mkRs1 :: Word32 -> Word32
mkRs1 = instrField 15 19

mkRs2 :: Word32 -> Word32
mkRs2 = instrField 20 24

mkRd :: Word32 -> Word32
mkRd = instrField 7 11