{-# LANGUAGE TemplateHaskell #-}
module Clash.Annotations.BitRepresentation.Util
( bitOrigins
, bitOrigins'
, bitRanges
, isContinuousMask
, BitOrigin(..)
, Bit(..)
) where
import Clash.Annotations.BitRepresentation.Internal
(DataRepr'(..), ConstrRepr'(..))
import Data.Bits (Bits, testBit, testBit, shiftR, (.|.))
import Data.List (findIndex, group, mapAccumL)
import Data.Tuple (swap)
data Bit
= H
| L
| U
deriving (Show,Eq)
data BitOrigin
= Lit [Bit]
| Field
Int
Int
Int
deriving (Show)
bitOrigins'
:: DataRepr'
-> ConstrRepr'
-> [BitOrigin]
bitOrigins' (DataRepr' _ size constrs) (ConstrRepr' _ _ mask value fields) =
map bitOrigin (reverse [0..fromIntegral $ size - 1])
where
commonMask = foldl (.|.) 0 [m | ConstrRepr' _ _ m _ _ <- constrs]
bitOrigin :: Int -> BitOrigin
bitOrigin n =
if testBit mask n then
Lit [if testBit value n then H else L]
else
case findIndex (\fmask -> testBit fmask n) fields of
Nothing ->
if testBit commonMask n then
Lit [if testBit value n then H else L]
else
Lit [U]
Just fieldn ->
let fieldbitn = length $ filter id
$ take n
$ bitsToBools (fields !! fieldn) in
Field fieldn fieldbitn fieldbitn
bitOrigins
:: DataRepr'
-> ConstrRepr'
-> [BitOrigin]
bitOrigins dataRepr constrRepr =
mergeOrigins (bitOrigins' dataRepr constrRepr)
mergeOrigins :: [BitOrigin] -> [BitOrigin]
mergeOrigins (Lit n : Lit n' : fs) =
mergeOrigins $ Lit (n ++ n') : fs
mergeOrigins (Field n s e : Field n' s' e' : fs)
| n == n' = mergeOrigins $ Field n s e' : fs
| otherwise = Field n s e : mergeOrigins (Field n' s' e' : fs)
mergeOrigins (x:fs) = x : mergeOrigins fs
mergeOrigins [] = []
bitsToBools :: (Num a, Bits a, Ord a) => a -> [Bool]
bitsToBools 0 = []
bitsToBools n | n < 0 = error "Can't deal with negative bitmasks/values"
| otherwise = testBit n 0 : bitsToBools (n `shiftR` 1)
offsets
:: Int
-> [Bool]
-> (Int, (Int, [Bool]))
offsets offset group' =
(length group' + offset, (offset, group'))
bitRanges :: Integer -> [(Int, Int)]
bitRanges word = reverse $ map swap ranges
where
ranges = map (\(ofs, grp) -> (ofs, ofs+length grp-1)) groups'
groups' = filter (head . snd) groups
groups = snd $ mapAccumL offsets 0 (group bits)
bits = bitsToBools word
isContinuousMask :: Integer -> Bool
isContinuousMask word =
case bitRanges word of
(_:_:_) -> False
_ -> True