netlist-0.2: Language/Netlist/Util.hs
--------------------------------------------------------------------------------
-- |
-- Module : Language.Netlist.Util
-- Copyright : (c) Signali Corp. 2010
-- License : All rights reserved
--
-- Maintainer : pweaver@signalicorp.com
-- Stability : experimental
-- Portability : non-portable
--
-- Utility functions for constructing Netlist AST elements.
--------------------------------------------------------------------------------
module Language.Netlist.Util where
import Language.Netlist.AST
-- -----------------------------------------------------------------------------
data Direction = Up | Down
unsizedInteger :: Integer -> Expr
unsizedInteger = unsizedIntegral
unsizedIntegral :: Integral a => a -> Expr
unsizedIntegral = ExprLit Nothing . ExprNum . toInteger
sizedInteger :: Int -> Integer -> Expr
sizedInteger = sizedIntegral
sizedIntegral :: Integral a => Int -> a -> Expr
sizedIntegral sz = ExprLit (Just sz) . ExprNum . toInteger
-- | Given a direction and size, maybe generate a 'Range', where a size of 1
-- yields 'Nothing'.
makeRange :: Direction -> Size -> Maybe Range
makeRange _ 1 = Nothing
makeRange d sz
| sz > 1
= let upper = unsizedIntegral (sz - 1)
lower = unsizedInteger 0
in Just $ case d of
Up -> Range lower upper
Down -> Range upper lower
| otherwise
= error ("makeRange: invalid size: " ++ show sz)
-- | Concatenate a list of expressions, unless there is just one expression.
exprConcat :: [Expr] -> Expr
exprConcat [e] = e
exprConcat es = ExprConcat es
-- | Make a 'Seq' statement from a list of statements, unless there is just one
-- statement.
statements :: [Stmt] -> Stmt
statements [x] = x
statements xs = Seq xs
-- -----------------------------------------------------------------------------
-- | generate a process declaration for a generic register based on the following:
--
-- * the register name (as an expression)
--
-- * clock expression
--
-- * width of the register
--
-- * optional asynchronous reset and initial value
--
-- * optional clock enable
--
-- * optional synchronous restart and initial value
--
-- * optional load enable
--
-- * when enabled, the expression to assign to the identifier
--
-- You can implement a shift register by passing in a concatenation for the
-- register expression and the input expression, though that is not compatible
-- with VHDL.
--
-- TODO
-- * support negative-edge triggered clock/reset, active-low reset/restart
-- * support true clock enable (as opposed to load enable)?
generateReg :: Expr -> Expr -> Maybe (Expr, Expr) -> Maybe (Expr, Expr) ->
Maybe Expr -> Expr -> Decl
generateReg x clk mb_reset mb_restart mb_enable expr
= ProcessDecl as
where
as = case mb_reset of
Just (reset, initial)
-> [ (Event reset PosEdge, Assign x initial), a0]
Nothing
-> [a0]
a0 = (Event clk PosEdge, stmt2)
stmt2 = case mb_restart of
Just (restart, initial)
-> If restart (Assign x initial) (Just stmt1)
Nothing
-> stmt1
stmt1 = case mb_enable of
Just enable -> If enable stmt0 Nothing
Nothing -> stmt0
stmt0 = Assign x expr
-- -----------------------------------------------------------------------------