-------------------------------------------------------------------------------- -- | -- 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 (Event clk PosEdge) mb_reset' stmt2 where mb_reset' = case mb_reset of Just (reset, initial) -> Just (Event reset PosEdge, Assign x initial) Nothing -> Nothing 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 -- -----------------------------------------------------------------------------