2020-07-07 05:40:07 +02:00
|
|
|
{-# LANGUAGE PatternSynonyms #-}
|
2019-03-19 18:40:25 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Conversion for unbased, unsized literals ('0, '1, 'z, 'x)
|
|
|
|
|
-
|
2020-07-07 05:40:07 +02:00
|
|
|
- The literals are given a binary base, a size of 1, and are made signed to
|
|
|
|
|
- allow sign extension. For context-determined expressions, the converted
|
|
|
|
|
- literals are explicitly cast to the appropriate context-determined size.
|
|
|
|
|
-
|
|
|
|
|
- As a special case, unbased, unsized literals which take on the size of a
|
|
|
|
|
- module port binding are replaced with a hierarchical reference to an
|
|
|
|
|
- appropriately sized constant which is injected into the instantiated module's
|
|
|
|
|
- definition. This allows these literals to be used for parameterized ports
|
|
|
|
|
- without further complicating other conversions, as hierarchical references
|
|
|
|
|
- are not allowed within constant expressions.
|
2019-03-19 18:40:25 +01:00
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.UnbasedUnsized (convert) where
|
|
|
|
|
|
2020-07-07 05:40:07 +02:00
|
|
|
import Control.Monad.Writer
|
|
|
|
|
|
2019-03-19 18:40:25 +01:00
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
2020-07-07 05:40:07 +02:00
|
|
|
data ExprContext
|
|
|
|
|
= SelfDetermined
|
|
|
|
|
| ContextDetermined Expr
|
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
|
|
|
|
|
type Port = Either Identifier Int
|
|
|
|
|
|
|
|
|
|
data Bind = Bind
|
|
|
|
|
{ bModule :: Identifier
|
|
|
|
|
, bBit :: Char
|
|
|
|
|
, bPort :: Port
|
|
|
|
|
} deriving (Eq, Show)
|
|
|
|
|
|
|
|
|
|
type Binds = [Bind]
|
|
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
2020-07-07 05:40:07 +02:00
|
|
|
convert files =
|
|
|
|
|
map (traverseDescriptions $ convertDescription binds) files'
|
|
|
|
|
where
|
|
|
|
|
(files', binds) = runWriter $
|
|
|
|
|
mapM (mapM $ traverseModuleItemsM convertModuleItemM) files
|
|
|
|
|
|
|
|
|
|
convertDescription :: Binds -> Description -> Description
|
|
|
|
|
convertDescription [] other = other
|
|
|
|
|
convertDescription binds (Part attrs extern kw lifetime name ports items) =
|
|
|
|
|
Part attrs extern kw lifetime name ports items'
|
|
|
|
|
where
|
|
|
|
|
binds' = filter ((== name) . bModule) binds
|
|
|
|
|
items' = removeDupes [] $ items ++ map (bindItem ports) binds'
|
|
|
|
|
removeDupes :: [Identifier] -> [ModuleItem] -> [ModuleItem]
|
|
|
|
|
removeDupes _ [] = []
|
|
|
|
|
removeDupes existing (item @ (MIPackageItem (Decl decl)) : is) =
|
|
|
|
|
case decl of
|
|
|
|
|
Param Localparam _ x _ ->
|
|
|
|
|
if elem x existing
|
|
|
|
|
then removeDupes existing is
|
|
|
|
|
else item : removeDupes (x : existing) is
|
|
|
|
|
_ -> item : removeDupes existing is
|
|
|
|
|
removeDupes existing (item : is) =
|
|
|
|
|
item : removeDupes existing is
|
|
|
|
|
convertDescription _ other = other
|
|
|
|
|
|
|
|
|
|
bindName :: Bind -> Identifier
|
|
|
|
|
bindName (Bind _ ch (Left x)) = "sv2v_uub_" ++ ch : '_' : x
|
|
|
|
|
bindName (Bind m ch (Right i)) =
|
|
|
|
|
bindName $ Bind m ch (Left $ show i)
|
|
|
|
|
|
|
|
|
|
bindItem :: [Identifier] -> Bind -> ModuleItem
|
|
|
|
|
bindItem ports bind =
|
|
|
|
|
MIPackageItem $ Decl $ Param Localparam typ name expr
|
|
|
|
|
where
|
|
|
|
|
portName = lookupPort ports (bPort bind)
|
|
|
|
|
size = DimsFn FnBits $ Right $ Ident portName
|
2020-07-12 23:06:27 +02:00
|
|
|
rng = (BinOp Sub size (RawNum 1), RawNum 0)
|
2020-07-07 05:40:07 +02:00
|
|
|
typ = Implicit Unspecified [rng]
|
|
|
|
|
name = bindName bind
|
|
|
|
|
expr = literalFor $ bBit bind
|
|
|
|
|
|
|
|
|
|
lookupPort :: [Identifier] -> Port -> Identifier
|
|
|
|
|
lookupPort _ (Left x) = x
|
|
|
|
|
lookupPort ports (Right i) =
|
|
|
|
|
if i < length ports
|
|
|
|
|
then ports !! i
|
|
|
|
|
else error $ "out of bounds bort binding " ++ show (ports, i)
|
|
|
|
|
|
|
|
|
|
convertModuleItemM :: ModuleItem -> Writer Binds ModuleItem
|
|
|
|
|
convertModuleItemM (Instance moduleName params instanceName [] bindings) = do
|
|
|
|
|
bindings' <- mapM (uncurry convertBinding) $ zip bindings [0..]
|
|
|
|
|
let item = Instance moduleName params instanceName [] bindings'
|
|
|
|
|
return $ convertModuleItem item
|
|
|
|
|
where
|
|
|
|
|
tag = Ident ":uub:"
|
|
|
|
|
convertBinding :: PortBinding -> Int -> Writer Binds PortBinding
|
|
|
|
|
convertBinding (portName, expr) idx = do
|
|
|
|
|
let port = if null portName then Right idx else Left portName
|
|
|
|
|
let expr' = convertExpr (ContextDetermined tag) expr
|
|
|
|
|
expr'' <- traverseNestedExprsM (replaceBindingExpr port) expr'
|
|
|
|
|
return (portName, expr'')
|
|
|
|
|
replaceBindingExpr :: Port -> Expr -> Writer Binds Expr
|
2020-07-12 23:06:27 +02:00
|
|
|
replaceBindingExpr port (orig @ (Cast Right{} (ConvertedUU a b))) = do
|
|
|
|
|
let ch = charForBit a b
|
2020-07-07 05:40:07 +02:00
|
|
|
if orig == sizedLiteralFor tag ch
|
|
|
|
|
then do
|
|
|
|
|
let bind = Bind moduleName ch port
|
|
|
|
|
tell [bind]
|
|
|
|
|
let expr = Dot (Ident instanceName) (bindName bind)
|
|
|
|
|
return expr
|
|
|
|
|
else return orig
|
|
|
|
|
replaceBindingExpr _ other = return other
|
|
|
|
|
convertModuleItemM other = return $ convertModuleItem other
|
2020-06-15 03:43:32 +02:00
|
|
|
|
|
|
|
|
convertModuleItem :: ModuleItem -> ModuleItem
|
|
|
|
|
convertModuleItem =
|
2020-07-07 05:40:07 +02:00
|
|
|
traverseExprs (convertExpr SelfDetermined) .
|
2020-07-14 02:55:47 +02:00
|
|
|
traverseTypes (traverseNestedTypes convertType)
|
2019-03-19 18:40:25 +01:00
|
|
|
|
2020-07-07 05:40:07 +02:00
|
|
|
literalFor :: Char -> Expr
|
2020-07-12 23:06:27 +02:00
|
|
|
literalFor 'Z' = literalFor 'z'
|
|
|
|
|
literalFor 'X' = literalFor 'x'
|
|
|
|
|
literalFor '0' = Number $ Based 1 True Binary 0 0
|
|
|
|
|
literalFor '1' = Number $ Based 1 True Binary 1 0
|
|
|
|
|
literalFor 'x' = Number $ Based 1 True Binary 0 1
|
|
|
|
|
literalFor 'z' = Number $ Based 1 True Binary 1 1
|
|
|
|
|
literalFor ch = error $ "unexpected unbased-unsized digit: " ++ [ch]
|
|
|
|
|
|
|
|
|
|
pattern ConvertedUU :: Integer -> Integer -> Expr
|
|
|
|
|
pattern ConvertedUU a b = Number (Based 1 True Binary a b)
|
|
|
|
|
|
|
|
|
|
charForBit :: Integer -> Integer -> Char
|
|
|
|
|
charForBit 0 0 = '0'
|
|
|
|
|
charForBit 1 0 = '1'
|
|
|
|
|
charForBit 0 1 = 'x'
|
|
|
|
|
charForBit 1 1 = 'z'
|
|
|
|
|
charForBit _ _ = error "charForBit invariant violated"
|
2020-06-06 03:40:59 +02:00
|
|
|
|
2020-07-07 05:40:07 +02:00
|
|
|
sizedLiteralFor :: Expr -> Char -> Expr
|
|
|
|
|
sizedLiteralFor expr ch =
|
|
|
|
|
Cast (Right size) (literalFor ch)
|
|
|
|
|
where size = DimsFn FnBits $ Right expr
|
|
|
|
|
|
|
|
|
|
convertExpr :: ExprContext -> Expr -> Expr
|
|
|
|
|
convertExpr _ (DimsFn fn (Right e)) =
|
|
|
|
|
DimsFn fn $ Right $ convertExpr SelfDetermined e
|
|
|
|
|
convertExpr _ (Cast te e) =
|
|
|
|
|
Cast te $ convertExpr SelfDetermined e
|
|
|
|
|
convertExpr _ (Concat exprs) =
|
|
|
|
|
Concat $ map (convertExpr SelfDetermined) exprs
|
|
|
|
|
convertExpr _ (Pattern items) =
|
|
|
|
|
Pattern $ zip
|
|
|
|
|
(map fst items)
|
|
|
|
|
(map (convertExpr SelfDetermined . snd) items)
|
|
|
|
|
convertExpr _ (Call expr (Args pnArgs kwArgs)) =
|
|
|
|
|
Call expr $ Args pnArgs' kwArgs'
|
|
|
|
|
where
|
|
|
|
|
pnArgs' = map (convertExpr SelfDetermined) pnArgs
|
|
|
|
|
Pattern kwArgs' = convertExpr SelfDetermined $ Pattern kwArgs
|
|
|
|
|
convertExpr _ (Repeat count exprs) =
|
|
|
|
|
Repeat count $ map (convertExpr SelfDetermined) exprs
|
|
|
|
|
convertExpr SelfDetermined (Mux cond (e1 @ UU{}) (e2 @ UU{})) =
|
|
|
|
|
Mux
|
|
|
|
|
(convertExpr SelfDetermined cond)
|
|
|
|
|
(convertExpr SelfDetermined e1)
|
|
|
|
|
(convertExpr SelfDetermined e2)
|
|
|
|
|
convertExpr SelfDetermined (Mux cond e1 e2) =
|
|
|
|
|
Mux
|
|
|
|
|
(convertExpr SelfDetermined cond)
|
|
|
|
|
(convertExpr (ContextDetermined e2) e1)
|
|
|
|
|
(convertExpr (ContextDetermined e1) e2)
|
|
|
|
|
convertExpr (ContextDetermined expr) (Mux cond e1 e2) =
|
|
|
|
|
Mux
|
|
|
|
|
(convertExpr SelfDetermined cond)
|
|
|
|
|
(convertExpr context e1)
|
|
|
|
|
(convertExpr context e2)
|
|
|
|
|
where context = ContextDetermined expr
|
|
|
|
|
convertExpr SelfDetermined (BinOp op e1 e2) =
|
|
|
|
|
if isPeerSizedBinOp op || isParentSizedBinOp op
|
|
|
|
|
then BinOp op
|
|
|
|
|
(convertExpr (ContextDetermined e2) e1)
|
|
|
|
|
(convertExpr (ContextDetermined e1) e2)
|
|
|
|
|
else BinOp op
|
|
|
|
|
(convertExpr SelfDetermined e1)
|
|
|
|
|
(convertExpr SelfDetermined e2)
|
|
|
|
|
convertExpr (ContextDetermined expr) (BinOp op e1 e2) =
|
|
|
|
|
if isPeerSizedBinOp op then
|
|
|
|
|
BinOp op
|
|
|
|
|
(convertExpr (ContextDetermined e2) e1)
|
|
|
|
|
(convertExpr (ContextDetermined e1) e2)
|
|
|
|
|
else if isParentSizedBinOp op then
|
|
|
|
|
BinOp op
|
|
|
|
|
(convertExpr context e1)
|
|
|
|
|
(convertExpr context e2)
|
|
|
|
|
else
|
|
|
|
|
BinOp op
|
|
|
|
|
(convertExpr SelfDetermined e1)
|
|
|
|
|
(convertExpr SelfDetermined e2)
|
|
|
|
|
where context = ContextDetermined expr
|
|
|
|
|
convertExpr context (UniOp op expr) =
|
|
|
|
|
if isSizedUniOp op
|
|
|
|
|
then UniOp op (convertExpr context expr)
|
|
|
|
|
else UniOp op (convertExpr SelfDetermined expr)
|
|
|
|
|
convertExpr SelfDetermined (UU ch) =
|
|
|
|
|
literalFor ch
|
|
|
|
|
convertExpr (ContextDetermined expr) (UU ch) =
|
|
|
|
|
sizedLiteralFor expr ch
|
|
|
|
|
convertExpr _ other = other
|
|
|
|
|
|
|
|
|
|
pattern UU :: Char -> Expr
|
2020-07-12 23:06:27 +02:00
|
|
|
pattern UU ch = Number (UnbasedUnsized ch)
|
2020-06-15 03:43:32 +02:00
|
|
|
|
|
|
|
|
convertType :: Type -> Type
|
2020-07-07 05:40:07 +02:00
|
|
|
convertType (TypeOf e) = TypeOf $ convertExpr SelfDetermined e
|
2020-06-15 03:43:32 +02:00
|
|
|
convertType other = other
|
|
|
|
|
|
2020-07-07 05:40:07 +02:00
|
|
|
isParentSizedBinOp :: BinOp -> Bool
|
|
|
|
|
isParentSizedBinOp BitAnd = True
|
|
|
|
|
isParentSizedBinOp BitXor = True
|
|
|
|
|
isParentSizedBinOp BitXnor = True
|
|
|
|
|
isParentSizedBinOp BitOr = True
|
|
|
|
|
isParentSizedBinOp Mul = True
|
|
|
|
|
isParentSizedBinOp Div = True
|
|
|
|
|
isParentSizedBinOp Mod = True
|
|
|
|
|
isParentSizedBinOp Add = True
|
|
|
|
|
isParentSizedBinOp Sub = True
|
|
|
|
|
isParentSizedBinOp _ = False
|
|
|
|
|
|
|
|
|
|
isPeerSizedBinOp :: BinOp -> Bool
|
|
|
|
|
isPeerSizedBinOp Eq = True
|
|
|
|
|
isPeerSizedBinOp Ne = True
|
|
|
|
|
isPeerSizedBinOp TEq = True
|
|
|
|
|
isPeerSizedBinOp TNe = True
|
|
|
|
|
isPeerSizedBinOp WEq = True
|
|
|
|
|
isPeerSizedBinOp WNe = True
|
|
|
|
|
isPeerSizedBinOp Lt = True
|
|
|
|
|
isPeerSizedBinOp Le = True
|
|
|
|
|
isPeerSizedBinOp Gt = True
|
|
|
|
|
isPeerSizedBinOp Ge = True
|
|
|
|
|
isPeerSizedBinOp _ = False
|
|
|
|
|
|
|
|
|
|
isSizedUniOp :: UniOp -> Bool
|
|
|
|
|
isSizedUniOp = (/= LogNot)
|