packages feed

hardware-edsl-0.1.0.1: src/Language/Embedded/Hardware/Expression/Represent.hs

module Language.Embedded.Hardware.Expression.Represent
  ( Tagged (..)
  , Rep    (..)
  ) where

import Language.Embedded.VHDL            (VHDL)
import Language.Embedded.VHDL.Monad      (newLibrary, newImport)
import Language.Embedded.VHDL.Monad.Type

import Data.Int
import Data.Word

import Data.Char   (intToDigit)
import Data.Bits   (shiftR)
import Text.Printf (printf)
import Numeric     (showIntAtBase)

import Data.ByteString (ByteString)
import qualified Data.ByteString as B

--------------------------------------------------------------------------------
-- * Representable types (until I come up with a solution free of VHDL stuff).
--------------------------------------------------------------------------------

-- | Tag a value with some (possibly) interesting information
newtype Tagged s b = Tag { unTag :: b }

-- | A 'rep'resentable value.
class Rep a
  where
    width   :: Tagged a Int
    typed   :: Tagged a Type
    declare :: a -> VHDL ()
    format  :: a -> String

declareBoolean :: VHDL ()
declareBoolean =
  do newLibrary "IEEE"
     newImport  "IEEE.std_logic_1164"

declareNumeric :: VHDL ()
declareNumeric =
  do newLibrary "IEEE"
     newImport  "IEEE.std_logic_1164"
     newImport  "IEEE.numeric_std"

declareFloating :: VHDL ()
declareFloating =
  do newLibrary "IEEE"
     newImport  "IEEE.float_pkg"

--------------------------------------------------------------------------------
-- ** Boolean

instance Rep Bool where
  width        = Tag 1
  typed        = Tag std_logic
  declare _    = declareBoolean
  format True  = "1"
  format False = "0"

--------------------------------------------------------------------------------
-- ** Signed

instance Rep Int8 where
  width     = Tag 8
  typed     = Tag signed8
  declare _ = declareNumeric
  format    = convert

instance Rep Int16 where
  width     = Tag 16
  typed     = Tag signed16
  declare _ = declareNumeric
  format    = convert

instance Rep Int32 where
  width     = Tag 32
  typed     = Tag signed32
  declare _ = declareNumeric
  format    = convert

instance Rep Int64 where
  width     = Tag 64
  typed     = Tag signed64
  declare _ = declareNumeric
  format    = convert

--------------------------------------------------------------------------------
-- ** Unsigned

instance Rep Word8 where
  width     = Tag 8
  typed     = Tag usigned8
  declare _ = declareNumeric
  format    = convert

instance Rep Word16 where
  width     = Tag 16
  typed     = Tag usigned16
  declare _ = declareNumeric
  format    = convert

instance Rep Word32 where
  width     = Tag 32
  typed     = Tag usigned32
  declare _ = declareNumeric
  format    = convert

instance Rep Word64 where
  width     = Tag 64
  typed     = Tag usigned64
  declare _ = declareNumeric
  format    = convert

--------------------------------------------------------------------------------
-- ** Floating point.

instance Rep Float where
  width     = Tag 32
  typed     = Tag float
  declare _ = declareFloating
  format    = error "todo: format float."

instance Rep Double where
  width     = Tag 64
  typed     = Tag double
  declare _ = declareFloating
  format    = error "todo: format double."

--------------------------------------------------------------------------------
-- * Converting Integers to their Binrary representation
--------------------------------------------------------------------------------

-- | Convert an Integral to its binary representation
convert :: Integral a => a -> String
convert = foldr1 (++) . fmap w2s . B.unpack . i2bs . toInteger

-- | Go over an Integer and convert it into a bytestring containing its
--   binary representation
i2bs :: Integer -> ByteString
i2bs x = B.reverse . B.unfoldr (fmap chunk) . Just $ sign x
  where
    sign :: (Num a, Ord a) => a -> a
    sign | x < 0     = subtract 1 . negate
         | otherwise = id

    chunk :: Integer -> (Word8, Maybe Integer)
    chunk x = (b, i)
      where
        b = sign (fromInteger x)
        i | x >= 128  = Just (x `shiftR` 8)
          | otherwise = Nothing

-- | Shows a word with zero padding
--
-- I assum the negative numbers to already be padded with ones
w2s :: Word8 -> String
w2s w = printf "%08s" $ showIntAtBase 2 intToDigit w ""

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