{-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveDataTypeable #-} -------------------------------------------------------------------- -- | -- Copyright : © Edward Kmett 2010-2015, © Eric Mertens 2014, Johan Kiviniemi 2013 -- License : BSD3 -- Maintainer: Edward Kmett -- Stability : experimental -- Portability: non-portable -- -- 'Bits' is an arbitrary length natural number type -------------------------------------------------------------------- module Ersatz.Bits ( -- * Fixed length bit vectors Bit1(..), Bit2(..), Bit3(..), Bit4(..), Bit5(..), Bit6(..), Bit7(..), Bit8(..) -- * Variable length bit vectors , Bits(Bits) , HasBits(..) , isEven , isOdd , sumBit , sumBits -- * Adders , fullAdder, halfAdder ) where import Control.Applicative import Control.Monad.Trans.State (State, runState, get, put) import Data.Bits ((.&.), (.|.), shiftL, shiftR) import qualified Data.Bits as Data #if __GLASGOW_HASKELL__ < 710 import Data.Foldable (Foldable, toList) #else import Data.Foldable (toList) #endif import Data.List (unfoldr, foldl') #if __GLASGOW_HASKELL__ < 710 import Data.Traversable (traverse) #endif import Data.Typeable (Typeable) import Data.Word (Word8) import Ersatz.Bit import Ersatz.Codec import Ersatz.Equatable import Ersatz.Orderable import Ersatz.Variable import GHC.Generics import Prelude hiding (and, or, not, (&&), (||)) -- | A container of 1 'Bit' that 'encode's from and 'decode's to 'Word8' newtype Bit1 = Bit1 Bit deriving (Show,Typeable,Generic) -- | A container of 2 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit2 = Bit2 !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 3 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit3 = Bit3 !Bit !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 4 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit4 = Bit4 !Bit !Bit !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 5 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit5 = Bit5 !Bit !Bit !Bit !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 6 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit6 = Bit6 !Bit !Bit !Bit !Bit !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 7 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit7 = Bit7 !Bit !Bit !Bit !Bit !Bit !Bit !Bit deriving (Show,Typeable,Generic) -- | A container of 8 'Bit's that 'encode's from and 'decode's to 'Word8' data Bit8 = Bit8 !Bit !Bit !Bit !Bit !Bit !Bit !Bit !Bit deriving (Show,Typeable,Generic) instance Boolean Bit1 instance Boolean Bit2 instance Boolean Bit3 instance Boolean Bit4 instance Boolean Bit5 instance Boolean Bit6 instance Boolean Bit7 instance Boolean Bit8 instance Equatable Bit1 instance Equatable Bit2 instance Equatable Bit3 instance Equatable Bit4 instance Equatable Bit5 instance Equatable Bit6 instance Equatable Bit7 instance Equatable Bit8 instance Orderable Bit1 instance Orderable Bit2 instance Orderable Bit3 instance Orderable Bit4 instance Orderable Bit5 instance Orderable Bit6 instance Orderable Bit7 instance Orderable Bit8 instance Variable Bit1 instance Variable Bit2 instance Variable Bit3 instance Variable Bit4 instance Variable Bit5 instance Variable Bit6 instance Variable Bit7 instance Variable Bit8 instance Codec Bit1 where type Decoded Bit1 = Word8 decode s (Bit1 a) = boolsToNum1 <$> decode s a encode i = Bit1 a where (a:_) = bitsOf i instance Codec Bit2 where type Decoded Bit2 = Word8 decode s (Bit2 a b) = boolsToNum2 <$> decode s a <*> decode s b encode i = Bit2 a b where (b:a:_) = bitsOf i instance Codec Bit3 where type Decoded Bit3 = Word8 decode s (Bit3 a b c) = boolsToNum3 <$> decode s a <*> decode s b <*> decode s c encode i = Bit3 a b c where (c:b:a:_) = bitsOf i instance Codec Bit4 where type Decoded Bit4 = Word8 decode s (Bit4 a b c d) = boolsToNum4 <$> decode s a <*> decode s b <*> decode s c <*> decode s d encode i = Bit4 a b c d where (d:c:b:a:_) = bitsOf i instance Codec Bit5 where type Decoded Bit5 = Word8 decode s (Bit5 a b c d e) = boolsToNum5 <$> decode s a <*> decode s b <*> decode s c <*> decode s d <*> decode s e encode i = Bit5 a b c d e where (e:d:c:b:a:_) = bitsOf i instance Codec Bit6 where type Decoded Bit6 = Word8 decode s (Bit6 a b c d e f) = boolsToNum6 <$> decode s a <*> decode s b <*> decode s c <*> decode s d <*> decode s e <*> decode s f encode i = Bit6 a b c d e f where (f:e:d:c:b:a:_) = bitsOf i instance Codec Bit7 where type Decoded Bit7 = Word8 decode s (Bit7 a b c d e f g) = boolsToNum7 <$> decode s a <*> decode s b <*> decode s c <*> decode s d <*> decode s e <*> decode s f <*> decode s g encode i = Bit7 a b c d e f g where (g:f:e:d:c:b:a:_) = bitsOf i instance Codec Bit8 where type Decoded Bit8 = Word8 decode s (Bit8 a b c d e f g h) = boolsToNum8 <$> decode s a <*> decode s b <*> decode s c <*> decode s d <*> decode s e <*> decode s f <*> decode s g <*> decode s h encode i = Bit8 a b c d e f g h where (h:g:f:e:d:c:b:a:_) = bitsOf i boolsToNum1 :: Bool -> Word8 boolsToNum1 = boolToNum boolsToNum2 :: Bool -> Bool -> Word8 boolsToNum2 a b = boolsToNum [a,b] boolsToNum3 :: Bool -> Bool -> Bool -> Word8 boolsToNum3 a b c = boolsToNum [a,b,c] boolsToNum4 :: Bool -> Bool -> Bool -> Bool -> Word8 boolsToNum4 a b c d = boolsToNum [a,b,c,d] boolsToNum5 :: Bool -> Bool -> Bool -> Bool -> Bool -> Word8 boolsToNum5 a b c d e = boolsToNum [a,b,c,d,e] boolsToNum6 :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Word8 boolsToNum6 a b c d e f = boolsToNum [a,b,c,d,e,f] boolsToNum7 :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Word8 boolsToNum7 a b c d e f g = boolsToNum [a,b,c,d,e,f,g] boolsToNum8 :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Word8 boolsToNum8 a b c d e f g h = boolsToNum [a,b,c,d,e,f,g,h] bitsOf :: (Num a, Data.Bits a) => a -> [Bit] bitsOf n = bool (numToBool (n .&. 1)) : bitsOf (n `shiftR` 1) {-# INLINE bitsOf #-} numToBool :: (Eq a, Num a) => a -> Bool numToBool 0 = False numToBool _ = True {-# INLINE numToBool #-} boolsToNum :: (Num a, Data.Bits a) => [Bool] -> a boolsToNum = foldl' (\n a -> (n `shiftL` 1) .|. boolToNum a) 0 {-# INLINE boolsToNum #-} boolToNum :: Num a => Bool -> a boolToNum False = 0 boolToNum True = 1 {-# INLINE boolToNum #-} instance Num Bit1 where Bit1 a + Bit1 b = Bit1 (xor a b) Bit1 a * Bit1 b = Bit1 (a && b) Bit1 a - Bit1 b = Bit1 (xor a b) negate a = a abs a = a signum a = a fromInteger = Bit1 . bool . odd -- | Compute the sum and carry bit from adding three bits. fullAdder :: Bit -> Bit -> Bit -> (Bit, Bit) -- ^ (sum, carry) fullAdder a b c = -- ( full_Adder_Sum a b c , full_Adder_Carry a b c ) let (s1,c1) = halfAdder a b ; (s2,c2) = halfAdder s1 c in (s2, c1||c2) -- following does not work (formula generation does not stop), why? {- ( Run $ exists >>= \ x -> do assert ( a || b || c || not x ) ; assert ( not a || not b || not c || x ) assert ( a || not b || not c || not x ) ; assert ( not a || b || c || x ) assert ( not a || b || not c || not x ) ; assert ( a || not b || c || x ) assert ( not a || not b || c || not x ) ; assert ( a || b || not c || x ) return x , Run $ exists >>= \ x -> do assert ( not b || not c || x ) ; assert ( b || c || not x ) assert ( not a || not c || x ) ; assert ( a || c || not x ) assert ( not a || not b || x ) ; assert ( a || b || not x ) return x ) -} -- | Compute the sum and carry bit from adding two bits. halfAdder :: Bit -> Bit -> (Bit, Bit) -- ^ (sum, carry) halfAdder a b = (a `xor` b, a && b) instance Num Bit2 where Bit2 a2 a1 + Bit2 b2 b1 = Bit2 s2 s1 where (s1,c2) = halfAdder a1 b1 (s2,_) = fullAdder a2 b2 c2 Bit2 a2 a1 * Bit2 b2 b1 = Bit2 ((a1 && b2) `xor` (a2 && b1)) (a1 && b1) -- wallace tree -- -- XX -- XX -- ---- -- XXX -- X -- ---- -- XXXX -- -- But we only need the first 2 bits negate (Bit2 a b) = Bit2 (not a) (not b) + 1 abs a = a signum (Bit2 a b) = Bit2 false (a || b) fromInteger k = Bit2 (bool (k .&. 2 /= 0)) (bool (k .&. 1 /= 0)) -- suitable for comparisons and arithmetic. Bits are stored -- in little-endian order to enable phantom 'false' values -- to be truncated. newtype Bits = Bits { _getBits :: [Bit] } deriving Typeable instance Show Bits where showsPrec d (Bits xs) = showParen (d > 10) $ showString "Bits " . showsPrec 11 xs instance Equatable Bits where Bits xs === Bits ys = and (zipWithBits (===) xs ys) Bits xs /== Bits ys = or (zipWithBits (/==) xs ys) -- | Zip the component bits of a 'Bits' extending the -- shorter argument with 'false' values. zipWithBits :: (Bit -> Bit -> a) -> [Bit] -> [Bit] -> [a] zipWithBits _ [] [] = [] zipWithBits f (x:xs) (y:ys) = f x y : zipWithBits f xs ys zipWithBits f xs [] = map (`f` false) xs zipWithBits f [] ys = map (false `f`) ys instance Orderable Bits where Bits xs [Bit] -> [Bit] -> Bit orderHelper c0 xs ys = foldl aux c0 (zipWithBits (,) xs ys) where aux c (x,y) = c && x === y || x if x then 1 else 0) ys -- Integers to Integer return (foldr (\x acc -> x + 2 * acc) 0 zs) encode = Bits . unfoldr step where step x = case compare x 0 of LT -> error "Bits/encode: Negative number" EQ -> Nothing GT -> Just (if odd x then true else false, x `div` 2) unbits :: HasBits a => a -> [Bit] unbits a = case bits a of Bits xs -> xs -- | Add two 'Bits' values given an incoming carry bit. addBits :: (HasBits a, HasBits b) => Bit -> a -> b -> Bits addBits c xs0 ys0 = Bits (add2 c (unbits xs0) (unbits ys0)) where add2 cin [] ys = add1 cin ys add2 cin xs [] = add1 cin xs add2 cin (x:xs) (y:ys)= s : add2 cout xs ys where (s,cout) = fullAdder x y cin add1 cin [] = [cin] add1 cin (x:xs) = s : add1 cout xs where (s,cout) = halfAdder cin x -- | Compute the sum of a source of 'Bits' values. sumBits :: (Foldable t, HasBits a) => t a -> Bits sumBits = sumBits' . map bits . toList sumBits' :: [Bits] -> Bits sumBits' [] = Bits [] sumBits' [x] = x sumBits' xs0 = sumBits (merge xs0) where merge [x] = [x] merge [] = [] merge (x1:x2:xs) = addBits false x1 x2 : merge xs -- | Optimization of 'sumBits' enabled when summing -- individual 'Bit's. sumBit :: Foldable t => t Bit -> Bits sumBit t = case runState (merge (map bits h2)) h1 of (s,[]) -> s _ -> error "Bits.betterSumBits: OOPS! Bad algorithm!" where ts = toList t (h1,h2) = splitAt ((length ts-1) `div` 2) ts spareBit = do xs <- get case xs of [] -> return false y:ys -> put ys >> return y merge :: [Bits] -> State [Bit] Bits merge [x] = return x merge [] = return (Bits []) merge xs = merge =<< merge' xs merge' :: [Bits] -> State [Bit] [Bits] merge' [] = return [] merge' [x] = return [x] merge' (x1:x2:xs) = do cin <- spareBit xs' <- merge' xs return (addBits cin x1 x2 : xs') -- | Predicate for odd-valued 'Bits's. isOdd :: HasBits b => b -> Bit isOdd b = case unbits b of [] -> false (x:_) -> x -- | Predicate for even-valued 'Bits's. isEven :: HasBits b => b -> Bit isEven = not . isOdd -- | 'HasBits' provides the 'bits' method for embedding -- fixed with numeric encoding types into the arbitrary width -- 'Bits' type. class HasBits a where bits :: a -> Bits instance HasBits Bit where bits x = Bits [x] instance HasBits Bit1 where bits (Bit1 x0) = Bits [x0] instance HasBits Bit2 where bits (Bit2 x1 x0) = Bits [x0,x1] instance HasBits Bit3 where bits (Bit3 x2 x1 x0) = Bits [x0,x1,x2] instance HasBits Bit4 where bits (Bit4 x3 x2 x1 x0) = Bits [x0,x1,x2,x3] instance HasBits Bit5 where bits (Bit5 x4 x3 x2 x1 x0) = Bits [x0,x1,x2,x3,x4] instance HasBits Bit6 where bits (Bit6 x5 x4 x3 x2 x1 x0) = Bits [x0,x1,x2,x3,x4,x5] instance HasBits Bit7 where bits (Bit7 x6 x5 x4 x3 x2 x1 x0) = Bits [x0,x1,x2,x3,x4,x5,x6] instance HasBits Bit8 where bits (Bit8 x7 x6 x5 x4 x3 x2 x1 x0) = Bits [x0,x1,x2,x3,x4,x5,x6,x7] instance HasBits Bits where bits = id mulBits :: Bits -> Bits -> Bits mulBits (Bits xs) (Bits ys0) = sumBits $ zipWith aux xs (iterate times2 ys0) where times2 = (false:) aux x ys = Bits (map (x &&) ys) instance Num Bits where (+) = addBits false (*) = mulBits (-) = subBits fromInteger = encode signum (Bits xs) = Bits [or xs] abs x = x fullSubtract :: Bit -> Bit -> Bit -> (Bit,Bit) fullSubtract c x y = (x `xor` y `xor` c, x && y && c || not x && y || not x && c) subBits :: (HasBits a, HasBits b) => a -> b -> Bits subBits xs0 ys0 = Bits (map (not cN &&) ss) where (cN, ss) = aux false (unbits xs0) (unbits ys0) aux c [] [] = (c, []) aux c [] ys = aux c [false] ys aux c xs [] = aux c xs [false] aux c (x:xs) (y:ys) = fmap (z :) (aux cout xs ys) where (z,cout) = fullSubtract c x y