packages feed

HHDL (empty) → 0.1.0.0

raw patch · 14 files changed

+2483/−0 lines, 14 filesdep +basedep +containersdep +mtlsetup-changed

Dependencies added: base, containers, mtl, template-haskell

Files

+ HHDL.cabal view
@@ -0,0 +1,82 @@+-- HHDL.cabal auto-generated by cabal init. For additional options,
+-- see
+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
+-- The name of the package.
+Name:                HHDL
+
+-- The package version. See the Haskell package versioning policy
+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
+-- standards guiding when and how versions should be incremented.
+Version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+Synopsis:            Hardware Description Language embedded in Haskell.
+
+-- A longer description of the package.
+Description:         Hardware Description Language embedded in Haskell.
+                     Main distinction from Lava or similar packages is
+                     that HHDL supports algebraic types with pattern matching.
+
+-- URL for the project homepage or repository.
+Homepage:            http://thesz.mskhug.ru/svn/hhdl/hackage/hhdl/
+
+-- The license under which the package is released.
+License:             BSD3
+
+-- The file containing the license text.
+License-file:        LICENSE
+
+-- The package author(s).
+Author:              Serguey Zefirov
+
+-- An email address to which users can send suggestions, bug reports,
+-- and patches.
+Maintainer:          sergueyz@gmail.com
+
+-- Stability is experimental right now.
+Stability:           experimental
+
+-- A copyright notice.
+Copyright:           Copyright (C) 2010, 2011 Serguey Zefirov
+
+Category:            Hardware
+
+Build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or
+-- a README.
+-- Extra-source-files:  
+
+-- Constraint on the version of Cabal needed to build this package.
+Cabal-version:       >=1.2
+
+-- Tested with.
+Tested-with: GHC == 6.12.1
+
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     Hardware.HHDL
+
+  -- Sources are in proper directory:
+  hs-source-dirs:      src
+
+  -- Packages needed in order to build this package.
+  Build-depends:       base >= 3.0 && < 4.0,
+                       template-haskell >= 2.4 && < 2.5,
+                       containers >= 0.3 && < 0.4,
+                       mtl >= 1.1
+  
+  -- Modules not exported by this package.
+  Other-modules:       Hardware.HHDL.HHDL, Hardware.HHDL.TH, 
+                       Hardware.HHDL.BitRepr, Hardware.HHDL.HDLPrelude,
+                       Hardware.HHDL.ToWires, Hardware.HHDL.TyLeA,
+                       Hardware.HHDL.Examples.Clock, Hardware.HHDL.Examples.RunningSum,
+                       Hardware.HHDL.Examples.SimpleSum,
+                       Hardware.HHDL.Examples.RunningSumMaybes
+  
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:         
+
+  -- Tested with.
+  -- tested-with: ghc-6.12.1
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Serguey Zefirov
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Serguey Zefirov nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain
+ src/Hardware/HHDL.hs view
@@ -0,0 +1,10 @@+-- |Hardware.HHDL
+-- Convenient top-level module that exports everything HHDL-related.
+
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Hardware.HHDL(
+	  module Hardware.HHDL.HHDL
+	) where
+
+import Hardware.HHDL.HHDL
+ src/Hardware/HHDL/BitRepr.hs view
@@ -0,0 +1,86 @@+-- |BitRepr.hs
+-- Bit representation.
+
+{-# LANGUAGE RankNTypes, GADTs, TypeFamilies, TypeOperators, TemplateHaskell #-}
+{-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
+{-# LANGUAGE MultiParamTypeClasses, OverlappingInstances #-}
+
+module Hardware.HHDL.BitRepr where
+
+import Data.Bits
+
+import Hardware.HHDL.TyLeA
+
+-------------------------------------------------------------------------------
+-- Main class.
+
+class Nat (BitVectorSize a) => BitRepr a where
+	type BitVectorSize a
+
+	-- |Convert value to an integer.
+	toBitVector :: a -> Integer
+
+	-- |Convert integer to value. Conversion should ignore any bits above
+	-- "bitVectorSize result".
+	fromBitVector :: Integer -> a
+
+	-- |Size of value in bits.
+	bitVectorSize :: a -> Int
+	bitVectorSize a = i
+		where
+			getSize :: a -> BitVectorSize a
+			getSize a = undefined
+			i = fromNat (getSize a)
+
+	-- |Mask for value's significant bits.
+	-- In usual bit vectors they are all significant (default variant below).
+	-- In algebraic types they aren't: data T = B Bool | W Word64.
+	-- The mask for B x could ignore significant bits from Word64 in W.
+	-- Right now it is not widely used, so it is safe to leave it as it is.
+	bitMask :: a -> Integer
+	bitMask a = shiftL 1 (bitVectorSize a) - 1
+
+
+-------------------------------------------------------------------------------
+-- Support definitions and type functions for algebraic types.
+-- instances are generated by calling generateMakeMatches from TH.hs.
+
+-- |How much bits do we need to pass arguments for any constructor?
+type family ArgsBusSize a
+
+-- |How much bits do we need for constructor selector?
+type family SelectorBusSize a
+
+
+-- Utility conversion function.
+-- USed for toBitVector/fromBitVector implementations.
+_toArgsBusSize :: a -> ArgsBusSize a
+_toArgsBusSize = undefined
+
+_toArgsBusSizeInt :: Nat (ArgsBusSize a) => a -> Int
+_toArgsBusSizeInt = fromNat . _toArgsBusSize
+
+_toSelBusSize :: a -> SelectorBusSize a
+_toSelBusSize = undefined
+
+_toSelBusSizeInt :: Nat (SelectorBusSize a) => a -> Int
+_toSelBusSizeInt = fromNat . _toSelBusSize
+
+_combineConstructorIndexArgs :: Integer -> Int -> Integer -> Integer
+_combineConstructorIndexArgs argsVector shift ci = shiftL ci shift .|. argsVector
+
+-- |Helper class that breaks some type checking dependencies and
+-- allow for faster compilation.
+class (Nat (ArgsBusSize a), Nat (SelectorBusSize a)) => AlgTypeBitEnc a where
+	algTypeArgsBusSize :: a -> Int
+	algTypeArgsBusSize a = fromNat (_toArgsBusSize a)
+
+	algTypeArgsBusMask :: a -> Integer
+	algTypeArgsBusMask a = shiftL 1 (algTypeArgsBusSize a) - 1
+
+	algTypeSelectorBusSize :: a -> Int
+	algTypeSelectorBusSize = _toSelBusSizeInt
+
+	algTypeSelectorBusMask :: a -> Integer
+	algTypeSelectorBusMask a = shiftL 1 (_toSelBusSizeInt a) - 1
+
+ src/Hardware/HHDL/Examples/Clock.hs view
@@ -0,0 +1,22 @@+-- |Hardware.HHDL.Examples.Clock
+-- Clock description for examples.
+
+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts, DoRec #-}
+{-# LANGUAGE DeriveDataTypeable, NoImplicitPrelude, TemplateHaskell #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+
+module Hardware.HHDL.Examples.Clock where
+
+import Hardware.HHDL
+
+data Clk = Clk deriving Typeable
+data Reset = Reset deriving Typeable
+instance Clock Clk where
+	type ClkReset Clk = Reset
+	clockValue = Clk
+	clockResetPositive _ = False
+	clockFrontEdge _ = True
+
+fixClockedClock :: Clocked (Clk :. Nil) ins outs -> Clocked (Clk :. Nil) ins outs
+fixClockedClock clocked = clocked
+ src/Hardware/HHDL/Examples/RunningSum.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts, DoRec #-}+{-# LANGUAGE DeriveDataTypeable, NoImplicitPrelude, TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}++module Hardware.HHDL.Examples.RunningSum where++import Data.Word++import Hardware.HHDL++import Hardware.HHDL.Examples.Clock+import Hardware.HHDL.Examples.SimpleSum++-------------------------------------------------------------------------------+-- Running polymorphic sum, ie, accumulator.+-- Demonstrates registers.++runningSumRec :: (Show a, ArithResult a ~ a, ClockAllowed c clks, IntegerConstant a, BitRepr a, BitRepr (ArithResult a), Arith (Wire c a)) => Clocked clks (Wire c a :. Nil) (Wire c a :. Nil)+runningSumRec = mkClocked "runningSum" $ \(a :. Nil) -> do+	rec+		sum <- register 0 nextSum+		(nextSum :. Nil) <- instantiate simpleSum (a :. sum :. Nil)+	return $ sum :. Nil++runningSumRecVHDLText = writeHDLText VHDL (runningSumRec :: Clocked (Clk :. Nil) (Wire Clk Word8 :. Nil) (Wire Clk Word8 :. Nil))+	(\s -> putStrLn s >> writeFile "runningSum.vhdl" s)++test = runningSumRecVHDLText
+ src/Hardware/HHDL/Examples/RunningSumMaybes.hs view
@@ -0,0 +1,60 @@+-- Many extensions. I overload many things from Haskell Prelude in the style+-- of Awesome Prelude. Also you may need a Template Haskell transformations+-- on declarations, which derives classes and type families instances, etc, etc.+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts, DoRec #-}+{-# LANGUAGE DeriveDataTypeable, NoImplicitPrelude, TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}++module Hardware.HHDL.Examples.RunningSumMaybes where++import Data.Word++-- The main module of the library. It exports everything I deemed useful+-- for hardware description - code generation over ADT, netlist operators, some+-- handy functions from Prelude...+-- Also, it contains making of wires for Either and Maybe and matching functions.+import Hardware.HHDL++-- The description of clocking frequency for our example.+import Hardware.HHDL.Examples.Clock++-------------------------------------------------------------------------------+-- How to pattern match an algebraic type.++-- Clocked is a type of entity. It has three arguments: a list of clocking frequencies allowed+-- in netlist, types of inputs and outputs.+runningSumMaybes :: Clock c => Mealy c (Wire c (Maybe Word8) :. Nil) (Wire c Word8 :. Nil)+runningSumMaybes = mkMealyNamed+	-- names of inputs and outputs.+	(Just ("maybeA" :. Nil, "currentSum" :. Nil))+	-- default value for state.+	(0 :. Nil)+	"runningSumMaybes" $ \(sum :. Nil) (mbA :. Nil) -> do+        -- here we pattern match in the <a href=http://hackage.haskell.org/package/first-class-patterns>"First class patterns"</a> style.+        -- the idea is that for each constructor Cons of algebraic type T we automatically+        -- create two functions:+        --   - mkCons which creates a wire (of type Wire c T) from wires of arguments and+        --   - pCons which matches a wire of type Wire c T with patterns of types of Cons+        --     arguments.+        -- pJust and pNothing were generated in Hardware.HHDL.HHDL from the description of+        -- Maybe type.+        -- pvar is a pattern that matches anything and passes that anything as an argument+        -- to processing function.+	a <- match mbA [+                -- if we have Just x, return it!+		  pJust pvar --> \(x :. Nil) -> return x+                -- default with 0, if Nothing.+		, pNothing --> \Nil -> return (constant 0)+		]+        -- compute the sum.+	nextSum <- assignWire (sum + a)+        -- return currently locked sum.+	return (nextSum :. Nil, sum :. Nil)++-- How to obtain VHDL text - we fix polymorphic parameters in Clocked, generate text (with any+-- entities we have to use) and pass it to display and write function.+runningSumMaybesVHDLText = writeHDLText VHDL (runningSumMaybes :: Mealy Clk (Wire Clk (Maybe Word8) :. Nil) (Wire Clk Word8 :. Nil))+	(\s -> putStrLn s >> writeFile "runningSumMaybes.vhdl" s)++-- a shortcut.+test = runningSumMaybesVHDLText
+ src/Hardware/HHDL/Examples/SimpleSum.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts, DoRec #-}+{-# LANGUAGE DeriveDataTypeable, NoImplicitPrelude, TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}++module Hardware.HHDL.Examples.SimpleSum where++import Data.Word++import Hardware.HHDL++-------------------------------------------------------------------------------+-- Polymorphic sum of inputs.++simpleSum :: (Show a, BitRepr a, BitRepr (ArithResult a), Arith (Wire c a)) => Comb (Wire c a :. Wire c a :. Nil) (Wire c (ArithResult a) :. Nil)+simpleSum = mkComb "simpleSum" $ \(a :. b :. Nil) -> do+	t <- assignWire (a+b)+	return $ t :. Nil+
+ src/Hardware/HHDL/HDLPrelude.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE RankNTypes, GADTs, TypeFamilies, TypeOperators, TemplateHaskell #-}
+{-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
+{-# LANGUAGE MultiParamTypeClasses, OverlappingInstances, NoImplicitPrelude #-}
+
+
+module Hardware.HHDL.HDLPrelude where
+
+import Prelude
+	( putStrLn, ($), (.), IO, (++), String, repeat, zipWith, head
+	, fst, snd, length, map, Show(..), reverse, Int, Integer, flip, filter
+	, unwords, unlines, replicate, const, undefined, error, Ordering(..)
+	, concat, concatMap, tail, iterate, Bool, Char, id)
+
+import qualified Prelude
+import Data.Word
+
+-------------------------------------------------------------------------------
+-- Replacement for Prelude classes.
+
+infixl 6 +, -
+infixl 7 *
+class Arith op where
+	type ArithResult op
+	(+), (-), (*) :: op -> op -> ArithResult op
+
+class IntegerConstant a where
+	fromInteger :: Integer -> a
+
+class ToInteger a where
+	toInteger :: a -> Integer
+
+convertThroughInteger :: (IntegerConstant res, ToInteger arg) => arg -> res
+convertThroughInteger = fromInteger . toInteger
+
+infix 4 ==, /=
+class Eq a where
+	type EqResult a
+	(==), (/=) :: a -> a -> EqResult a
+
+infixr 3 &&
+infixr 2 ||
+class Boolean b where
+	not :: b -> b
+	(&&), (||) :: b -> b -> b
+
+infix 4 <, >, <=, >=
+class Boolean b => Compare a b where
+	(>), (<), (>=), (<=) :: a -> a -> b
+
+
+-------------------------------------------------------------------------------
+-- Required instances.
+
+instance IntegerConstant Int where
+	fromInteger = Prelude.fromInteger
+
+instance ToInteger Int where
+	toInteger = Prelude.toInteger
+
+instance IntegerConstant Integer where
+	fromInteger = Prelude.fromInteger
+
+instance ToInteger Integer where
+	toInteger = Prelude.toInteger
+
+instance Boolean Bool where
+	not = Prelude.not
+	(&&) = (Prelude.&&)
+	(||) = (Prelude.||)
+
+instance Arith Int where
+	type ArithResult Int = Int
+	(+) = (Prelude.+)
+	(-) = (Prelude.-)
+	(*) = (Prelude.*)
+
+instance Arith Integer where
+	type ArithResult Integer = Integer
+	(+) = (Prelude.+)
+	(-) = (Prelude.-)
+	(*) = (Prelude.*)
+
+instance Eq Char where
+	type EqResult Char = Bool
+	(==) = (Prelude.==)
+	(/=) = (Prelude./=)
+
+instance Eq Int where
+	type EqResult Int = Bool
+	(==) = (Prelude.==)
+	(/=) = (Prelude./=)
+
+instance Compare Int Bool where
+	(>) = (Prelude.>)
+	(<) = (Prelude.<)
+	(>=) = (Prelude.>=)
+	(<=) = (Prelude.<=)
+
+instance Arith Word8 where
+	type ArithResult Word8 = Word8
+	(+) = (Prelude.+)
+	(-) = (Prelude.-)
+	(*) = (Prelude.*)
+
+instance Eq Word8 where
+	type EqResult Word8 = Bool
+	(==) = (Prelude.==)
+	(/=) = (Prelude./=)
+
+instance Eq Integer where
+	type EqResult Integer = Bool
+	(==) = (Prelude.==)
+	(/=) = (Prelude./=)
+
+instance IntegerConstant Word8 where
+	fromInteger = Prelude.fromInteger
+
+instance ToInteger Word8 where
+	toInteger = Prelude.toInteger
+ src/Hardware/HHDL/HHDL.hs view
@@ -0,0 +1,1211 @@+{-# LANGUAGE RankNTypes, GADTs, TypeFamilies, TypeOperators, TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-}+{-# LANGUAGE MultiParamTypeClasses, OverlappingInstances, NoImplicitPrelude #-}+{-# LANGUAGE DoRec #-}+-- {-# LANGUAGE NoMonomorphismRestriction #-}++module Hardware.HHDL.HHDL(+	-- convenience exports.+	  module Data.Typeable+	, module Hardware.HHDL.HDLPrelude+	, module Prelude+	, module Control.Monad.Fix+	, module Hardware.HHDL.BitRepr+	, module Hardware.HHDL.TyLeA+	, module Hardware.HHDL.TH+	-- This module exports.+	, (:.)(..), Nil(Nil)	-- our own HList.+	, Wire			-- abstract type.+	, HDL(..)		-- what kind of HDL you want to generate.+	, WireOp(..)		-- the means to extend operations.+	, toBits		-- a method to get bit vector from a type.+	, WList+	, WiresList		-- a class that defines list of wires.+	, NLM+	, Clock(..), ClockAllowed+	, Clocked		-- the type constructor of clocked circuits.+	, mkClockedNamed	-- for top-level exported entities.+	, mkClocked+	, Comb			-- the type constrictor of combinational (stateless) circuits.+	, mkComb+	, Mealy			-- simple MEaly state machine.+	, mkMealyNamed		-- for top-level exported entities.+	, mkMealy+	, assignWire		-- w <- assignWire (expression)+	, assignFlattened+	, register		-- latched <- register defaultValue wireToLatch+	, instantiate		-- instantiate entity, literally. outputs <- instantiate entity inputs+	, constant		-- convert Haskell value (BitRepr one) into wire.+	, writeHDLText		-- write HDL text of an entity.+	, match			-- match expression against list of patterns.+	, (-->)			-- combine pattern and netlists.+	, pvar, pcst, pwild	-- variable match, constant match, wildcard match.+	, pJust, mkJust, pNothing, mkNothing	-- generated for Maybe.+	, pLeft, mkLeft, pRight, mkRight	-- generated for Maybe.+	) where++-- what we need from Prelude:+import Prelude+	( putStrLn, ($), (.), IO, (++), String, repeat, zipWith, head+	, fst, snd, length, map, Show(..), reverse, Int, Integer, flip, filter+	, unwords, unlines, replicate, const, undefined, error, Ordering(..)+	, concat, concatMap, take, tail, iterate, Bool(..), Monad(..)+	, writeFile, otherwise, asTypeOf+	, foldr, foldl, foldl1, zipWith3, zip, init, Maybe(..), Either(..))++import qualified Prelude++import Control.Monad.State+import Control.Monad+import Control.Monad.Fix+import qualified Data.Bits as B+import qualified Data.Bits+import Data.IORef+import Data.List (nub, intersperse)+import Data.Maybe+import qualified Data.Map as Map+import qualified Data.Set as Set+import Data.Typeable+import Data.Word+import qualified Language.Haskell.TH as TH+import System.IO.Unsafe+import qualified Text.Printf++import Hardware.HHDL.BitRepr+import Hardware.HHDL.HDLPrelude+import Hardware.HHDL.TH+import Hardware.HHDL.TyLeA++-------------------------------------------------------------------------------+-- Our own HList.++infixr 5 :.++data a :. as = a :. as deriving Show+data Nil = Nil++-------------------------------------------------------------------------------+-- Unique index generation.++{-# NOINLINE uniqueCounterRef #-}+uniqueCounterRef :: IORef Int+uniqueCounterRef = unsafePerformIO (newIORef 0)++createUniqueIndex :: (String -> Int -> a) -> String -> a+createUniqueIndex mk n = unsafePerformIO $ do+	atomicModifyIORef uniqueCounterRef (\x -> (x+1,()))+	i <- readIORef uniqueCounterRef+	return $ mk n i++-------------------------------------------------------------------------------+-- What is wire.++data Wire clk ty where+	Wire :: Maybe String -> Int -> Wire clk ty+	Expr :: WireOp (op c ty) => op c ty -> Wire c ty++instance Show (Wire c ty) where+	show w = error "No show for wires right now!"++data HDL = VHDL | Verilog+	deriving (Prelude.Eq, Prelude.Ord, Show)++class BitRepr (WireOpType op) => WireOp op where+	type WireOpType op+	-- |Transformation to HDL.+	opToHDL :: BitRepr (WireOpType op) => HDL -> op -> String++	-- |Flattening transformation.+	opFlatten :: op -> NLM clocks op++	opType :: op -> WireOpType op+	opType op = undefined++	opTypeSize :: op -> Int+	opTypeSize op = bitVectorSize (opType op)++data SimpleOps c ty where+	OpConst :: (BitRepr ty, Show ty) => ty -> SimpleOps c ty+	OpSimpleBin :: (BitRepr res, BitRepr arg) =>+		Wire c arg -> [(HDL,String)] -> Wire c arg -> SimpleOps c res+	OpSimpleUn :: (BitRepr res, BitRepr arg) => [(HDL,String)] -> Wire c arg -> SimpleOps c res++instance BitRepr ty => WireOp (Wire c ty) where+	type WireOpType (Wire c ty) = ty+	opToHDL hdl wire = case wire of+		Wire _ _ -> signalName wire+		Expr e -> opToHDL hdl e+	opFlatten w@(Wire _ _) = return w+	opFlatten (Expr e) = liftM Expr $ opFlatten e++toBits :: BitRepr ty => ty -> String+toBits x+	| n > 1 = show bits+	| otherwise = show $ head bits+	where+		i = toBitVector x+		n = bitVectorSize x+		bits = reverse $ concatMap show $ take n $ map snd $ tail $+			iterate ((`Prelude.divMod` 2) . fst) (i,0)++instance BitRepr ty => WireOp (SimpleOps c ty) where+	type WireOpType (SimpleOps c ty) = ty+	opToHDL hdl (OpConst x) = toBits x+	opToHDL hdl (OpSimpleBin l ops r) = opToHDL hdl l++hdlOp++opToHDL hdl r+		where+			hdlOp = (" "++) $ (++" ") $+				maybe (error $ "No op for hdl "++show hdl) Prelude.id $+					Prelude.lookup hdl ops+	opFlatten o@(OpConst x) = return o+	opFlatten (OpSimpleBin l ops r) = do+		l <- assignFlattened l+		r <- assignFlattened r+		return $ OpSimpleBin l ops r++instance (Show ty, BitRepr ty, IntegerConstant ty) => IntegerConstant (Wire c ty) where+	fromInteger i = Expr (OpConst (fromInteger i))++simpleBinAnyHDL a op b = OpSimpleBin a (Prelude.zip [VHDL, Verilog] (repeat op)) b++instance (BitRepr ty, Arith ty, BitRepr (ArithResult ty)) => Arith (Wire c ty) where+	type ArithResult (Wire c ty) = Wire c (ArithResult ty)+	a + b = Expr $ simpleBinAnyHDL a "+" b+	a - b = Expr $ simpleBinAnyHDL a "-" b+	a * b = Expr $ simpleBinAnyHDL a "*" b++instance Boolean (Wire c Bool) where+	not x = Expr $ OpSimpleUn [(VHDL, "not"), (Verilog, "!")] x+	a && b = Expr $ OpSimpleBin a [(VHDL, "and"),(Verilog, "&&")] b+	a || b = Expr $ OpSimpleBin a [(VHDL, "or"),(Verilog, "||")] b+++type family WList c ts+type instance WList c Nil = Nil+type instance WList c (t :. ts)  = Wire c t :. WList c ts++class WiresList a where+	type WireNamesList a+	mkWireList :: Maybe (WireNamesList a) -> NLM clocks a+	copyWireList :: Maybe (WireNamesList a) -> a -> NLM clocks a+instance WiresList Nil where+	type WireNamesList Nil = Nil+	mkWireList _ = return Nil+	copyWireList _ _ = return Nil+instance (BitRepr a, WiresList as) => WiresList (Wire c a :. as) where+	type WireNamesList (Wire c a :. as) = String :. WireNamesList as+	mkWireList names = do+		let (n,ns) = case names of+			Just (n :. ns) -> (Just n, Just ns)+			Nothing -> (Nothing, Nothing)+		a <- mkWire n+		as <- mkWireList ns+		return (a :. as)+	copyWireList names ~(w :. ws) = do+		let (n,ns) = case names of+			Just (n :. ns) -> (Just n, Just ns)+			Nothing -> (Nothing, Nothing)+		w <- assignWithForcedCopy n w+		ws <- copyWireList ns ws+		return (w :. ws)++class RegisterWiresList a clocks where+	type RegisterDefault a+	registerWiresList :: RegisterDefault a -> a -> NLM clocks a+instance RegisterWiresList Nil clocks where+	type RegisterDefault Nil = Nil+	registerWiresList _ _ = return Nil+instance (Show a, BitRepr a, ClockAllowed c clocks, RegisterWiresList as clocks) => RegisterWiresList (Wire c a :. as) clocks where+	type RegisterDefault (Wire c a :. as) = a :. RegisterDefault as+	registerWiresList ~(a :. as) ~(w :. ws) = do+		w' <- register a w+		ws' <- registerWiresList as ws+		return $ w' :. ws'++data SignalKind = BitSignal | BusSignal Int deriving Show++class HDLSignal a where+	signalNameKind :: a -> (String, SignalKind)++signalName :: HDLSignal a => a -> String+signalName = fst . signalNameKind++signalKind :: HDLSignal a => a -> SignalKind+signalKind = snd . signalNameKind++wireBusSize :: BitRepr a => Wire c a -> Int+wireBusSize wire = bitVectorSize (wireType wire)+	where+		wireType :: BitRepr a => Wire c a -> a+		wireType _ = undefined++wireOpBusSize :: (BitRepr (WireOpType op), WireOp op) => op -> Int+wireOpBusSize op = bitVectorSize (projectType op)+	where+		projectType :: WireOp op => op -> WireOpType op+		projectType = undefined++instance BitRepr a => HDLSignal (Wire c a) where+	signalNameKind wire = (name,kind)+		where+			kind = if width == 1 then BitSignal else BusSignal width+			width = wireBusSize wire+			name = case wire of+				Wire Nothing i -> "generated_temporary_name_"++show i+				Wire (Just n) i -> concat [n,"_",show i]+++class HDLSignals a where+	signalsWires :: a -> [(String,SignalKind)]+instance HDLSignals Nil where+	signalsWires Nil = []+instance (HDLSignal a, HDLSignals as) => HDLSignals (a :. as) where+	signalsWires (w :. ws) = signalNameKind w : signalsWires ws++class HDLOp op where+	opArgs :: WiresList as => op clk ty -> as+	opSize :: BitRepr ty => op clk ty -> Int++class (Typeable c, Typeable (ClkReset c)) => Clock c where+	type ClkReset c+	-- |Provide construction of clock value to carry around.+	clockValue :: c+	-- |Reset sensitivity.+	clockResetPositive :: c -> Bool+	-- |Front sensitivity.+	clockFrontEdge :: c -> Bool++changeDotsToUnderscores :: Typeable t => t -> String+changeDotsToUnderscores = map (\c -> if c == '.' then '_' else c) . show . typeOf++clockName :: Clock c => c -> String+clockName c = changeDotsToUnderscores c++clockResetName :: Clock c => c -> String+clockResetName c = changeDotsToUnderscores $ clockReset c+	where+		clockReset :: Clock c => c -> ClkReset c+		clockReset _ = undefined++class ClockList l where+	clockListValue :: l+	clockListClocks :: l -> [String]+	clockListResets :: l -> [String]+instance ClockList Nil where+	clockListValue = Nil+	clockListClocks = const []+	clockListResets = const []+instance (ClockList t, Clock h) => ClockList (h :. t) where+	clockListValue = clockValue :. clockListValue+	clockListClocks (c :. cs) = nub $ clockName c : clockListClocks cs+	clockListResets (c :. cs) = nub $ clockResetName c : clockListResets cs++class (Clock c, ClockList cs) => ClockAllowed c cs+instance (Clock c, Clock c1, ClockAllowed c cs) => ClockAllowed c (c1 :. cs)+instance (Clock c, ClockList (c :. cs)) => ClockAllowed c (c :. cs)++class (ClockList clockSubset, ClockList clockSet) => ClockSubset clockSubset clockSet+instance ClockList clockSet => ClockSubset Nil clockSet+instance (Clock c, ClockAllowed c clockSet, ClockSubset css clockSet, ClockList clockSet) => ClockSubset (c :. css) clockSet++wireClock :: Clock c => Wire c a -> c+wireClock w = clockValue++-- |Basic netlist operations.+data NetlistOp domain where+ 	-- Latching wires. First comes default+	Register :: (ClockAllowed c clocks, BitRepr a, Show a) =>+		a -> Wire c a -> Wire c a -> NetlistOp clocks+++	-- Assign dest what+	-- dest <= what;+	Assign :: BitRepr ty => Wire c ty -> Wire c ty -> NetlistOp clocks++	-- Instance ent+	-- entity ent port map (...);+	Instance :: (Instantiable entity, HDLSignals ins, HDLSignals outs+		, EntityIns entity ~ ins, EntityOuts entity ~ outs) => +		entity -> ins -> outs -> NetlistOp clocks++-- |Netlist type.+data Netlist clocks = Netlist { netlistOperations :: [NetlistOp clocks] }++-- |State of netlist construction monad.+data NLMS domain = NLMS {+	  nlmsNetlist	:: Netlist domain+	, nlmsCounter	:: Int+	}+emptyNLMS :: NLMS clocked+emptyNLMS = NLMS (Netlist []) 0++type NLM clocked a = State (NLMS clocked) a++mkWire :: BitRepr a => Maybe String -> NLM clocked (Wire c a)+mkWire name = do+	n <- liftM nlmsCounter get+	modify $ \nlms -> nlms { nlmsCounter = n+1 }+	return $ Wire name n++tempWire :: BitRepr a => NLM clocked (Wire c a)+tempWire = mkWire Nothing++constant :: (BitRepr a, Show a) => a -> Wire c a+constant c = Expr $ OpConst c++class (ClockList (EntityClocks entity)+	, HDLSignals (EntityIns entity)+	, HDLSignals (EntityOuts entity)+	, GenHDL entity) => Instantiable entity where+	type EntityClocks entity+	type EntityIns entity+	type EntityOuts entity+	getInputsOuputsClocks :: entity+		-> (EntityIns entity, EntityOuts entity, EntityClocks entity)++data Comb ins outs where+	Comb :: (HDLSignals ins, HDLSignals outs) => +		String -> Int -> ins -> outs -> Netlist Nil -> Comb ins outs++instance (HDLSignals ins+	, HDLSignals outs+	, GenHDL (Comb ins outs)) => Instantiable (Comb ins outs) where+	type EntityClocks (Comb ins outs) = Nil+	type EntityIns (Comb ins outs) = ins+	type EntityOuts (Comb ins outs) = outs+	getInputsOuputsClocks (Comb _ _ ins outs _) = (ins, outs, Nil)++runNetlistCreation :: (WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs)+	=> Maybe (WireNamesList ins, WireNamesList outs)+	-> (ins -> outs -> Netlist domain -> a) -> (ins -> NLM domain outs) -> a+runNetlistCreation names q f = mk $ do+	ins <- mkWireList (fmap fst names)+	outs <- f ins+	outs <- copyWireList (fmap snd names) outs+	return (ins,outs)+	where+		mk act = (\((ins,outs),nlms) -> q ins outs (nlmsNetlist nlms)) $+			runState act emptyNLMS++-- |Create a combinational circut with named inputs and outputs from netlist description.+mkCombNamed :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs)+	=> Maybe (WireNamesList ins, WireNamesList outs) -> String -> (ins -> NLM Nil outs) -> Comb ins outs+mkCombNamed names n f = runNetlistCreation names (createUniqueIndex Comb n) f++-- |Create a combinational circut anonymous inputs and outputs from netlist description.+mkComb :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs)+	=> String -> (ins -> NLM Nil outs) -> Comb ins outs+mkComb n f = mkCombNamed Nothing n f++-- |Create a combinational circuit from pure function.+-- You can easily shoot your foot here by creating cyclic expressions like+-- 'f a = y where { x = a+y; y = x-a}.+-- Use with care.+mkCombPure :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs) => String -> (ins -> outs) -> Comb ins outs+mkCombPure n f = mkComb n (\ins -> return (f ins))++data Clocked clks ins outs where+	Clocked :: (HDLSignals ins, HDLSignals outs, ClockList clks) =>+		clks -> String -> Int -> ins -> outs -> Netlist clks -> Clocked clks ins outs++instance (ClockList clks+	, HDLSignals ins+	, HDLSignals outs+	, GenHDL (Clocked clks ins outs)) => Instantiable (Clocked clks ins outs) where+	type EntityClocks (Clocked clks ins outs) = clks+	type EntityIns (Clocked clks ins outs) = ins+	type EntityOuts (Clocked clks ins outs) = outs+	getInputsOuputsClocks (Clocked clks _ _ ins outs _) = (ins, outs, clks)++mkClockedNamed :: (ClockList clks, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs)+	=> Maybe (WireNamesList ins, WireNamesList outs) -> String+	-> (ins -> NLM clks outs) -> Clocked clks ins outs+mkClockedNamed names n f = runNetlistCreation names (createUniqueIndex (Clocked clockListValue) n) f++mkClocked :: (ClockList clks, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs)+	=> String -> (ins -> NLM clks outs) -> Clocked clks ins outs+mkClocked n f = mkClockedNamed Nothing n f++data Mealy clk ins outs where+	Mealy :: (HDLSignals ins, HDLSignals outs, Clock clk) =>+		clk -> String -> Int -> ins -> outs -> Netlist (clk :. Nil) -> Mealy clk ins outs++instance (Clock clk+	, HDLSignals ins+	, HDLSignals outs+	, GenHDL (Mealy clk ins outs)) => Instantiable (Mealy clk ins outs) where+	type EntityClocks (Mealy clk ins outs) = clk :. Nil+	type EntityIns (Mealy clk ins outs) = ins+	type EntityOuts (Mealy clk ins outs) = outs+	getInputsOuputsClocks (Mealy clk _ _ ins outs _) = (ins, outs, clk :. Nil)++mkMealyNamed :: (Clock clk, WiresList state, HDLSignals state, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs, RegisterWiresList state (clk :. Nil))+	=> Maybe (WireNamesList ins, WireNamesList outs)+	-> RegisterDefault state -> String -> (state -> ins -> NLM (clk :. Nil) (state, outs))+	-> Mealy clk ins outs+mkMealyNamed names defs n f = runNetlistCreation names (createUniqueIndex (Mealy clockValue) n) action+	where+		action ins = do+			rec+				state <- registerWiresList defs nextState+				~(nextState, outs) <- f state ins+			return outs+mkMealy:: (Clock clk, WiresList state, HDLSignals state, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs, RegisterWiresList state (clk :. Nil))+	=> RegisterDefault state -> String -> (state -> ins -> NLM (clk :. Nil) (state, outs))+	-> Mealy clk ins outs+mkMealy defs n f = mkMealyNamed Nothing defs n f++-------------------------------------------------------------------------------+-- BitRepr instances.++instance BitRepr Int where+	type BitVectorSize Int = $(tySize 32)+	toBitVector x = convertThroughInteger x+	fromBitVector x = convertThroughInteger x+	bitVectorSize x = 32++instance BitRepr Word8 where+	type BitVectorSize Word8 = $(tySize 8)+	toBitVector x = convertThroughInteger x+	fromBitVector x = convertThroughInteger x+	bitVectorSize x = 8++instance BitRepr Nil where+	type BitVectorSize Nil = $(tySize 0)+	toBitVector x = 0+	fromBitVector x = Nil+	bitVectorSize x = 0++instance (BitRepr a, BitRepr as+	, Nat (Plus (BitVectorSize a) (BitVectorSize as)))+	=> BitRepr (a :. as) where+	type BitVectorSize (a :. as) = Plus (BitVectorSize a) (BitVectorSize as)+	toBitVector (a :. as) = B.shiftL (toBitVector a) (bitVectorSize as)+		B..|. toBitVector as+	fromBitVector x = a :. as+		where+			mask :: BitRepr a => a -> Integer+			mask x = B.shiftL (1 :: Integer) (bitVectorSize x) - 1+			ys = x B..&. mask as+			y = B.shiftR x (bitVectorSize as) B..&. mask a+			a = fromBitVector y+			as = fromBitVector ys+	bitVectorSize (a :. as) = bitVectorSize a + bitVectorSize as++instance BitRepr () where+	type BitVectorSize () = $(tySize 0)+	toBitVector = const 0+	fromBitVector = const ()++-------------------------------------------------------------------------------+-- Dumping HDL.++data HDLGenState = HDLGenState {+	-- errors, if we encounter any.+	  hdlgErrors		:: [String]+	-- Mapping from entities to their "real" names.+	, hdlgGeneratedEntities	:: Map.Map (String, Int) String+	-- how deep we recurred?+	, hdlgRecursionLevel	:: Int+	-- lines of generated text. In reverse order.+	, hdlgTextLines		:: [String]+	-- nesting level.+	, hdlgNestLevel		:: Int+	-- what kind of language we generate.+	, hdlgLanguage		:: HDL+	-- set of defined names.+	, hdlgDefinedNames	:: Set.Set String+	}+	deriving (Prelude.Eq, Prelude.Ord, Show)+type HDLGen a = State HDLGenState a++emptyHDLGenState hdl = HDLGenState {+	  hdlgErrors		= []+	, hdlgGeneratedEntities	= Map.empty+	, hdlgRecursionLevel	= 0+	, hdlgTextLines		= []+	, hdlgNestLevel		= 0+	, hdlgLanguage		= hdl+	, hdlgDefinedNames	= Set.empty+	}++runHDLGeneration :: GenHDL a => HDL -> a -> (String, [String])+runHDLGeneration hdl entity = (text, errors)+	where+		errors = hdlgErrors state+		text = unlines $ reverse $ hdlgTextLines state+		(_,state) = runState (generateHDL entity) (emptyHDLGenState hdl)++generateLine :: String -> HDLGen ()+generateLine s = modify $ \hdlg -> hdlg {+		  hdlgTextLines = (replicate (hdlgNestLevel hdlg) ' '++s) : hdlgTextLines hdlg+		}++generateEmptyLines :: Int -> HDLGen ()+generateEmptyLines n = modify $ \hdlg -> hdlg {+		  hdlgTextLines = (replicate n "") ++ hdlgTextLines hdlg+		}++generateNest :: HDLGen a -> HDLGen a+generateNest act = do+	nest <- liftM hdlgNestLevel get+	modify $ \hdlg -> hdlg { hdlgNestLevel = nest + 4 }+	x <- act+	modify $ \hdlg -> hdlg { hdlgNestLevel = nest }+	return x++generateDashes :: HDLGen ()+generateDashes = modify $ \hdlg -> hdlg {+		  hdlgTextLines = dashesLine (hdlgLanguage hdlg) (hdlgNestLevel hdlg)+			 : hdlgTextLines hdlg+		}+	where+		dashesLine hdl n = concat [replicate n ' ',prefix hdl, replicate (79-n-2) '-']+		prefix hdl = case hdl of+			VHDL -> "--"+			Verilog -> "//"++generateError :: String -> HDLGen ()+generateError err = modify $ \hdlg -> hdlg { hdlgErrors = err : hdlgErrors hdlg}++generateComment :: String -> HDLGen ()+generateComment c = do+	hdl <- liftM hdlgLanguage get+	let commentPrefix = case hdl of+		VHDL -> "--"+		Verilog -> "//"+	generateLine $ unwords [commentPrefix,c]++generateDashesComment :: String -> HDLGen ()+generateDashesComment c = do+	generateDashes+	generateComment c++generateDefineName :: String -> HDLGen ()+generateDefineName name = modify $ \hdlg -> hdlg {+	  hdlgDefinedNames = Set.insert name $ hdlgDefinedNames hdlg+	}++generateFilterDefined :: [a] -> (a -> String) -> HDLGen [a]+generateFilterDefined things nameProjection = do+	defined <- liftM hdlgDefinedNames get+	let things' = filter (not . flip Set.member defined . nameProjection) things+	mapM (generateDefineName . nameProjection) things'+	return things'++class GenHDL a where+	generateHDL :: a -> HDLGen ()++names :: HDLSignals s => s -> [String]+names s = map fst $ signalsWires s+entityPortsList dir signals = (+			 map fst wiresKinds+			,map (\(name,kind) -> (name,unwords [name,":",dir,vhdlType kind])) wiresKinds)+			where+				wiresKinds = signalsWires signals+				vhdlType BitSignal = "bit"+				vhdlType (BusSignal width) =+					"unsigned ("++show (width-1)++" downto 0)"+generateHDLForEntity :: (HDLSignals ins, HDLSignals outs, ClockList clocks) =>+	String -> Int -> ins -> outs -> clocks -> Netlist domain -> HDLGen ()+generateHDLForEntity name index ins outs clocks netlist = do+	hdl <- liftM hdlgLanguage get+	n <- liftM (Map.lookup key . hdlgGeneratedEntities) get+	case n of+		Nothing -> do+			ourName <- registerOurEntity+			mapM_ subEntity $ netlistOperations netlist+			case hdl of+				VHDL -> vhdlText ourName+				Verilog -> verilogText ourName+		Just _ -> return ()+	where+		key = (name, index)+		registerOurEntity = do+			names <- liftM (Set.fromList . Map.elems . hdlgGeneratedEntities) get+			let newNames = map (name++) $+				map ('_':) $ map show [(1::Int)..]+			let ourName = head $ filter (not . (`Set.member` names)) newNames+			modify $ \hdlgs -> hdlgs { hdlgGeneratedEntities = Map.insert key ourName $ hdlgGeneratedEntities hdlgs }+			return ourName+		subEntity :: NetlistOp domain -> HDLGen ()+		subEntity (Instance entity ins outs) = do+			generateHDL entity+		subEntity _ = return ()+		generateEntityClocksResets clks = map addTypeDir $ clocks ++ resets+			where+				addTypeDir name = name ++ ": in std_logic"+				clocks = clockListClocks clks+				resets = clockListResets clks+		generateVHDLDeclarations ops' = do+			ops <- generateFilterDefined ops' fst+			forM ops $ \(name, kind) -> do+				let ty = case kind of+					BitSignal -> "bit"+					BusSignal n -> "unsigned ("++show (n-1)++" downto 0)"+				generateLine $ concat ["signal ", name, " : ", ty,";"]+			return ()+		declareOperationSignals :: NetlistOp domain -> HDLGen ()+		declareOperationSignals op = generateVHDLDeclarations $ case op of+			Register _ wa wb -> signalsWires $ wa :. Nil+			Assign wa op -> signalsWires $ wa :. Nil+			Instance entity ins outs -> signalsWires outs+		vhdlOperation :: NetlistOp domain -> HDLGen ()+		vhdlOperation op = case op of+			Register def wa wb -> do+				let c = wireClock wa+				let cn = clockName c+				let edge = (if clockFrontEdge c then "rising_edge" else "falling_edge")+					++"("++cn++")"+				let rn = clockResetName c+				let resetFunc = +					rn ++ " = "+					++ (if clockResetPositive c then "'1'" else "'0'")+				generateLine $ "process ("++cn++", "++rn++") is"+				generateLine $ "begin"+				generateNest $ do+					generateLine $ unwords ["if",resetFunc, "then"]+					generateNest $ vhdlOperation (Assign wa (constant def))+					generateLine $ unwords ["elsif",edge, "then"]+					generateNest $ vhdlOperation (Assign wa wb)+					generateLine "end if;"+				generateLine $ "end process;"+			Assign wa op -> do+				generateLine $ concat+					[signalName wa, " <= "+					,opToHDL VHDL op, ";"]+			Instance entity ins outs -> do+				let (eins, eouts, eclks) = getInputsOuputsClocks entity+				let insNames = names ins+				let outsNames = names outs+				let einsNames = names eins+				let eoutsNames = names eouts+				let clocks = nub $ clockListClocks eclks+				let resets = nub $ clockListResets eclks+				let connect a b = a ++" => " ++ b+				let allNames = zipWith connect insNames einsNames+					++ zipWith connect outsNames eoutsNames+					++ map (\c -> connect c c) clocks+					++ map (\c -> connect c c) resets+				let withCommas = zipWith (++) ("  ":repeat ", ") allNames+				generateLine "entity ("+				generateNest $ mapM generateLine withCommas+				generateLine ");"+		vhdlText name = do+			generateEmptyLines 2+			generateDashesComment $ "Entity declaration and architecture for "++name++"."+			generateEmptyLines 1+			generateLine "library ieee;"+			generateLine "use ieee.std_logic_1164.all;"+			generateLine "use ieee.numeric_bit.all;"+			generateEmptyLines 1+			generateLine $ "entity "++name++" is"+			generateNest $ do+				generateLine "port ("+				let (inputsNames,inputs) =+					entityPortsList "in" ins+				let (outputsNames, outputs) =+					entityPortsList "out" outs+				let clockResets = generateEntityClocksResets clocks+				let inouts = inputs ++ outputs+				let allSignals = (map snd inouts) ++ clockResets+				let signals = reverse $+					zipWith (++) (reverse allSignals) ("" : repeat ";")+				mapM generateDefineName $ map fst inouts+				generateNest $ do+					mapM generateLine signals+				generateLine ");"+				return $ inputsNames ++ outputsNames+			generateLine $ "end entity "++name++";"+			generateEmptyLines 2+			generateLine $ "architecture hhdl_generated of "++name++" is"+			generateNest $ do+				addSupportFunctions+				mapM declareOperationSignals $ netlistOperations netlist+			generateLine $ "begin"+			generateNest $ do+				mapM vhdlOperation $ netlistOperations netlist+			generateLine $ "end architecture hhdl_generated;"+			return ()++		verilogText name = do+			generateLine $ "Verilog text for entity "++name++		addSupportFunctions = mapM generateLine [+			  replicate 60 '-'+			, "-- Supporting functions."+			, ""+			, "pure function select_func(s : in bit; t, f : in bit) return bit is"+			, "begin"+			, "    if s = '1' then"+			, "        return t;"+			, "    else"+			, "        return f;"+			, "    end if;"+			, "end function select_func;"+			, ""+			, "pure function select_func(s : in bit; t, f : in unsigned) return unsigned is"+			, "begin"+			, "    if s = '1' then"+			, "        return t;"+			, "    else"+			, "        return f;"+			, "    end if;"+			, "end function select_func;"+			, ""+			, "pure function bit_equality(a, b : in bit) return bit is"+			, "begin"+			, "    if a = b then"+			, "        return '1';"+			, "    else"+			, "        return '0';"+			, "    end if;"+			, "end function bit_equality;"+			, ""+			, "pure function bit_equality(a, b : in unsigned) return bit is"+			, "begin"+			, "    if a = b then"+			, "        return '1';"+			, "    else"+			, "        return '0';"+			, "    end if;"+			, "end function bit_equality;"+			, ""+			]++instance GenHDL (Comb ins outs) where+	generateHDL (Comb name index ins outs netlist) = do+		generateHDLForEntity name index ins outs Nil netlist++instance GenHDL (Clocked cs ins outs) where+	generateHDL (Clocked clocks name index ins outs netlist) = do+		generateHDLForEntity name index ins outs clocks netlist++instance GenHDL (Mealy c ins outs) where+	generateHDL (Mealy c name index ins outs netlist) = do+		generateHDLForEntity name index ins outs (c :. Nil) netlist++writeHDLText :: GenHDL a => HDL -> a -> (String -> IO ()) -> IO ()+writeHDLText hdl entity write = do+	let (text, errors) = runHDLGeneration hdl entity+	write text+	case errors of+		[] -> return ()+		errs -> do+			putStrLn $ "\n\n\nErrors:"+			mapM putStrLn errs+			putStrLn "------------------"+			putStrLn $ "Total " ++ show (length errs) ++ " errors in HDL generation."++-------------------------------------------------------------------------------+-- Bit vectors.++data BV size = BV Integer++instance Nat size => BitRepr (BV size) where+	type BitVectorSize (BV size) = size+	toBitVector (BV i) = i+	fromBitVector i = r+		where+			r = BV (i B..&. bitMask r)++instance Nat size => IntegerConstant (BV size) where+	fromInteger i = fromBitVector i++instance Show (BV size) where+	showsPrec n (BV i) = (concat [o,Text.Printf.printf "BV 0x%x" i,c]++)+		where+			(o,c)+				| n > 10 = ("(",")")+				| otherwise = ("","")++instance Nat size => Eq (BV size) where+	type EqResult (BV size) = Bool+	a == b = toBitVector a == toBitVector b+	a /= b = toBitVector a /= toBitVector b++_toSelBusSizeBitVector :: AlgTypeBitEnc a => a -> BV (SelectorBusSize a)+_toSelBusSizeBitVector = undefined++_toSelBusSizeBitVectorWireExpr :: AlgTypeBitEnc a => Wire c a -> BV (SelectorBusSize a)+_toSelBusSizeBitVectorWireExpr = undefined++_toArgsBusSizeBitVector :: AlgTypeBitEnc a => Wire c a -> Wire c (BV (ArgsBusSize a))+_toArgsBusSizeBitVector = undefined++-------------------------------------------------------------------------------+-- Netlist operations.++addNetlistOperation op =+	modify $ \nlms -> nlms {+	  nlmsNetlist = Netlist $ op : netlistOperations (nlmsNetlist nlms)+	}+register :: (ClockAllowed c clocks, BitRepr a, Show a) => a -> Wire c a -> NLM clocks (Wire c a)+register resetValue computedValue = do+	w <- tempWire+	modify $ \nlms -> nlms {+		  nlmsNetlist = Netlist (Register resetValue w computedValue : netlistOperations (nlmsNetlist nlms))+		}+	return w++instantiate :: (Instantiable entity, ClockSubset (EntityClocks entity) clocks+	, WiresList (EntityIns entity), WiresList (EntityOuts entity)) =>+	entity -> EntityIns entity -> NLM clocks (EntityOuts entity)+instantiate entity ins = do+	outs <- mkWireList Nothing+	addNetlistOperation $ Instance entity ins outs+	return outs++assignWire :: (BitRepr ty) => Wire c ty -> NLM registers (Wire c ty)+assignWire what = do+	assignFlattened what++assignWithForcedCopy n wire = do+	t <- mkWire n+	addNetlistOperation $ Assign t wire+	return t++assignFlattened :: (BitRepr ty) => Wire c ty -> NLM registers (Wire c ty)+assignFlattened w@(Wire _ _) = return w+assignFlattened (Expr op) = do+	op <- opFlatten op+	assignWithForcedCopy Nothing $ Expr op++extendZero :: (Nat src, Nat dest) => Wire c (BV src) -> Wire c (BV dest)+extendZero what = Expr $ Extend False what++extendSign :: (Nat src, Nat dest) => Wire c (BV src) -> Wire c (BV dest)+extendSign what = Expr $ Extend True what++castWires :: (BitRepr src, BitRepr res, BitVectorSize src ~ BitVectorSize res) =>+	Wire c src -> Wire c res+castWires what = Expr $ CastWires what++_runPureNetlist :: NLM Nil a -> NLM clocks a+_runPureNetlist action = do+	s <- get+	let (a,s') = runState action (copyNLMS s)+	put (copyNLMSBack s' s)+	return a+	where+		copyNLMS (NLMS (Netlist netlist) cntr) = NLMS (Netlist []) cntr+		copyNLMSBack :: NLMS Nil -> NLMS clocks -> NLMS clocks+		copyNLMSBack (NLMS (Netlist ops1) cntr) (NLMS (Netlist ops2) _)+			= NLMS (Netlist $ copyOps ops1 ops2) cntr+		copyOps :: [NetlistOp Nil] -> [NetlistOp clocks] -> [NetlistOp clocks]+		copyOps [] ops2 = ops2+		copyOps (Assign to what : ops1) ops2 = copyOps ops1 (ops2++[Assign to what])+		copyOps (Instance ent ins outs  : ops1) ops2 = copyOps ops1 (ops2++[Instance ent ins outs])++-------------------------------------------------------------------------------+-- Operations for expressions.++data Extend c dest where+	-- bool flag is whether we're using sign (we are when True).+	Extend :: (Nat src, Nat res) => Bool -> Wire c (BV src) -> Extend c (BV res)++instance BitRepr res => WireOp (Extend c res) where+	type WireOpType (Extend c res) = res+	opToHDL hdl op@(Extend signExtendFlag arg)+		| widen = widenExpr+		| narrow = narrowExpr+		| otherwise = subExpr+		where+			destSize = wireOpBusSize op+			srcSize = wireOpBusSize arg+			widen = destSize > srcSize+			narrow = destSize > srcSize+			delta = destSize - srcSize+			sign = case hdl of+				VHDL -> subExpr ++"("++show (srcSize-1)++")"+				Verilog -> subExpr ++"["++show (srcSize-1)++"]"+			extension = case hdl of+				VHDL -> if signExtendFlag+						then concat $ intersperse " & " (replicate delta sign)+						else show (replicate delta '0')+				Verilog -> if signExtendFlag+						then concat $ intersperse ", " (replicate delta sign)+						else show (replicate delta '0')+			subExpr = opToHDL hdl arg+			widenExpr = case hdl of+				VHDL -> unwords [extension, subExpr]+				Verilog -> "{"++concat [extension, ", ", subExpr]++"}"+			narrowExpr = case hdl of+				VHDL -> subExpr ++"("++show (destSize-1)++" downto 0)"+	opFlatten (Extend se a) = liftM (Extend se) $ assignFlattened a++data CastWires c res where+	-- bool flag is whether we're using sign (we are when True).+	CastWires :: (BitRepr src, BitRepr res, BitVectorSize src ~ BitVectorSize res) =>+		Wire c src -> CastWires c res++instance BitRepr res => WireOp (CastWires c res) where+	type WireOpType (CastWires c res) = res+	opToHDL hdl (CastWires op) = opToHDL hdl op+	opFlatten (CastWires op) = do+		op <- assignFlattened op+		return $ CastWires op++class BitRepr (WireOpListTypes a) => WireOpList a where+	type WireOpListTypes a+--	type WireOpListClock a+	opsToHDL :: HDL -> a -> [String]+instance WireOpList Nil where+	type WireOpListTypes Nil = Nil+	opsToHDL hdl = const []+instance (WireOp x, WireOpList xs+	, Nat (Plus (BitVectorSize (WireOpType x)) (BitVectorSize (WireOpListTypes xs)))) => WireOpList (x :. xs) where+	type WireOpListTypes (x :. xs) = WireOpType x :. WireOpListTypes xs+	opsToHDL hdl (a :. as) = opToHDL hdl a : opsToHDL hdl as++data SplitWiresOp c r where+	SplitWiresOp :: BitRepr s => Wire c s -> Int -> SplitWiresOp c r++instance BitRepr r => WireOp (SplitWiresOp c r) where+	type WireOpType (SplitWiresOp c r) = r+	opToHDL hdl x@(SplitWiresOp wire ofs) = case hdl of+		VHDL+			| rSize > 1 -> unwords [subExpr, "(", show (rSize+ofs-1), "downto", show ofs, ")"]+			| otherwise -> unwords [subExpr, "(", show ofs,")"]+		Verilog -> error "Verilog SplitWiresOp!!!"+		where+			rSize = opTypeSize x+			subExpr = opToHDL hdl wire+	opFlatten (SplitWiresOp wire ofs) = liftM (\w -> SplitWiresOp w ofs) $ assignFlattened wire++type family SplitProjection c w+class BitRepr w => SplitWires w where+	splitWires :: Wire c w -> SplitProjection c w++instance (BitRepr a, BitRepr b, Nat (Plus (BitVectorSize a) (BitVectorSize b)), Nat (BitVectorSize(a,b))) => BitRepr (a,b) where+	type BitVectorSize (a,b) = Plus (BitVectorSize a) (BitVectorSize b)+	toBitVector (x0,x1) = B.shiftL (toBitVector x0) (bitVectorSize x1) B..|. toBitVector x1+	fromBitVector v = (x0,x1)+		where+			x1 = fromBitVector v+			x0 = fromBitVector (B.shiftR v (bitVectorSize x1))++type instance SplitProjection c (a,b) = (Wire c a, Wire c b)+instance (BitRepr a, BitRepr b, BitRepr (a,b)) => SplitWires (a,b) where+	splitWires wab = (wa, wb)+		where+			wa = Expr $ SplitWiresOp wab (wireBusSize wb)+			wb = Expr $ SplitWiresOp wab 0++splitWires2 :: (BitRepr a, BitRepr b, BitRepr (a,b)) => Wire clk (a,b) -> (Wire clk a, Wire clk b)+splitWires2 = splitWires++$(liftM concat $ forM [3..8] $ \n -> let+		typeNames' = map (\i -> TH.mkName ("t_"++show i)) [1..n]+		typeNames = map TH.VarT typeNames'+		ty = foldl TH.AppT (TH.TupleT n) typeNames+		clkN = TH.mkName "clk"+		clk = TH.VarT clkN+		wireTy ty = TH.ConT (TH.mkName "Wire") `TH.AppT` clk `TH.AppT` ty+		wiresTy = foldl TH.AppT (TH.TupleT n) $ map wireTy typeNames+		bitReprP ty = TH.ClassP (TH.mkName "BitRepr") [ty]+		bitVectorSizeT ty = TH.ConT (TH.mkName "BitVectorSize") `TH.AppT` ty+		commonCxt = map bitReprP typeNames+		brCxt = TH.ClassP (TH.mkName "Nat") [bitVectorSizeT ty] : commonCxt+		swCxt = bitReprP ty : commonCxt+		argNames = map (\i -> TH.mkName ("x"++show i)) [1..n]+		shiftNames = map (\i -> TH.mkName ("s"++show i)) [1..n]+		argVars = map TH.VarE argNames+		prevArgs = Prelude.scanr (:) [] argVars+		sumWidths ws = foldr (\a b -> TH.InfixE (Just a) (TH.VarE $ TH.mkName "+") (Just b)) (TH.LitE $ TH.IntegerL 0) $ map (TH.AppE (TH.VarE (TH.mkName "wireBusSize"))) ws+		def v widths = flip (TH.ValD (TH.VarP v)) [] $ TH.NormalB $+			TH.ConE (TH.mkName "Expr") `TH.AppE`+			(TH.ConE (TH.mkName "SplitWiresOp")+				`TH.AppE` vV `TH.AppE` sumWidths widths)+		defs = zipWith def argNames (tail prevArgs)+		vN = TH.mkName "v"+		vV = TH.VarE vN+		bitVecSizeTy = TH.TySynInstD (TH.mkName "BitVectorSize") [ty] $+			foldl1 (\a b -> TH.ConT (TH.mkName "Plus") `TH.AppT` a `TH.AppT` b) $ map bitVectorSizeT typeNames+		defShift Nothing def arg = TH.ValD (TH.VarP def) (TH.NormalB $ TH.LitE $ TH.IntegerL 0) []+		defShift (Just prev) def arg = TH.ValD (TH.VarP def) (TH.NormalB $ TH.InfixE (Just (TH.VarE prev)) (TH.VarE $ TH.mkName "+") (Just sz)) []+			where+				sz = TH.VarE (TH.mkName "bitVectorSize") `TH.AppE` TH.VarE arg+		shiftDefs = Prelude.zipWith3 defShift (map Just (Prelude.init shiftNames) ++ [Nothing]) shiftNames argNames+		toBVE = Prelude.foldr1 (\x y -> TH.InfixE (Just x) (TH.VarE $ TH.mkName "Data.Bits..|.") (Just y))+			$ zipWith (\x s -> TH.VarE (TH.mkName "Data.Bits.shiftL")+				`TH.AppE` (TH.VarE (TH.mkName "toBitVector") `TH.AppE` TH.VarE x)+				`TH.AppE` TH.VarE s) argNames shiftNames+		toBV = TH.FunD (TH.mkName "toBitVector")+			[TH.Clause [TH.TupP $ map TH.VarP argNames] (TH.NormalB toBVE) shiftDefs]+		fromBVEShiftDef x s pxs = [+			  TH.ValD (TH.VarP x) (TH.NormalB convertedX) []+			, TH.ValD (TH.VarP s) (TH.NormalB shiftE) []+			]+			where+				vx = TH.VarE x+				convertedX = TH.VarE (TH.mkName "fromBitVector") `TH.AppE` shiftedV+				shiftedV = TH.VarE (TH.mkName "Data.Bits.shiftR") `TH.AppE` vV `TH.AppE` TH.VarE s+				shiftE = case pxs of+					Nothing -> TH.LitE $ TH.IntegerL 0+					Just (x,s) -> TH.InfixE+						(Just $ TH.VarE (TH.mkName "bitVectorSize") `TH.AppE` TH.VarE x)+						(TH.VarE $ TH.mkName "+")+						(Just $ TH.VarE s)+		shiftArgs as = map Just (tail as) ++ [Nothing]+		fromBVEShiftDefs = concat $ zipWith3 fromBVEShiftDef argNames shiftNames (shiftArgs $ zip argNames shiftNames)+		fromBVE = TH.TupE $ map TH.VarE argNames+		fromBV = TH.FunD (TH.mkName "fromBitVector")+			[TH.Clause [TH.VarP vN] (TH.NormalB fromBVE) fromBVEShiftDefs]+		split = TH.FunD (TH.mkName "splitWires")+			[TH.Clause [TH.VarP vN] (TH.NormalB $ TH.TupE argVars) defs]+		specializedSplitN = TH.mkName $ "splitWires"++show n+		decls = [ TH.InstanceD swCxt (TH.ConT (TH.mkName "SplitWires") `TH.AppT` ty) [split]+			, TH.TySynInstD (TH.mkName "SplitProjection") [clk,ty] wiresTy+			, TH.InstanceD brCxt (TH.ConT (TH.mkName "BitRepr") `TH.AppT` ty) [bitVecSizeTy, toBV, fromBV]+			, TH.SigD specializedSplitN $ TH.ForallT (map TH.PlainTV $ clkN : typeNames') brCxt $ (TH.AppT (TH.AppT TH.ArrowT $ wireTy ty) wiresTy)+			, TH.FunD specializedSplitN [TH.Clause [] (TH.NormalB $ TH.VarE (TH.mkName "splitWires")) []]+			]+	in do+--		runIO $ mapM (putStrLn . show . ppr) decls+		return decls+ )++_castAlgTypeToPair :: (Nat (Plus (SelectorBusSize a) (ArgsBusSize a)), BitRepr a+	, Plus (SelectorBusSize a) (ArgsBusSize a) ~ BitVectorSize a, AlgTypeBitEnc a) => Wire c a -> Wire c (BV (SelectorBusSize a), BV (ArgsBusSize a))+_castAlgTypeToPair w = castWires w+_splitAlgType :: (Plus (SelectorBusSize a) (ArgsBusSize a) ~ BitVectorSize a, Nat (Plus (SelectorBusSize a) (ArgsBusSize a)), AlgTypeBitEnc a, BitRepr a) => Wire c a -> (Wire c (BV (SelectorBusSize a)), Wire c (BV (ArgsBusSize a)))+_splitAlgType w = splitWires $ _castAlgTypeToPair w+_castArgsWires :: (Nat (ArgsBusSize a), AlgTypeBitEnc a, BitRepr a, BitRepr b) => Wire c a -> Wire c (BV (ArgsBusSize a)) -> Wire c b+_castArgsWires a w = r+	where+		r = castWires (extendZero w)++data Join c w where+	Join :: (BitRepr a, BitRepr b) => Wire c a -> Wire c b -> Join c (a :. b)++instance BitRepr w => WireOp (Join c w) where+	type WireOpType (Join c w) = w+	opToHDL hdl (Join l r) = case hdl of+		VHDL -> unwords ["(",opToHDL hdl l,"&",opToHDL hdl r,")"]+		Verilog -> concat ["{",opToHDL hdl l,",",opToHDL hdl r,"}"]+	opFlatten (Join l r) = liftM2 Join (assignFlattened l) (assignFlattened r)++infixr 5 &+(&) :: (BitRepr a, BitRepr b, Nat (Plus (BitVectorSize a) (BitVectorSize b))) => Wire c a -> Wire c b -> Wire c (a :. b)+a & b = Expr $ Join a b++data Equality c w where+	-- first is the flag for equality testing, if true.+	Equality :: BitRepr w => Bool -> Wire c w -> Wire c w -> Equality c Bool++instance BitRepr w => WireOp (Equality c w) where+	type WireOpType (Equality c w) = w+	opToHDL hdl (Equality eq l r) = case hdl of+		VHDL -> concat ["bit_equality( ", opToHDL hdl l,", ", opToHDL hdl r,")"]+		Verilog -> error "Equality Verilog!!!"+		where+			op = case hdl of+				VHDL -> if eq then "=" else "/="+				Verilog -> if eq then "==" else "!="+	opFlatten (Equality eq l r) = liftM2 (Equality eq) (assignFlattened l) (assignFlattened r)++instance (Eq w, EqResult w ~ Bool, BitRepr w) => Eq (Wire c w) where+	type EqResult (Wire c w) = Wire c Bool+	a == b = Expr $ Equality True  a b+	a /= b = Expr $ Equality False a b++data Select c w where+	Select :: Wire c Bool -> Wire c a -> Wire c a -> Select c a++instance BitRepr a => WireOp (Select c a) where+	type WireOpType (Select c a) = a+	opToHDL hdl (Select c l r) = case hdl of+		VHDL -> concat["select_func(",cv, ", ", lv,", ",rv,")"]+		Verilog -> error "Verilog Select!!!"+		where+			cv = opToHDL hdl c+			lv = opToHDL hdl l+			rv = opToHDL hdl r+	opFlatten (Select c l r) = do+		c <- assignFlattened c+		l <- assignFlattened l+		r <- assignFlattened r+		return $ Select c l r++selectWires :: BitRepr a => Wire c Bool -> Wire c a -> Wire c a -> Wire c a+selectWires sel true false = Expr $ Select sel true false++-------------------------------------------------------------------------------+-- Pattern matching.+-- We hardwire (pun intended) Wire(s) into Patterns because we can match+-- only on bit vectors. And those bit vectors get transferred by Wire(s).++type family ConcatPatList a b+type instance ConcatPatList a b = ConcatWiresList (a :. b)+--type instance ConcatPatList (x :. xs) ys = x :. (ConcatPatList xs ys)++class (WiresList (ConcatWiresList a)) => WiresListConcat a where+	type ConcatWiresList a+	concatWiresList :: a -> ConcatWiresList a++instance WiresListConcat Nil where+	type ConcatWiresList Nil = Nil+	concatWiresList Nil = Nil++instance WiresList as => WiresListConcat (Nil :. as) where+	type ConcatWiresList (Nil :. as) = as+	concatWiresList (Nil :. as) = as++instance (WiresListConcat (as :. bs), WiresList (a :. ConcatWiresList (as :. bs))) => WiresListConcat ((a :. as) :. bs) where+	type ConcatWiresList ((a :. as) :. bs) = a :. ConcatWiresList (as :. bs)+	concatWiresList ((a :. as) :. bs) = a :. concatWiresList (as :. bs)++data PatMatch v r where+	PatMatch :: (Wire c v -> NLM Nil (Wire c Bool, Wire c result))+		-> PatMatch (Wire c v) (Wire c result)++data Pattern w o where+	Pattern :: {unPattern :: WiresList o => (Wire c w -> NLM Nil (o, Wire c Bool))} -> Pattern (Wire c w) o++match :: (ClockAllowed c registers, BitRepr v, BitRepr r) => Wire c v+	-> [PatMatch (Wire c v) (Wire c r)] -> NLM registers (Wire c r)+match v ms = do+	w <- assignWire v+	_runPureNetlist $ reduceMatches w ms+	where+		reduceMatches :: BitRepr r => Wire c v -> [PatMatch (Wire c v) (Wire c r)] -> NLM Nil (Wire c r)+		reduceMatches w [] = error "Empty list of pattern matches!"+		reduceMatches w [PatMatch pm] = do+			(_,r) <- pm w+			return r+		reduceMatches w pms = do+			pms' <- reduceMatchesByTwo pms+			reduceMatches w pms'+		reduceMatchesByTwo :: BitRepr r => [PatMatch (Wire c v) (Wire c r)] -> NLM Nil [PatMatch (Wire c v) (Wire c r)]+		reduceMatchesByTwo [] = return []+		reduceMatchesByTwo [pm] = return [pm]+		reduceMatchesByTwo (PatMatch pm1:PatMatch pm2:pms) = do+			let pm = PatMatch $ \v -> do+				(f1,r1) <- pm1 v+				(f2,r2) <- pm2 v+				fw <- assignWire $ f1 || f2+				sw <- assignWire $ selectWires f1 r1 r2+				return (fw, sw)+			pms' <- reduceMatchesByTwo pms+			return $ pm : pms'++infixl 8 -->+(-->) :: WiresList wires => Pattern (Wire c t) wires -> (wires -> NLM Nil (Wire c result))+	-> PatMatch (Wire c t) (Wire c result)+(Pattern p) --> f = PatMatch $ \w -> do+	(ws,flag) <- p w+	r <- f ws+	return (flag, r)++-- |Constant match.+pcst :: (Eq a, EqResult a ~ Bool, Eq (Wire c a), Show a, BitRepr a) => a -> Pattern (Wire c a) Nil+pcst c = Pattern $ \w -> return (Nil, w == constant c)++pvar :: BitRepr a => Pattern (Wire c a) (Wire c a :. Nil)+pvar = Pattern $ \w -> return (w :. Nil, constant True)++pwild :: BitRepr a => Pattern (Wire c a) Nil+pwild = Pattern $ \w -> return (Nil, constant True)++-- Pattern matching for some Prelude types.+$(reifyGenerateMakeMatch [''Maybe, ''Either, ''Bool])
+ src/Hardware/HHDL/TH.hs view
@@ -0,0 +1,457 @@+{-# LANGUAGE TemplateHaskell, PatternGuards #-}++module Hardware.HHDL.TH(reifyGenerateMakeMatch, generateMakeMatches) where++import Control.Monad+import Data.List+import Language.Haskell.TH++import Hardware.HHDL.TyLeA++-------------------------------------------------------------------------------+-- Build BitRepr instance, make and pattern combinators for algebraic types.+--+-- For every constructor Cons in declarations we will build mkCons with Cons'+-- arguments wrapped into WireOps amd pCons pattern match which matches+-- constructor against Wire.++generateMakeMatches :: Q [Dec] -> Q [Dec]+generateMakeMatches decs = do+	ds <- decs+	liftM concat $ forM ds generateMakeMatch++reifyGenerateMakeMatch :: [Name] -> Q[Dec]+reifyGenerateMakeMatch names = liftM concat $ mapM checkReifyGenerate names+	where+		checkReifyGenerate n = do+			i <- reify n+			case i of+				TyConI dec -> generateMakeMatchGen dec+				_ -> error $ show n ++ " does not reify to type declaration."++logGen s = runIO $ appendFile "gen" $ s++"\n"++generateMakeMatch dec = liftM (dec:) $ generateMakeMatchGen dec++generateMakeMatchGen :: Dec -> Q [Dec]+generateMakeMatchGen d@(DataD cxt name args conses _)+	| not $ null cxt = declError "Context is not empty."+	| Nothing <- bindersAreVars = declError "Only variable args are supported."+	| Just argVars <- bindersAreVars = do+		let justTyName = mkName $ nameBase name+		ds <- forM (zip [0..] conses) (uncurry $ generateConMakeMatch justTyName argVars)+		argsBusSize <- generateArgsBusSize justTyName argVars conses+		selBusSize <- generateSelBusSize justTyName argVars conses+		bitReprIns <- generateBitRepr justTyName argVars conses+		let result = argsBusSize : selBusSize : bitReprIns ++ concat ds+		logGen $ unlines (map (show . ppr) result)+		return result+	where+		declError e = error $ unlines [+			  e+			, "", ""+			, "Declaration:"+			, show (ppr d)+			]+		bindersAreVars = mapM binderIsVar args+		binderIsVar (PlainTV  v) = return v+		binderIsVar _ = Nothing+generateMakeMatchGen d = return []++generateConMakeMatch :: Name -> [Name] -> Integer -> Con -> Q [Dec]+generateConMakeMatch dataName args selectorIndex c@(NormalC conName types) = do+	return [makeType, makeFunc, matchTypeD, matchFunc]+--	return [matchTypeD, matchFunc]+	where+		matchName = mkName $ "p"++nameBase conName+		matchFunc = FunD matchName+			[Clause argPatterns (NormalB $ ConE (mkName "Pattern") `AppE` (LamE [wP] (DoE matchStats))) []]+		wN = mkName "w"+		wP = VarP wN+		wV = VarE wN+		returnStat e = NoBindS $ VarE (mkName "return") `AppE` e+		cN = mkName "c"+		cP = VarP cN+		cV = VarE cN+		asN = mkName "as"+		asP = VarP asN+		asV = VarE asN+		conpN = mkName "conp"+		conpV = VarE conpN+		conpP = VarP conpN+		resultingCondN = mkName "resultingCond"+		resultingCondV = VarE resultingCondN+		resultingCondP = VarP resultingCondN+		argumentsWiresN = mkName "argumentsWires"+		argumentsWiresV = VarE argumentsWiresN+		argumentsWiresP = VarP argumentsWiresN+		constructorSplit = VarE (mkName "_splitAlgType") `AppE` wV+		argMatch (argPat, argWire, matchResult, matchCond) = BindS+			(TupP [VarP matchResult, VarP matchCond]) f+			where+				unpatterned = VarE (mkName "unPattern") `AppE` VarE argPat+				f = unpatterned `AppE` VarE argWire+		splitWiresN e+			| length types > 1 = VarE (mkName $ "splitWires"++show (length types))+				`AppE` e+			| length types == 1 = e+		splitAssign = case types of+			[] -> []+			[_] -> [LetS+                                [ValD (VarP $ head aws) (NormalB $ castWires $ extendZero asV) []]]+			xs -> [LetS+                                [ ValD argumentsWiresP (NormalB $ castWires $ extendZero asV) []+				, ValD (TupP $ map VarP aws) (NormalB $ splitWiresN argumentsWiresV) []]]+		consT a b = ConT (mkName ":.") `AppT` a `AppT` b+		consE a b = ConE (mkName ":.") `AppE` a `AppE` b+		nil = ConE nilN+		assignWire p e = BindS p $ VarE (mkName "assignWire") `AppE` e+		matchStats = concat [+			  [LetS [ValD (TupP [cP,asP]) (NormalB constructorSplit) []]]+			, splitAssign+			--, [BindS conpP (VarE (mkName "assignWire") `AppE` (VarE (mkName "_fixAsBoolWire") `AppE` (InfixE (Just cV) (VarE $ mkName "==") (Just $ VarE (mkName "asTypeOf") `AppE` (LitE $ IntegerL $ fromIntegral selectorIndex) `AppE` cV ))))]+			, [assignWire conpP (InfixE (Just cV) (VarE $ mkName "==") (Just $ VarE (mkName "asTypeOf") `AppE` (LitE $ IntegerL $ fromIntegral selectorIndex) `AppE` cV ))]+			, map argMatch $ zip4 argNames aws mrs mcs+			, [assignWire resultingCondP $ foldr and conpV $ map VarE mcs]+			, [returnStat $ TupE [concatWLs mrs, resultingCondV]]+			]+			where+				and a b = InfixE (Just a) (VarE $ mkName "&&") (Just b)+				concatWL a = VarE (mkName "concatWiresList") `AppE` a+				concatWLs vs = concatWL $ foldr consE nil $ map VarE mrs+		matchTypeD = SigD matchName matchType+		concatTyLists a b = ConT (mkName "ConcatPatList") `AppT` a `AppT` b+		patternT ty o = ConT (mkName "Pattern") `AppT` wireT ty `AppT` o+		wireT ty = ConT (mkName "Wire") `AppT` clkT `AppT` ty+		nilN = mkName "Nil"+		nilT = ConT nilN+		mkMatchType _ t _ [] [] = let +			in (patternT resultT nilT, nilT, [], [])+		mkMatchType n t os wss [] = let+				concatenated = add concatTyLists $ reverse $ map VarT wss+				listOfTyLists = foldr consT nilT $ reverse $ map VarT wss+			in (t $ patternT resultT $ ConT (mkName "ConcatWiresList") `AppT` listOfTyLists, concatenated, os, wss)+		mkMatchType n t os wss (ty:tys) =+			mkMatchType (n+1) t' (out:os) (out:wss) tys+			where+				t' = t . (patternT ty (VarT out) `arr`)+				arr a b = ArrowT `AppT` a `AppT` b+				out = mkName $ "o_"++show n+		baseDataTy = foldl AppT (ConT dataName) $ map VarT args+		matchType = ForallT (map PlainTV vars) (nub context) ty+			where+				bitReprInst ty = ClassP (mkName "BitRepr") [ty]+				bitVectorNatInst ty = ClassP (mkName "Nat") [bitVectorSize ty]+				wiresList c = ClassP (mkName "WiresList") [c]+				context = --wiresList cs+					{-:-} bitReprInst baseDataTy+					: bitVectorNatInst baseDataTy+					: ClassP (mkName "AlgTypeBitEnc") [baseDataTy]+					: map (wiresList . VarT) os+					++ map (bitReprInst . VarT) args+					++ map (bitVectorNatInst . VarT) args+					++ argumentsNat+					++ [resultsWiresList]+				(ty,cs,os,vs) = mkMatchType 0 id [] [] (map snd types)+				vars = nub $ tyVars ty+				tyVars (AppT a b) = tyVars a ++ tyVars b+				tyVars (VarT v) = [v]+				tyVars _ = []+		clk = mkName "c"+		clkT = VarT clk+		nameMake = mkName $ "mk"++nameBase conName+		wire = AppT (ConT $ mkName "Wire") clkT+		resultT = foldl AppT (ConT dataName) (map VarT args)+		mkTy [] = AppT wire resultT+		mkTy (t:ts) = AppT (AppT ArrowT (AppT wire (snd t))) (mkTy ts)+		typesVars = nub $ concatMap (typeVars . snd) types ++ args+		typeVars (AppT a b) = typeVars a ++ typeVars b+		typeVars (VarT v) = [v]+		typeVars _ = []+		mkCxt _   [] = []+		mkCxt brs (ty:ts) =+			bitRepr ++ mkCxt (ty:brs) ts+			where+				bitRepr+					| ty `elem` brs = []+					| not (anyVars ty) = []+					| otherwise =+						[ClassP (mkName "BitRepr") [ty]]+		anyVars (AppT a b) = anyVars a || anyVars b+		anyVars (VarT _) = True+		anyVars _ = False+		context = nub $ mkCxt [] (map VarT args ++ map snd types)++algTypeCxt+			++ sumNat (map snd types) ++ [wholeTypeNat]+			++ argumentsNat+		argumentsNat = map sumNat $ init $ tails types+			where+				sumNat ts = ClassP (mkName "Nat") [foldl1 plusT $ map (bitVectorSize . snd) ts]+		resultsWiresList = ClassP (mkName "WiresListConcat")+			[foldr consT nilT $ map (VarT . mkName) $ map (("o_"++) . show) $ zipWith const [0..] types]+		bitVectorSize ty = ConT (mkName "BitVectorSize") `AppT` ty+		natPred ty = ClassP (mkName "Nat") [ty]+		plusT a b = ConT (mkName "Plus") `AppT` a `AppT` b+		sumNat [] = []+		sumNat [ty]+			| anyVars ty = [natPred ty]+			| otherwise = []+		sumNat (ty:tys) = sumNat tys ++ thisNat ++ [sumNats]+			where+				thisNat+					| anyVars ty = [natPred $ bitVectorSize ty]+					| otherwise = []+				(t:ts) = map bitVectorSize $ (ty:tys)+				sumNats = natPred (add plusT $ t:ts)+		add f [a] = a+		add f (a:as) = f a (add f as)+		selectorBusSize ty = ConT selectorBusSizeName `AppT` ty+		argsBusSize ty = ConT (mkName "ArgsBusSize") `AppT` ty+		wholeTypeNat = natPred (foldl1 plusT $ selectorBusSize resultT : argsBusSize resultT : [])+		algTypeCxt+			| not $ null args = [ClassP (mkName "AlgTypeBitEnc") [resultT]]+			| otherwise = []+		makeType = SigD nameMake $ ForallT (map PlainTV $ clk : typesVars) context $ mkTy types+		namesWithPrefix pfx = zipWith (\i _ -> mkName $ pfx++"_"++show i) [0..] types+		argNames = namesWithPrefix "a"+		aws = namesWithPrefix "argumentWire"+		mrs = namesWithPrefix "matchResult"+		mcs = namesWithPrefix "matchCond"+		argPatterns = map VarP argNames+		argsVector = case map VarE argNames of+			[] -> VarE (mkName "constant") `AppE` LitE (IntegerL 0)+			(as) -> extendZero $ castWires $ add join as+		resultN = mkName "result"+		resultV = VarE resultN+		resultD = ValD (VarP resultN)+			(NormalB (castWires (selectorV `join` argsVectorV)))+			[]+		selectorN = mkName "selector"+		selectorV = VarE selectorN+		selectorD = ValD (VarP selectorN) (NormalB sel) []+			where+				sel = VarE (mkName "constant") `AppE` e+				e = InfixE+					(Just $ LitE (IntegerL selectorIndex))+					(VarE $ mkName "asTypeOf")+					(Just $ VarE (mkName "_toSelBusSizeBitVectorWireExpr") `AppE` resultV)+		castWires x = VarE (mkName "castWires") `AppE` x+		join a b = InfixE (Just a) (VarE $ mkName "&") (Just b)+		argsVectorN = mkName "argsVector"+		argsVectorV = VarE argsVectorN+		extendZero e = (VarE $ mkName "extendZero") `AppE` e+		argsVectorD = ValD (VarP argsVectorN) (NormalB r) []+			where+				e = argsVector+				r = InfixE (Just e) (VarE (mkName "asTypeOf"))+					(Just $ VarE (mkName "_toArgsBusSizeBitVector") `AppE` resultV)+		makeFunc = FunD nameMake+			[Clause argPatterns (NormalB resultV)+				[resultD, selectorD, argsVectorD+				]]++generateConMakeMatch dataName args selectorIndex c =+	error $ unlines ["Only normal constructors are supported!", "We're given "++show (ppr c)++"."]++bitVectorSize :: Type -> Type+bitVectorSize a = AppT (ConT $ mkName "BitVectorSize") a+tyBinary f a b = AppT (AppT (ConT $ mkName f) a) b+sizeMax a b = tyBinary "Max" a b+sizeAdd a b = tyBinary "Plus" a b++argumentsBusSize = mkName "ArgsBusSize"++data V a = T a | P (V a) (V a) | M (V a) (V a)+	deriving (Eq, Show)++opt :: Eq a => V a -> V a+opt v = snd r+	where+		r = minimumBy (\a b -> compare (fst a) (fst b)) fixedWeighted+		fixed = incrComb [v]+		fixedWeighted = map (\v -> (nops v, v)) fixed+		incrComb vs+			| length vs == length next = vs+			| otherwise = incrComb next+			where+				next = nub $ concatMap comb vs++{-+t = foldl1 M $ map (foldl1 P) $ map (map T) ts+ts = nub [+	 [1,2]		--	JALR 1.regv 2.RI+	,[3,1,1,2]	--	Ternary	3.TernaryOp 1.regv 1.regv 2.RI+	,[4,1,1]	--	Mult 4.Signed 1.regv 1.regv+	,[4,1,1]	--	Div 4.Signed 1.regv 1.regv+	,[5,1,2,6]	--	Shift 5.ShiftOp 1.regv 2.RI 6.Imm5+	--,[]		--	SysCall+	,[7,1,1]	--	Trap 7.Cond 1.regv 1.regv+	,[2]		--	MFHi 2.RI+	,[2]		--	MFLo 2.RI+	,[1]		--	JR 1.regv+	,[4,1,1,2]	--	SLT 4.Signed 1.regv 1.regv 2.RI+	,[8,1,2,9]	--	Imm16Op 8.ImmOp 1.regv 2.RI 9.Imm16+	,[10,11]	--	J 10.Link 11.Imm26+	,[12,4,1,2,9]	--	Load 12.Gran 4.Signed 1.regv 2.RI 9.Imm16+	,[2,9]		--	LUI 2.RI 9.Imm16+	,[12,1,1,9]	--	Store 12.Gran 1.regv 1.regv 9.Imm16+	,[7,10,1,1,9]	--	Branch 7.Cond 10.Link 1.regv 1.regv 9.Imm16+	]+-}+++nops (T _) = 1+nops (P a b) = nops a + nops b + 1+nops (M a b) = nops a + nops b + 1++comb (P a b) = concat [[P x y, P y x] | x <- comb a, y <- comb b]+comb (M a b)+	| a == b = comb a+comb (M (P a b) (P c d))+	| a == c = comb $ P a (M b d)+comb (M (P a b) c)+	| c == a = comb $ P a b+	| c == b = comb $ P a b+comb (M a b) = concat [[M x y, M y x] | x <- comb a, y <- comb b]+comb v = [v]++opt2 :: Eq a => [[a]] -> V a+opt2 [[a]] = T a+opt2 [as] = foldl1 P $ map T as+opt2 tss = result+	where+		inc t [] = [(1,t)]+		inc t ((c,a):cas)+			| t == a = (c+1,a) : cas+			| otherwise = (c,a) : inc t cas+		mostOccured = snd $ maximumBy (\a b -> compare (fst a) (fst b))$+			foldr inc [] $ concat tss+		(withMostOccured', withoutMostOccured) =+			partition (mostOccured `elem`) tss+		delMostOccured [] = []+		delMostOccured (x:xs)+			| x == mostOccured = xs+			| otherwise = x : delMostOccured xs+		withMostOccured = filter (not . null) $+			map delMostOccured withMostOccured'+		left = case withMostOccured of+			[] -> T mostOccured+			_ -> P (T mostOccured) $ opt2 withMostOccured+		right = opt2 withoutMostOccured+		result = case withoutMostOccured of+			[] -> left+			_ -> M left right+		+++generateArgsBusSize :: Name -> [Name] -> [Con] -> Q Dec+generateArgsBusSize dataName argVars conses = do+	case interestingConses of+		[] -> return ()+		_ -> do+			logGen $ "Starting expression: "++show v+			logGen $ "Optimized expression: "++show ov+	return result+	where+		result = TySynInstD argumentsBusSize+			[foldl AppT (ConT dataName) (map VarT argVars)] $+			newVariant+		newVariant = case interestingConses of+			[] -> tySizePure 0+			_ -> fromV ov+		oldVariant =+			case conArgsSizes of+				[] -> tySizePure 0+				cs -> foldl1 (\a b -> sizeMax a b) cs+		fromV (T t) = bitVectorSize t+		fromV (P a b) = sizeAdd (fromV a) (fromV b)+		fromV (M a b) = sizeMax (fromV a) (fromV b)+		consesArgs :: [[Type]]+		consesArgs = map conArgs conses+		conArgs (NormalC _ as) = map snd as+		conArgs c = error $ "Unsupported constructor "++show (ppr c)+		conArgsSizes = map conArgsSize interestingConses+		interestingConses = nub $ filter (not . null) consesArgs+		v = foldl1 M $ map (foldl1 P) $ map (map T) interestingConses+		ov =+			--opt v+			opt2 interestingConses+		conArgsSize [] = tySizePure 0+		conArgsSize as = foldl1 sizeAdd (map bitVectorSize as)++selectorBusSizeName = mkName "SelectorBusSize"++generateSelBusSize :: Name -> [Name] -> [Con] -> Q Dec+generateSelBusSize dataName argVars conses = do+	return result+	where+		result = TySynInstD selectorBusSizeName+			[foldl AppT (ConT dataName) (map VarT argVars)] $+			tySizePure (log2 $ length conses)++log2 0 = 0+log2 1 = 0+log2 n = 1 + log2 (div (n+1) 2)++generateBitRepr :: Name -> [Name] -> [Con] -> Q [Dec]+generateBitRepr dataName argVars conses = return [bitReprInstance, algTypeEncInstance]+	where+		bitReprName = mkName "BitRepr"+		algTypeEncName = mkName "AlgTypeBitEnc"+		bitReprInstance = InstanceD context (AppT (ConT bitReprName) dataType) decls+		algTypeEncInstance = InstanceD+			[ClassP (mkName "Nat") [AppT (ConT $ mkName "ArgsBusSize") dataType]]+			(AppT (ConT algTypeEncName) dataType)+			[]+		dataType = foldl AppT (ConT dataName) (map VarT argVars)+		decls = [bitVectorSizeInst, toBitVector, fromBitVector]+		context = natHeads++varBitRepr++[algType]+		natHeads = map (\t -> ClassP (mkName "Nat") [t])+			[bitVectorSize dataType] --, AppT (ConT $ mkName "ArgsBusSize") dataType]+		varBitRepr = map (\v -> ClassP bitReprName [VarT v]) argVars+		algType = ClassP algTypeEncName [dataType]++		nx = mkName "x"+		vx = VarE nx+                toBitVector = FunD (mkName "toBitVector") [Clause [VarP nx] (NormalB toBitVectorCase) []]+		toBitVectorCase = CaseE vx $ zipWith toBitVectorConsMatch [0..] conses+		nxi = zipWith (\i _ -> mkName $ "x_"++show i) [0..]+		nsi = zipWith (\i _ -> mkName $ "s_"++show i) [0..]+		pxi = map VarP . nxi+		vxi = map VarE . nxi+		toBitVectorConsMatch i (NormalC cn as) = Match pattern (NormalB e) []+			where+				pattern = AsP (mkName "y") (ConP (mkName $ nameBase cn) (pxi as))+				ci = LitE $ IntegerL (fromIntegral i)+				vs = vxi as+				argsVector = foldl combine (LitE $ IntegerL 0) vs+				combine acc x = r+					where+						sacc = VarE (mkName "Data.Bits.shiftL") `AppE` acc `AppE` (AppE (VarE $ mkName $ "bitVectorSize") x)+						r = InfixE (Just sacc) (VarE $ mkName "Data.Bits..|.") (Just $ VarE (mkName "toBitVector") `AppE` x)+				e = (VarE $ mkName "_combineConstructorIndexArgs") `AppE` argsVector `AppE` (VarE (mkName "algTypeArgsBusSize") `AppE` VarE (mkName "y")) `AppE` ci+                fromBitVector = FunD (mkName "fromBitVector") [Clause [VarP nx] (NormalB (VarE $ mkName "r"))+			[ValD (VarP nr) (NormalB fromBitVectorE) []]]+		nr = mkName "r"+		vr = VarE $ nr+		fromBitVectorConsMatch i (NormalC n as) =+				Match (LitP $ IntegerL (fromInteger i)) (NormalB r) decls+			where+				xs = nxi as+				ss = nsi as+				decls = snd $ foldl accShift (LitE $ IntegerL 0, []) (zip ss xs)+				accShift (p,acc) (s,x) = (VarE s,sdecl:xdecl:acc)+					where+						xdecl = ValD (VarP x)+							(NormalB $ VarE (mkName "fromBitVector") `AppE` (VarE (mkName "Data.Bits.shiftR") `AppE` vx `AppE` p))+							[]+						sdecl = ValD (VarP s)+							(NormalB $ InfixE (Just p) (VarE $ mkName "+") (Just $ VarE (mkName "bitVectorSize") `AppE` VarE x))+							[]+				r = foldr (flip AppE) (ConE $ mkName $ nameBase n) (map VarE xs)+		fromBitVectorE = CaseE sel $ zipWith fromBitVectorConsMatch [0..] conses+			where+				sel = InfixE (Just shifted) (VarE $ mkName "Data.Bits..&.") (Just $ VarE (mkName "algTypeSelectorBusMask") `AppE` vr)+				shifted = (VarE $ mkName "Data.Bits.shiftR") `AppE` vx `AppE` (VarE (mkName "algTypeArgsBusSize") `AppE` vr)+		bitVectorSizeInst = TySynInstD (mkName "BitVectorSize") [dataType]+			(sizeAdd (AppT (ConT selectorBusSizeName) dataType)+				(AppT (ConT argumentsBusSize) dataType))
+ src/Hardware/HHDL/ToWires.hs view
@@ -0,0 +1,113 @@+-- |ToWires.hs+--+-- A class that converts between Haskell types and bit vectors (Integer)+-- with instance for some handy types.+--+-- Copyright (C) Serguey Zefirov, 2009++{-# LANGUAGE TypeOperators, TemplateHaskell, TypeFamilies, FlexibleContexts, UndecidableInstances #-}++module Hardware.HHDL.ToWires where++import Data.Bits+import Data.Word++import Hardware.HHDL.TyLeA++class Nat (BusSize a) => ToWires a where+	type BusSize a+	wireSizeType :: a -> BusSize a+	wireSizeType _ = undefined+	wireSize :: a -> Int+	wireSize x = fromNat $ wireSizeType x+	wireMul :: a -> Integer+	wireMul x = Data.Bits.shiftL 1 (wireSize x)+	wireSelSize :: a -> Int+	wireSelSize = const 0+	-- Integer should occupy no more than wireSize bits, higher ones should be 0+	toWires :: a -> Integer+	-- fromWires should work with integers that have non-zero bits+	-- above wireSize index.+	fromWires :: Integer -> a+	-- enumeration size.+	-- valuesCount of (Maybe a) returns 1+valuesCount (x::a)+	-- valuesCount of Either a b returns valuesCount (x::a) + valuesCount (yLLb)+	-- valuesCount of (a,b) returns valuesCoutn (x::a) * valuesCount (y::b)+--	valuesCount :: a -> Integer+--	-- valueIndex.+--	-- get a value and return an index inside enumeration.+--	valueIndex :: a -> Integer+	-- enumerate values.+--	enumerate :: [a]++castWires :: (ToWires a, ToWires b, BusSize a ~ BusSize b) => a -> b+castWires from = to+	where+		to = fromWires $ toWires from++infixr 5 :&:	-- just like (:)+data l :&: r = l :&: r+instance (Nat (Plus (BusSize l) (BusSize r)), ToWires l, ToWires r) => ToWires (l :&: r) where+	type BusSize (l :&: r) = Plus (BusSize l) (BusSize r)+	toWires (a :&: b) = Data.Bits.shiftL (toWires a) (wireSize b) .|. toWires b+	fromWires x = a :&: b+		where+			b = fromWires x+			a = fromWires $ Data.Bits.shiftR x (wireSize b)+--	enumerate = [a :&: b | a <- enumerate, b <- enumerate]+--	valuesCount (a :&: b) = valuesCount a * valuesCount b++infixr 4 :|:	-- allows us to write a :&: b :|: c :&: d which equal to (a :&: b) :|: (c :&: d)+data l :|: r = l :|: r+instance (Nat (Max (BusSize l) (BusSize r)), ToWires l, ToWires r) => ToWires (l :|: r) where+	type BusSize (l :|: r) = Max (BusSize l) (BusSize r)+	toWires (a :|: b) = toWires a .|. toWires b+	fromWires x = a :|: b+		where+			b = fromWires x+			a = fromWires x+--	enumerate = error "no enumeration for :|:"+		-- [a :|: b | a <- enumerate, b <- enumerate]+--	valuesCount (a :|: b) = max (valuesCount a) (valuesCount b)++instance ToWires Int where+	type BusSize Int = $(tySize 32)+	toWires n = fromIntegral n .&. 0xffffffff+	fromWires x = fromIntegral x .&. 0xffffffff+--	valuesCount = const (Data.Bits.shiftL (1::Integer) 32)+--	valueIndex = fromIntegral+--	enumerate = [fromIntegral n | n <- [0..0xffffffff]]++instance ToWires Word32 where+	type BusSize Word32 = $(tySize 32)+	toWires n = fromIntegral n .&. 0xffffffff+	fromWires x = fromIntegral x .&. 0xffffffff+--	valuesCount = const (Data.Bits.shiftL (1::Integer) 32)+--	valueIndex = fromIntegral+--	enumerate = [fromIntegral n | n <- [0..0xffffffff]]++instance ToWires Word16 where+	type BusSize Word16 = $(tySize 16)+	toWires n = fromIntegral n .&. 0xffff+	fromWires x = fromIntegral x .&. 0xffff+--	valuesCount = const (Data.Bits.shiftL (1::Integer) 32)+--	valueIndex = fromIntegral+--	enumerate = [fromIntegral n | n <- [0..0xffffffff]]++instance ToWires Word8 where+	type BusSize Word8 = $(tySize 8)+	toWires n = fromIntegral n .&. 0xff+	fromWires x = fromIntegral x .&. 0xff+--	valuesCount = const (Data.Bits.shiftL (1::Integer) 32)+--	valueIndex = fromIntegral+--	enumerate = [fromIntegral n | n <- [0..0xffffffff]]++instance ToWires () where+	type BusSize () = $(tySize 0)+	toWires _ = 0+	fromWires _ = ()+--	valuesCount = const 1+--	valueIndex = fromIntegral+--	enumerate = [()]++
+ src/Hardware/HHDL/TyLeA.hs view
@@ -0,0 +1,245 @@+-- |TyLeA.hs
+--
+-- Type level decimal arithmetic.
+--
+-- Decimal numbers represented either by standalone digits (Dx)
+-- or by lists of standalone digits (D1 :. D2 :. D8), (D2 :. D4).
+--
+-- Author: Serguey Zefirov, 2011
+--
+-- I place it into public domain.
+
+{-# LANGUAGE TypeFamilies, TemplateHaskell, TypeOperators, UndecidableInstances #-}
+
+module Hardware.HHDL.TyLeA(
+	-- how to convert from types to runtime values.
+	  Nat(fromNat)
+	-- numbers construction.
+	-- numbers are either single digits or digits, separated by ":." operator.
+	, D0, D1, D2, D3, D4
+	, D5, D6, D7, D8, D9
+	, (:*)(..)
+	-- functions.
+	, Max, Plus
+	, Mul, Div2, Log2
+	-- shortcuts.
+	, tySizePure
+	, tySize	-- use it as SomeSizedType $(tySize 1024) (equal to D1 :* D0 :* D2 :* D4)
+) where
+
+import Control.Monad
+import Language.Haskell.TH
+
+data D0 = D0
+data D1 = D1
+data D2 = D2
+data D3 = D3
+data D4 = D4
+data D5 = D5
+data D6 = D6
+data D7 = D7
+data D8 = D8
+data D9 = D9
+
+infixl 5 :*
+data ds :* d = ds :* d deriving Show
+
+-------------------------------------------------------------------------------
+-- Maximum.
+
+data Equal = Equal deriving Show
+data Less = Less deriving Show
+data Greater = Greater deriving Show
+
+class Mat a where mat :: a
+instance Mat Equal where mat = Equal
+instance Mat Less where mat = Less
+instance Mat Greater where mat = Greater
+
+type family Max a b
+type instance Max a b = SelectMax (Compare a b Equal) a b
+
+type family SelectMax what a b
+type instance SelectMax Equal a b = a
+type instance SelectMax Less a b = b
+type instance SelectMax Greater a b = a
+
+type family Compare a b prevCond
+$(liftM concat $ forM [(a,b) | a <- [0..9], b <- [0..9]] $ \(a,b) -> do
+	let compareName = mkName "Compare"
+	let digit n = ConT $ mkName $ "D"++show n
+	let prevCond = VarT $ mkName "prevCond"
+	let less = ConT $ mkName "Less"
+	let greater = ConT $ mkName "Greater"
+	let da = digit a
+	let db = digit b
+	let compareDigits = TySynInstD compareName [da, db,prevCond] $ case compare a b of
+		EQ -> prevCond
+		LT -> less
+		GT -> greater
+	let va = VarT $ mkName "a"
+	let vb = VarT $ mkName "b"
+	let vc = VarT $ mkName "c"
+	let number h l = AppT (AppT (ConT $ mkName ":*") h) l
+	let compareNumberRight = TySynInstD compareName [da, number vb db, prevCond] less
+	let compareNumberLeft  = TySynInstD compareName [number va da, db, prevCond] greater
+	let compareNumbers = TySynInstD compareName [number va da, number vb db, prevCond] $ case compare a b of
+		EQ -> ConT compareName `AppT` va `AppT` vb `AppT` prevCond
+		LT -> ConT compareName `AppT` va `AppT` vb `AppT` less
+		GT -> ConT compareName `AppT` va `AppT` vb `AppT` greater
+	let r = [compareDigits, compareNumberLeft, compareNumberRight, compareNumbers]
+--	runIO $ mapM (putStrLn . show . ppr) r
+	return r
+ )
+
+-------------------------------------------------------------------------------
+-- Addition.
+
+type family Sum3 a b c
+$(liftM concat $ forM [(a,b,c) | a <- [0..9], b <- [0..9], c <- [0..1]] $ \(a,b,c) -> do
+	let sum3Name = mkName "Sum3"
+	let sum = a+b+c
+	let s = sum `mod` 10
+	let propC = sum `div` 10
+	let digit n = ConT $ mkName $ "D"++show n
+	let number h l = AppT (AppT (ConT $ mkName ":*") h) l
+	let ds = digit s
+	let digitSumResult
+		| propC == 0 = ds
+		| otherwise = number (digit propC) (ds)
+	let da = digit a
+	let db = digit b
+	let dc = digit c
+	let dPropC = digit propC
+	let va = VarT $ mkName "a"
+	let vb = VarT $ mkName "b"
+	let vc = VarT $ mkName "c"
+	let digitSum = TySynInstD sum3Name [da, db, dc] digitSumResult
+	let numberSumResult = number (ConT sum3Name `AppT` va `AppT` vb `AppT` dPropC) ds
+	let numberSum = TySynInstD sum3Name [number va da, number vb db, dc] numberSumResult
+	let add3 a b c = ConT sum3Name `AppT` a `AppT` b `AppT` c
+	let partLeftSumResult
+		| propC == 0 = number va ds
+		| otherwise = number (add3 va (digit 0) (digit 1)) ds
+	let partLeft = TySynInstD sum3Name [number va da, db, dc] partLeftSumResult
+	let partRightSumResult
+		| propC == 0 = number vb ds
+		| otherwise = number (add3 (digit 0) vb (digit 1)) ds
+	let partRight = TySynInstD sum3Name [da, number vb db, dc] partRightSumResult
+	let r = [digitSum, numberSum, partLeft, partRight]
+--	runIO $ mapM (putStrLn . show . ppr) r
+	return r
+ )
+
+type family Plus a b
+type instance Plus a b = Sum3 a b D0
+
+-------------------------------------------------------------------------------
+-- Multiplication.
+
+type family Mul a b
+type instance Mul a b = MulAcc D0 a b
+
+type family Dup a
+type instance Dup a = Plus a a
+
+type family MulAcc acc a b
+type instance MulAcc acc a D0 = acc
+type instance MulAcc acc a D1 = Plus acc a
+type instance MulAcc acc a D2 = Plus acc (Dup a)
+type instance MulAcc acc a D3 = Plus acc (Plus a (Dup a))
+type instance MulAcc acc a D4 = Plus acc (Dup (Dup a))
+type instance MulAcc acc a D5 = Plus acc (Plus (Dup (Dup a)) a)
+type instance MulAcc acc a D6 = Plus acc (Dup (Plus (Dup a) a))
+type instance MulAcc acc a D7 = Plus acc (Plus (Dup (Plus (Dup a) a)) a)
+type instance MulAcc acc a D8 = Plus acc (Dup (Dup (Dup a)))
+type instance MulAcc acc a D9 = Plus acc (Plus (Dup (Dup (Dup a))) a)
+type instance MulAcc acc a (bs :* b) = MulAcc (Mul a bs :* D0) a b
+
+
+-------------------------------------------------------------------------------
+-- Division by 2.
+
+type family Div2 a
+type instance Div2 D0 = D0
+type instance Div2 D1 = D0
+type instance Div2 D2 = D1
+type instance Div2 D3 = D1
+type instance Div2 D4 = D2
+type instance Div2 D5 = D2
+type instance Div2 D6 = D3
+type instance Div2 D7 = D3
+type instance Div2 D8 = D4
+type instance Div2 D9 = D4
+type instance Div2 (D0 :* a) = Div2 a
+type instance Div2 (D1 :* a) = Plus (Div2 a) D5
+type instance Div2 (D2 :* a) = D1 :* Div2 a
+type instance Div2 (D3 :* a) = D1 :* Plus (Div2 a) D5
+type instance Div2 (D4 :* a) = D2 :* Div2 a
+type instance Div2 (D5 :* a) = D2 :* Plus (Div2 a) D5
+type instance Div2 (D6 :* a) = D3 :* Div2 a
+type instance Div2 (D7 :* a) = D3 :* Plus (Div2 a) D5
+type instance Div2 (D8 :* a) = D4 :* Div2 a
+type instance Div2 (D9 :* a) = D4 :* Plus (Div2 a) D5
+type instance Div2 (as :* D0 :* a) = Div2 (as :* D0) :* Div2 a
+type instance Div2 (as :* D1 :* a) = Div2 (as :* D0) :* Plus (Div2 a) D5
+type instance Div2 (as :* D2 :* a) = Div2 (as :* D2) :* Div2 a
+type instance Div2 (as :* D3 :* a) = Div2 (as :* D2) :* Plus (Div2 a) D5
+type instance Div2 (as :* D4 :* a) = Div2 (as :* D4) :* Div2 a
+type instance Div2 (as :* D5 :* a) = Div2 (as :* D4) :* Plus (Div2 a) D5
+type instance Div2 (as :* D6 :* a) = Div2 (as :* D6) :* Div2 a
+type instance Div2 (as :* D7 :* a) = Div2 (as :* D6) :* Plus (Div2 a) D5
+type instance Div2 (as :* D8 :* a) = Div2 (as :* D8) :* Div2 a
+type instance Div2 (as :* D9 :* a) = Div2 (as :* D8) :* Plus (Div2 a) D5
+
+-------------------------------------------------------------------------------
+-- Base 2 logarithm.
+
+type family Log2 a
+type instance Log2 D0 = D0
+type instance Log2 D1 = D0
+type instance Log2 D2 = D1
+type instance Log2 D3 = D2
+type instance Log2 D4 = D2
+type instance Log2 D5 = D3
+type instance Log2 D6 = D3
+type instance Log2 D7 = D3
+type instance Log2 D8 = D3
+type instance Log2 D9 = D4
+type instance Log2 (as :* a) = Inc (Log2 (Div2 (Inc (as :* a))))
+
+type family Inc a
+type instance Inc a = Plus a D1
+
+-------------------------------------------------------------------------------
+-- Conversion to runtime values.
+
+class Nat a where
+	fromNat :: a -> Int
+	natMult :: a -> Int
+	natMult = const 0
+
+instance Nat D0 where { fromNat = const 0; natMult = const 1}
+instance Nat D1 where { fromNat = const 1; natMult = const 1}
+instance Nat D2 where { fromNat = const 2; natMult = const 1}
+instance Nat D3 where { fromNat = const 3; natMult = const 1}
+instance Nat D4 where { fromNat = const 4; natMult = const 1}
+instance Nat D5 where { fromNat = const 5; natMult = const 1}
+instance Nat D6 where { fromNat = const 6; natMult = const 1}
+instance Nat D7 where { fromNat = const 7; natMult = const 1}
+instance Nat D8 where { fromNat = const 8; natMult = const 1}
+instance Nat D9 where { fromNat = const 9; natMult = const 1}
+
+instance (Nat ds, Nat d) => Nat (ds :* d) where
+	fromNat ~(ds :* d) = fromNat d + fromNat ds * 10
+	natMult = const 1
+
+tySizePure :: Int -> Type
+tySizePure n = f $ show n
+	where
+		f [c] = digit c
+		f (c:cs) = AppT (AppT (ConT $ mkName ":*") $ digit c) $ f cs
+		digit c = ConT $ mkName $ ['D',c]
+
+tySize :: Int -> Q Type
+tySize = return . tySizePure