mirror of https://github.com/zachjs/sv2v.git
refactor cast conversion
- delegate cast type and sign resolution to TypeOf conversion - internal support for injecting data declarations into statements - fix size and sign of unbased unsized literals used in casts - avoid generating many unnecessary explicit casts - support casts which depend on localparams within procedures - expression traversal correctly visits types within type casts - fix typeof on expressions of net types - handle additional edge cases for unsized integer array patterns - preserve signedness of implicitly flattened unpacked integer arrays
This commit is contained in:
parent
c656cbb977
commit
dd1a9efb40
|
|
@ -13,6 +13,7 @@ import qualified Convert.AlwaysKW
|
|||
import qualified Convert.AsgnOp
|
||||
import qualified Convert.Assertion
|
||||
import qualified Convert.BlockDecl
|
||||
import qualified Convert.Cast
|
||||
import qualified Convert.DimensionQuery
|
||||
import qualified Convert.DuplicateGenvar
|
||||
import qualified Convert.EmptyArgs
|
||||
|
|
@ -35,9 +36,7 @@ import qualified Convert.Package
|
|||
import qualified Convert.ParamNoDefault
|
||||
import qualified Convert.ParamType
|
||||
import qualified Convert.RemoveComments
|
||||
import qualified Convert.SignCast
|
||||
import qualified Convert.Simplify
|
||||
import qualified Convert.SizeCast
|
||||
import qualified Convert.StarPort
|
||||
import qualified Convert.Stream
|
||||
import qualified Convert.StringParam
|
||||
|
|
@ -70,11 +69,11 @@ phases excludes =
|
|||
, Convert.KWArgs.convert
|
||||
, Convert.LogOp.convert
|
||||
, Convert.MultiplePacked.convert
|
||||
, Convert.UnbasedUnsized.convert
|
||||
, Convert.Cast.convert
|
||||
, Convert.TypeOf.convert
|
||||
, Convert.DimensionQuery.convert
|
||||
, Convert.ParamType.convert
|
||||
, Convert.UnbasedUnsized.convert
|
||||
, Convert.SizeCast.convert
|
||||
, Convert.Simplify.convert
|
||||
, Convert.Stream.convert
|
||||
, Convert.Struct.convert
|
||||
|
|
@ -83,7 +82,6 @@ phases excludes =
|
|||
, Convert.Unique.convert
|
||||
, Convert.UnpackedArray.convert
|
||||
, Convert.Unsigned.convert
|
||||
, Convert.SignCast.convert
|
||||
, Convert.Wildcard.convert
|
||||
, Convert.Enum.convert
|
||||
, Convert.ForDecl.convert
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion of elaborated type casts
|
||||
-
|
||||
- Much of the work of elaborating various casts into explicit integer vector
|
||||
- type casts happens in the TypeOf conversion, which contains the primary logic
|
||||
- for resolving the type and signedness of expressions. It also removes
|
||||
- redundant explicit casts to produce cleaner output.
|
||||
-
|
||||
- Type casts are defined as producing the result of the expression assigned to
|
||||
- a variable of the given type. In the general case, this conversion generates
|
||||
- a pass-through function which performs this assignment-based casting. This
|
||||
- allows for casts to be used anywhere expressions are used, including within
|
||||
- constant expressions.
|
||||
-
|
||||
- It is possible for the type in a cast to refer to localparams within a
|
||||
- procedure. Without evaluating the localparam itself, a function outside of
|
||||
- the procedure cannot refer to the size of the type in the cast. In these
|
||||
- scenarios, the cast is instead performed by adding a temporary parameter or
|
||||
- data declaration within the procedure and assigning the expression to that
|
||||
- declaration to perform the cast.
|
||||
-
|
||||
- A few common cases of casts on number literals are fully elaborated into
|
||||
- their corresponding resulting number literals to avoid excessive noise.
|
||||
-}
|
||||
|
||||
module Convert.Cast (convert) where
|
||||
|
||||
import Control.Monad.Writer.Strict
|
||||
import Data.List (isPrefixOf)
|
||||
|
||||
import Convert.ExprUtils
|
||||
import Convert.Scoper
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert = map $ traverseDescriptions convertDescription
|
||||
|
||||
convertDescription :: Description -> Description
|
||||
convertDescription description =
|
||||
traverseModuleItems dropDuplicateCaster $
|
||||
partScoper
|
||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
||||
description
|
||||
|
||||
type ST = Scoper Expr
|
||||
|
||||
traverseDeclM :: Decl -> ST Decl
|
||||
traverseDeclM decl = do
|
||||
decl' <- case decl of
|
||||
Variable d t x a e -> do
|
||||
enterStmt
|
||||
e' <- traverseExprM e
|
||||
exitStmt
|
||||
details <- lookupLocalIdentM x
|
||||
if isPrefixOf "sv2v_cast_" x && details /= Nothing
|
||||
then return $ Variable Local t DuplicateTag [] Nil
|
||||
else do
|
||||
insertElem x Nil
|
||||
return $ Variable d t x a e'
|
||||
Param _ _ x _ ->
|
||||
insertElem x Nil >> return decl
|
||||
ParamType _ _ _ -> return decl
|
||||
CommentDecl _ -> return decl
|
||||
traverseDeclExprsM traverseExprM decl'
|
||||
|
||||
pattern DuplicateTag :: Identifier
|
||||
pattern DuplicateTag = ":duplicate_cast_to_be_removed:"
|
||||
|
||||
dropDuplicateCaster :: ModuleItem -> ModuleItem
|
||||
dropDuplicateCaster (MIPackageItem (Function _ _ DuplicateTag _ _)) =
|
||||
Generate []
|
||||
dropDuplicateCaster other = other
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> ST ModuleItem
|
||||
traverseModuleItemM (Genvar x) =
|
||||
insertElem x Nil >> return (Genvar x)
|
||||
traverseModuleItemM item =
|
||||
traverseExprsM traverseExprM item
|
||||
|
||||
traverseGenItemM :: GenItem -> ST GenItem
|
||||
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||
|
||||
traverseStmtM :: Stmt -> ST Stmt
|
||||
traverseStmtM stmt = do
|
||||
enterStmt
|
||||
stmt' <- traverseStmtExprsM traverseExprM stmt
|
||||
exitStmt
|
||||
return stmt'
|
||||
|
||||
traverseExprM :: Expr -> ST Expr
|
||||
traverseExprM (Cast (Left (IntegerVector _ sg rs)) e) = do
|
||||
e' <- traverseExprM e
|
||||
convertCastM (dimensionsSize rs) e' signed
|
||||
where signed = sg == Signed
|
||||
traverseExprM other =
|
||||
traverseSinglyNestedExprsM traverseExprM other
|
||||
|
||||
convertCastM :: Expr -> Expr -> Bool -> ST Expr
|
||||
convertCastM (RawNum size) (RawNum val) signed =
|
||||
return $ Number $ Decimal (fromIntegral size) signed val'
|
||||
where val' = val `mod` (2 ^ size)
|
||||
convertCastM (RawNum size) (Number (Based 1 True Binary a b)) signed =
|
||||
return $ Number $ Based (fromIntegral size) signed Binary
|
||||
(val * a) (val * b)
|
||||
where val = (2 ^ size) - 1
|
||||
convertCastM (RawNum size) (Number (UnbasedUnsized ch)) signed =
|
||||
convertCastM (RawNum size) (Number num) signed
|
||||
where
|
||||
num = Based 1 True Binary a b
|
||||
(a, b) = case ch of
|
||||
'0' -> (0, 0)
|
||||
'1' -> (1, 0)
|
||||
'x' -> (0, 1)
|
||||
'z' -> (1, 1)
|
||||
_ -> error $ "unexpected unbased-unsized digit: " ++ [ch]
|
||||
convertCastM size value signed = do
|
||||
value' <- traverseExprM value
|
||||
useFn <- embedScopes canUseCastFn size
|
||||
if useFn then do
|
||||
let name = castFnName size signed
|
||||
details <- lookupLocalIdentM name
|
||||
when (details == Nothing) $
|
||||
injectItem $ castFn name size signed
|
||||
return $ Call (Ident name) (Args [value'] [])
|
||||
else do
|
||||
name <- castDeclName 0
|
||||
insertElem name Nil
|
||||
useVar <- withinStmt
|
||||
injectDecl $ castDecl useVar name value' size signed
|
||||
return $ Ident name
|
||||
|
||||
-- checks if a cast size can be hoisted to a cast function
|
||||
canUseCastFn :: Scopes a -> Expr -> Bool
|
||||
canUseCastFn scopes size =
|
||||
not (inProcedure && anyNonLocal)
|
||||
where
|
||||
inProcedure = withinProcedure scopes
|
||||
anyNonLocal = getAny $ execWriter $
|
||||
collectNestedExprsM collectNonLocalExprM size
|
||||
collectNonLocalExprM :: Expr -> Writer Any ()
|
||||
collectNonLocalExprM expr =
|
||||
case lookupElem scopes expr of
|
||||
Nothing -> return ()
|
||||
Just ([_, _], _, _) -> return ()
|
||||
Just (_, _, _) -> tell $ Any True
|
||||
|
||||
castType :: Expr -> Bool -> Type
|
||||
castType size signed =
|
||||
IntegerVector TLogic sg [r]
|
||||
where
|
||||
r = (simplify $ BinOp Sub size (RawNum 1), RawNum 0)
|
||||
sg = if signed then Signed else Unspecified
|
||||
|
||||
castFn :: Identifier -> Expr -> Bool -> ModuleItem
|
||||
castFn name size signed =
|
||||
MIPackageItem $ Function Automatic t name [decl] [stmt]
|
||||
where
|
||||
inp = "inp"
|
||||
t = castType size signed
|
||||
decl = Variable Input t inp [] Nil
|
||||
stmt = Asgn AsgnOpEq Nothing (LHSIdent name) (Ident inp)
|
||||
|
||||
castFnName :: Expr -> Bool -> String
|
||||
castFnName size signed =
|
||||
"sv2v_cast_" ++ sizeStr ++ suffix
|
||||
where
|
||||
sizeStr = case size of
|
||||
Number n ->
|
||||
case numberToInteger n of
|
||||
Just v -> show v
|
||||
_ -> shortHash size
|
||||
_ -> shortHash size
|
||||
suffix = if signed then "_signed" else ""
|
||||
|
||||
castDecl :: Bool -> Identifier -> Expr -> Expr -> Bool -> Decl
|
||||
castDecl useVar name value size signed =
|
||||
if useVar
|
||||
then Variable Local t name [] value
|
||||
else Param Localparam t name value
|
||||
where t = castType size signed
|
||||
|
||||
castDeclName :: Int -> ST String
|
||||
castDeclName counter = do
|
||||
details <- lookupElemM name
|
||||
if details == Nothing
|
||||
then return name
|
||||
else castDeclName (counter + 1)
|
||||
where
|
||||
name = if counter == 0
|
||||
then prefix
|
||||
else prefix ++ '_' : show counter
|
||||
prefix = "sv2v_tmp_cast"
|
||||
|
||||
-- track whether procedural casts should use variables
|
||||
pattern WithinStmt :: Identifier
|
||||
pattern WithinStmt = ":within_stmt:"
|
||||
withinStmt :: ST Bool
|
||||
withinStmt = do
|
||||
details <- lookupElemM WithinStmt
|
||||
return $ case details of
|
||||
Just (_, _, t) -> t /= Nil
|
||||
Nothing -> False
|
||||
enterStmt :: ST ()
|
||||
enterStmt = do
|
||||
inProcedure <- withinProcedureM
|
||||
when inProcedure $ insertElem WithinStmt (RawNum 1)
|
||||
exitStmt :: ST ()
|
||||
exitStmt = do
|
||||
inProcedure <- withinProcedureM
|
||||
when inProcedure $ insertElem WithinStmt Nil
|
||||
|
|
@ -32,6 +32,7 @@ module Convert.Scoper
|
|||
, partScoperT
|
||||
, insertElem
|
||||
, injectItem
|
||||
, injectDecl
|
||||
, lookupElem
|
||||
, lookupElemM
|
||||
, Access(..)
|
||||
|
|
@ -83,7 +84,8 @@ data Scopes a = Scopes
|
|||
{ sCurrent :: [Tier]
|
||||
, sMapping :: Mapping a
|
||||
, sProcedure :: Bool
|
||||
, sInjected :: [ModuleItem]
|
||||
, sInjectedItems :: [ModuleItem]
|
||||
, sInjectedDecls :: [Decl]
|
||||
} deriving Show
|
||||
|
||||
extractMapping :: Scopes a -> Map.Map Identifier a
|
||||
|
|
@ -176,13 +178,25 @@ insertElem key element = do
|
|||
|
||||
injectItem :: Monad m => ModuleItem -> ScoperT a m ()
|
||||
injectItem item =
|
||||
modify' $ \s -> s { sInjected = add $ sInjected s }
|
||||
where
|
||||
add :: [ModuleItem] -> [ModuleItem]
|
||||
add items =
|
||||
if elem item items
|
||||
then items
|
||||
else items ++ [item]
|
||||
modify' $ \s -> s { sInjectedItems = item : sInjectedItems s }
|
||||
|
||||
injectDecl :: Monad m => Decl -> ScoperT a m ()
|
||||
injectDecl decl =
|
||||
modify' $ \s -> s { sInjectedDecls = decl : sInjectedDecls s }
|
||||
|
||||
consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem]
|
||||
consumeInjectedItems = do
|
||||
injected <- gets sInjectedItems
|
||||
when (not $ null injected) $
|
||||
modify' $ \s -> s { sInjectedItems = [] }
|
||||
return $ reverse injected
|
||||
|
||||
consumeInjectedDecls :: Monad m => ScoperT a m [Decl]
|
||||
consumeInjectedDecls = do
|
||||
injected <- gets sInjectedDecls
|
||||
when (not $ null injected) $
|
||||
modify' $ \s -> s { sInjectedDecls = [] }
|
||||
return $ reverse injected
|
||||
|
||||
type Replacements = Map.Map Identifier Expr
|
||||
|
||||
|
|
@ -305,7 +319,7 @@ runScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items =
|
|||
items' <- mapM wrappedModuleItemMapper items
|
||||
exitScope topName ""
|
||||
return items'
|
||||
initialState = Scopes [] Map.empty False []
|
||||
initialState = Scopes [] Map.empty False [] []
|
||||
|
||||
wrappedModuleItemMapper = scopeModuleItemT
|
||||
declMapper moduleItemMapper genItemMapper stmtMapper
|
||||
|
|
@ -324,13 +338,28 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
|
|||
fullStmtMapper :: Stmt -> ScoperT a m Stmt
|
||||
fullStmtMapper (Block kw name decls stmts) = do
|
||||
enterScope name ""
|
||||
decls' <- mapM declMapper decls
|
||||
decls' <- fmap concat $ mapM declMapper' decls
|
||||
stmts' <- mapM fullStmtMapper stmts
|
||||
exitScope name ""
|
||||
return $ Block kw name decls' stmts'
|
||||
-- TODO: Do we need to support the various procedural loops?
|
||||
fullStmtMapper stmt =
|
||||
stmtMapper stmt >>= traverseSinglyNestedStmtsM fullStmtMapper
|
||||
fullStmtMapper stmt = do
|
||||
stmt' <- stmtMapper stmt
|
||||
injected <- consumeInjectedDecls
|
||||
if null injected
|
||||
then traverseSinglyNestedStmtsM fullStmtMapper stmt'
|
||||
else fullStmtMapper $ Block Seq "" injected [stmt']
|
||||
|
||||
-- converts a decl and adds decls injected during conversion
|
||||
declMapper' :: Decl -> ScoperT a m [Decl]
|
||||
declMapper' decl = do
|
||||
decl' <- declMapper decl
|
||||
injected <- consumeInjectedDecls
|
||||
if null injected
|
||||
then return [decl']
|
||||
else do
|
||||
injected' <- mapM declMapper injected
|
||||
return $ injected' ++ [decl']
|
||||
|
||||
mapTFDecls :: [Decl] -> ScoperT a m [Decl]
|
||||
mapTFDecls = mapTFDecls' 0
|
||||
|
|
@ -340,14 +369,14 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
|
|||
mapTFDecls' idx (decl : decls) =
|
||||
case argIdxDecl decl of
|
||||
Nothing -> do
|
||||
decl' <- declMapper decl
|
||||
decl' <- declMapper' decl
|
||||
decls' <- mapTFDecls' idx decls
|
||||
return $ decl' : decls'
|
||||
return $ decl' ++ decls'
|
||||
Just declFunc -> do
|
||||
_ <- declMapper $ declFunc idx
|
||||
decl' <- declMapper decl
|
||||
decl' <- declMapper' decl
|
||||
decls' <- mapTFDecls' (idx + 1) decls
|
||||
return $ decl' : decls'
|
||||
return $ decl' ++ decls'
|
||||
|
||||
argIdxDecl :: Decl -> Maybe (Int -> Decl)
|
||||
argIdxDecl (Variable d t _ a e) =
|
||||
|
|
@ -369,11 +398,10 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
|
|||
wrappedModuleItemMapper :: ModuleItem -> ScoperT a m ModuleItem
|
||||
wrappedModuleItemMapper item = do
|
||||
item' <- fullModuleItemMapper item
|
||||
injected <- gets sInjected
|
||||
injected <- consumeInjectedItems
|
||||
if null injected
|
||||
then return item'
|
||||
else do
|
||||
modify' $ \s -> s { sInjected = [] }
|
||||
injected' <- mapM fullModuleItemMapper injected
|
||||
return $ Generate $ map GenModuleItem $ injected' ++ [item']
|
||||
fullModuleItemMapper :: ModuleItem -> ScoperT a m ModuleItem
|
||||
|
|
@ -423,11 +451,10 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
|
|||
fullGenItemMapper :: GenItem -> ScoperT a m GenItem
|
||||
fullGenItemMapper genItem = do
|
||||
genItem' <- genItemMapper genItem
|
||||
injected <- gets sInjected
|
||||
injected <- consumeInjectedItems
|
||||
if null injected
|
||||
then scopeGenItemMapper genItem'
|
||||
else do
|
||||
modify' $ \s -> s { sInjected = [] }
|
||||
injected' <- mapM fullModuleItemMapper injected
|
||||
genItem'' <- scopeGenItemMapper genItem'
|
||||
let genItems = map GenModuleItem injected' ++ [genItem'']
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for `signed` and `unsigned` type casts.
|
||||
-
|
||||
- SystemVerilog has `signed'(foo)` and `unsigned'(foo)` as syntactic sugar for
|
||||
- the `$signed` and `$unsigned` system functions present in Verilog-2005. This
|
||||
- conversion elaborates these casts.
|
||||
-}
|
||||
|
||||
module Convert.SignCast (convert) where
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert =
|
||||
map $
|
||||
traverseDescriptions $
|
||||
traverseModuleItems $
|
||||
traverseExprs $
|
||||
traverseNestedExprs convertExpr
|
||||
|
||||
convertExpr :: Expr -> Expr
|
||||
convertExpr (Cast (Left (Implicit Signed [])) e) =
|
||||
Call (Ident "$signed") (Args [e] [])
|
||||
convertExpr (Cast (Left (Implicit Unsigned [])) e) =
|
||||
Call (Ident "$unsigned") (Args [e] [])
|
||||
convertExpr other = other
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion of size casts on non-constant expressions.
|
||||
-}
|
||||
|
||||
module Convert.SizeCast (convert) where
|
||||
|
||||
import Control.Monad.Writer.Strict
|
||||
import Data.List (isPrefixOf)
|
||||
|
||||
import Convert.ExprUtils
|
||||
import Convert.Scoper
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert = map $ traverseDescriptions convertDescription
|
||||
|
||||
convertDescription :: Description -> Description
|
||||
convertDescription =
|
||||
traverseModuleItems dropDuplicateCaster . partScoper
|
||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
||||
|
||||
traverseDeclM :: Decl -> Scoper Type Decl
|
||||
traverseDeclM decl = do
|
||||
decl' <- case decl of
|
||||
Variable _ t x _ _ -> do
|
||||
details <- lookupLocalIdentM x
|
||||
if isPrefixOf "sv2v_cast_" x && details /= Nothing
|
||||
then return $ Variable Local t DuplicateTag [] Nil
|
||||
else insertElem x t >> return decl
|
||||
Param _ t x _ -> do
|
||||
inProcedure <- withinProcedureM
|
||||
when (not inProcedure) $ insertElem x t
|
||||
return decl
|
||||
ParamType _ _ _ -> return decl
|
||||
CommentDecl _ -> return decl
|
||||
traverseDeclExprsM traverseExprM decl'
|
||||
|
||||
pattern DuplicateTag :: Identifier
|
||||
pattern DuplicateTag = ":duplicate_cast_to_be_removed:"
|
||||
|
||||
dropDuplicateCaster :: ModuleItem -> ModuleItem
|
||||
dropDuplicateCaster (MIPackageItem (Function _ _ DuplicateTag _ _)) =
|
||||
Generate []
|
||||
dropDuplicateCaster other = other
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
|
||||
traverseModuleItemM (Genvar x) =
|
||||
insertElem x (IntegerAtom TInteger Unspecified) >> return (Genvar x)
|
||||
traverseModuleItemM item =
|
||||
traverseExprsM traverseExprM item
|
||||
|
||||
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
||||
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||
|
||||
traverseStmtM :: Stmt -> Scoper Type Stmt
|
||||
traverseStmtM = traverseStmtExprsM traverseExprM
|
||||
|
||||
traverseExprM :: Expr -> Scoper Type Expr
|
||||
traverseExprM =
|
||||
traverseNestedExprsM convertExprM
|
||||
where
|
||||
convertExprM :: Expr -> Scoper Type Expr
|
||||
convertExprM (Cast (Right (Number s)) (Number n)) =
|
||||
case n of
|
||||
UnbasedUnsized{} -> fallback
|
||||
Decimal (-32) True val ->
|
||||
num $ Decimal (fromIntegral size) False val'
|
||||
where
|
||||
Just size = numberToInteger s
|
||||
val' = val `mod` (2 ^ size)
|
||||
Decimal size signed val ->
|
||||
if sizesMatch
|
||||
then num $ Decimal (abs size) signed val
|
||||
else fallback
|
||||
Based size signed base vals knds ->
|
||||
if sizesMatch
|
||||
then num $ Based (abs size) signed base vals knds
|
||||
else fallback
|
||||
where
|
||||
sizesMatch = numberToInteger s == Just (numberBitLength n)
|
||||
fallback = convertCastM (Number s) (Number n)
|
||||
num = return . Number
|
||||
convertExprM (Cast (Right (Ident x)) e) = do
|
||||
details <- lookupElemM x
|
||||
-- can't convert this cast yet because x could be a typename
|
||||
if details == Nothing
|
||||
then return $ Cast (Right $ Ident x) e
|
||||
else convertCastM (Ident x) e
|
||||
convertExprM (Cast (Right s) e) =
|
||||
if isSimpleExpr s
|
||||
then convertCastM s e
|
||||
else return $ Cast (Right s) e
|
||||
convertExprM (Cast (Left (IntegerVector _ Signed rs)) e) =
|
||||
convertCastWithSigningM (dimensionsSize rs) e Signed
|
||||
convertExprM (Cast (Left (IntegerVector _ _ rs)) e) =
|
||||
convertExprM $ Cast (Right $ dimensionsSize rs) e
|
||||
convertExprM other = return other
|
||||
|
||||
convertCastM :: Expr -> Expr -> Scoper Type Expr
|
||||
convertCastM (RawNum n) (Number (Based 1 True Binary a b)) =
|
||||
return $ Number $ Based (fromIntegral n) True Binary
|
||||
(extend a) (extend b)
|
||||
where
|
||||
extend 0 = 0
|
||||
extend 1 = (2 ^ n) - 1
|
||||
extend _ = error "not possible"
|
||||
convertCastM (RawNum n) (Number (UnbasedUnsized ch)) =
|
||||
return $ Number $ Based (fromIntegral n) False Binary
|
||||
(extend a) (extend b)
|
||||
where
|
||||
(a, b) = case ch of
|
||||
'0' -> (0, 0)
|
||||
'1' -> (1, 0)
|
||||
'x' -> (0, 1)
|
||||
'z' -> (1, 1)
|
||||
_ -> error $ "unexpected unbased-unsized digit: " ++ [ch]
|
||||
extend :: Integer -> Integer
|
||||
extend 0 = 0
|
||||
extend 1 = (2 ^ n) - 1
|
||||
extend _ = error "not possible"
|
||||
convertCastM s e = do
|
||||
signing <- embedScopes exprSigning e
|
||||
case signing of
|
||||
Just sg -> convertCastWithSigningM s e sg
|
||||
_ -> return $ Cast (Right s) e
|
||||
|
||||
convertCastWithSigningM :: Expr -> Expr -> Signing -> Scoper Type Expr
|
||||
convertCastWithSigningM (RawNum size) (RawNum val) Signed =
|
||||
return $ Number $ Decimal (fromIntegral size) True val'
|
||||
where val' = val `mod` (2 ^ size)
|
||||
convertCastWithSigningM s e sg = do
|
||||
details <- lookupLocalIdentM $ castFnName s sg
|
||||
when (details == Nothing) $ injectItem $ MIPackageItem $ castFn s sg
|
||||
let f = castFnName s sg
|
||||
let args = Args [e] []
|
||||
return $ Call (Ident f) args
|
||||
|
||||
isSimpleExpr :: Expr -> Bool
|
||||
isSimpleExpr =
|
||||
null . execWriter . collectNestedExprsM collectUnresolvedExprM
|
||||
where
|
||||
collectUnresolvedExprM :: Expr -> Writer [Expr] ()
|
||||
collectUnresolvedExprM (expr @ PSIdent{}) = tell [expr]
|
||||
collectUnresolvedExprM (expr @ CSIdent{}) = tell [expr]
|
||||
collectUnresolvedExprM (expr @ DimsFn{}) = tell [expr]
|
||||
collectUnresolvedExprM (expr @ DimFn {}) = tell [expr]
|
||||
collectUnresolvedExprM _ = return ()
|
||||
|
||||
castFn :: Expr -> Signing -> PackageItem
|
||||
castFn e sg =
|
||||
Function Automatic t fnName [decl] [Return $ Ident inp]
|
||||
where
|
||||
inp = "inp"
|
||||
r = (simplify $ BinOp Sub e (RawNum 1), RawNum 0)
|
||||
t = IntegerVector TLogic sg [r]
|
||||
fnName = castFnName e sg
|
||||
decl = Variable Input t inp [] Nil
|
||||
|
||||
castFnName :: Expr -> Signing -> String
|
||||
castFnName e sg =
|
||||
if sg == Unspecified
|
||||
then init name
|
||||
else name
|
||||
where
|
||||
sizeStr = case e of
|
||||
Number n ->
|
||||
case numberToInteger n of
|
||||
Just v -> show v
|
||||
_ -> shortHash e
|
||||
_ -> shortHash e
|
||||
name = "sv2v_cast_" ++ sizeStr ++ "_" ++ show sg
|
||||
|
||||
exprSigning :: Scopes Type -> Expr -> Maybe Signing
|
||||
exprSigning scopes (BinOp op e1 e2) =
|
||||
combiner sg1 sg2
|
||||
where
|
||||
sg1 = exprSigning scopes e1
|
||||
sg2 = exprSigning scopes e2
|
||||
combiner = case op of
|
||||
BitAnd -> combineSigning
|
||||
BitXor -> combineSigning
|
||||
BitXnor -> combineSigning
|
||||
BitOr -> combineSigning
|
||||
Mul -> combineSigning
|
||||
Div -> combineSigning
|
||||
Add -> combineSigning
|
||||
Sub -> combineSigning
|
||||
Mod -> curry fst
|
||||
Pow -> curry fst
|
||||
ShiftAL -> curry fst
|
||||
ShiftAR -> curry fst
|
||||
_ -> \_ _ -> Just Unspecified
|
||||
exprSigning _ (Number n) =
|
||||
Just $ if numberIsSigned n
|
||||
then Signed
|
||||
else Unsigned
|
||||
exprSigning scopes expr =
|
||||
case lookupElem scopes expr of
|
||||
Just (_, _, t) -> typeSigning t
|
||||
Nothing -> Just Unspecified
|
||||
|
||||
combineSigning :: Maybe Signing -> Maybe Signing -> Maybe Signing
|
||||
combineSigning Nothing _ = Nothing
|
||||
combineSigning _ Nothing = Nothing
|
||||
combineSigning (Just Unspecified) _ = Just Unspecified
|
||||
combineSigning _ (Just Unspecified) = Just Unspecified
|
||||
combineSigning (Just Unsigned) _ = Just Unsigned
|
||||
combineSigning _ (Just Unsigned) = Just Unsigned
|
||||
combineSigning (Just Signed) (Just Signed) = Just Signed
|
||||
|
||||
typeSigning :: Type -> Maybe Signing
|
||||
typeSigning (Net _ sg _) = Just sg
|
||||
typeSigning (Implicit sg _) = Just sg
|
||||
typeSigning (IntegerVector _ sg _) = Just sg
|
||||
typeSigning (IntegerAtom t sg ) =
|
||||
Just $ case (sg, t) of
|
||||
(Unspecified, TTime) -> Unsigned
|
||||
(Unspecified, _ ) -> Signed
|
||||
(_ , _ ) -> sg
|
||||
typeSigning _ = Nothing
|
||||
|
|
@ -281,7 +281,9 @@ convertExpr (t @ IntegerVector{}) (Concat exprs) =
|
|||
t' = dropInnerTypeRange t
|
||||
isUnsizedNumber :: Expr -> Bool
|
||||
isUnsizedNumber (Number n) = not $ numberIsSized n
|
||||
isUnsizedNumber (UniOp UniSub e) = isUnsizedNumber e
|
||||
isUnsizedNumber (UniOp _ e) = isUnsizedNumber e
|
||||
isUnsizedNumber (BinOp _ e1 e2) =
|
||||
isUnsizedNumber e1 || isUnsizedNumber e2
|
||||
isUnsizedNumber _ = False
|
||||
|
||||
-- TODO: This is really a conversion for using default patterns to
|
||||
|
|
|
|||
|
|
@ -460,12 +460,10 @@ traverseSinglyNestedExprsM exprMapper = em
|
|||
e2' <- exprMapper e2
|
||||
e3' <- exprMapper e3
|
||||
return $ Mux e1' e2' e3'
|
||||
em (Cast (Left t) e) =
|
||||
exprMapper e >>= return . Cast (Left t)
|
||||
em (Cast (Right e1) e2) = do
|
||||
e1' <- exprMapper e1
|
||||
e2' <- exprMapper e2
|
||||
return $ Cast (Right e1') e2'
|
||||
em (Cast tore e) = do
|
||||
tore' <- typeOrExprMapper tore
|
||||
e' <- exprMapper e
|
||||
return $ Cast tore' e'
|
||||
em (DimsFn f tore) =
|
||||
typeOrExprMapper tore >>= return . DimsFn f
|
||||
em (DimFn f tore e) = do
|
||||
|
|
@ -834,8 +832,8 @@ traverseExprTypesM mapper = exprMapper
|
|||
typeOrExprMapper (Right e) = return $ Right e
|
||||
typeOrExprMapper (Left t) =
|
||||
mapper t >>= return . Left
|
||||
exprMapper (Cast (Left t) e) =
|
||||
mapper t >>= \t' -> return $ Cast (Left t') e
|
||||
exprMapper (Cast tore e) =
|
||||
typeOrExprMapper tore >>= return . flip Cast e
|
||||
exprMapper (DimsFn f tore) =
|
||||
typeOrExprMapper tore >>= return . DimsFn f
|
||||
exprMapper (DimFn f tore e) = do
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@
|
|||
- concatenation conversions, defer the resolution of type information to this
|
||||
- conversion pass by producing nodes with the `type` operator during
|
||||
- elaboration.
|
||||
-
|
||||
- This conversion also elaborates sign and size casts to their primitive types.
|
||||
- Sign casts take on the size of the underlying expression. Size casts take on
|
||||
- the sign of the underlying expression. This conversion incorporates this
|
||||
- elaboration as the canonical source for type information. It also enables the
|
||||
- removal of unnecessary casts often resulting from struct literals or casts in
|
||||
- the source intended to appease certain lint rules.
|
||||
-}
|
||||
|
||||
module Convert.TypeOf (convert) where
|
||||
|
|
@ -18,7 +25,7 @@ module Convert.TypeOf (convert) where
|
|||
import Data.Tuple (swap)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.ExprUtils (endianCondRange, simplify)
|
||||
import Convert.ExprUtils (dimensionsSize, endianCondRange, simplify)
|
||||
import Convert.Scoper
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
|
@ -34,8 +41,8 @@ pattern UnitType = IntegerVector TLogic Unspecified []
|
|||
-- insert the given declaration into the scope, and convert an TypeOfs within
|
||||
traverseDeclM :: Decl -> Scoper Type Decl
|
||||
traverseDeclM decl = do
|
||||
item <- traverseModuleItemM (MIPackageItem $ Decl decl)
|
||||
let MIPackageItem (Decl decl') = item
|
||||
decl' <- traverseDeclExprsM traverseExprM decl
|
||||
>>= traverseDeclTypesM traverseTypeM
|
||||
case decl' of
|
||||
Variable _ (Implicit sg rs) ident a _ ->
|
||||
-- implicit types, which are commonly found in function return
|
||||
|
|
@ -66,7 +73,8 @@ traverseModuleItemM (Genvar x) = do
|
|||
insertElem x $ IntegerAtom TInteger Unspecified
|
||||
return $ Genvar x
|
||||
traverseModuleItemM item =
|
||||
traverseTypesM (traverseNestedTypesM traverseTypeM) item
|
||||
traverseNodesM traverseExprM return traverseTypeM traverseLHSM return item
|
||||
where traverseLHSM = traverseLHSExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a GenItem
|
||||
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
||||
|
|
@ -76,14 +84,57 @@ traverseGenItemM = traverseGenItemExprsM traverseExprM
|
|||
traverseStmtM :: Stmt -> Scoper Type Stmt
|
||||
traverseStmtM = traverseStmtExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a Expr
|
||||
-- convert TypeOf in an Expr
|
||||
traverseExprM :: Expr -> Scoper Type Expr
|
||||
traverseExprM = traverseNestedExprsM $ traverseExprTypesM $
|
||||
traverseNestedTypesM traverseTypeM
|
||||
traverseExprM (Cast (Left (Implicit sg [])) expr) =
|
||||
-- `signed'(foo)` and `unsigned'(foo)` are syntactic sugar for the `$signed`
|
||||
-- and `$unsigned` system functions present in Verilog-2005
|
||||
traverseExprM $ Call (Ident fn) $ Args [expr] []
|
||||
where fn = if sg == Signed then "$signed" else "$unsigned"
|
||||
traverseExprM (Cast (Left t) (Number (UnbasedUnsized ch))) =
|
||||
-- defer until this expression becomes explicit
|
||||
return $ Cast (Left t) (Number (UnbasedUnsized ch))
|
||||
traverseExprM (Cast (Left (t @ (IntegerAtom TInteger _))) expr) =
|
||||
-- convert to cast to an integer vector type
|
||||
traverseExprM $ Cast (Left t') expr
|
||||
where
|
||||
(tf, []) = typeRanges t
|
||||
t' = tf [(RawNum 1, RawNum 1)]
|
||||
traverseExprM (Cast (Left t1) expr) = do
|
||||
expr' <- traverseExprM expr
|
||||
t1' <- traverseTypeM t1
|
||||
t2 <- typeof expr'
|
||||
if typeCastUnneeded t1' t2
|
||||
then traverseExprM $ makeExplicit expr'
|
||||
else return $ Cast (Left t1') expr'
|
||||
traverseExprM (Cast (Right (Ident x)) expr) = do
|
||||
expr' <- traverseExprM expr
|
||||
details <- lookupElemM x
|
||||
if details == Nothing
|
||||
then return $ Cast (Left $ Alias x []) expr'
|
||||
else elaborateSizeCast (Ident x) expr'
|
||||
traverseExprM (Cast (Right size) expr) = do
|
||||
expr' <- traverseExprM expr
|
||||
elaborateSizeCast size expr'
|
||||
traverseExprM other =
|
||||
traverseExprTypesM traverseTypeM other
|
||||
>>= traverseSinglyNestedExprsM traverseExprM
|
||||
|
||||
-- carry forward the signedness of the expression when cast to the given size
|
||||
elaborateSizeCast :: Expr -> Expr -> Scoper Type Expr
|
||||
elaborateSizeCast size value = do
|
||||
t <- typeof value
|
||||
case typeSignedness t of
|
||||
Unspecified -> return $ Cast (Right size) value
|
||||
sg -> traverseExprM $ Cast (Left $ typeOfSize sg size) value
|
||||
|
||||
-- convert TypeOf in a Type
|
||||
traverseTypeM :: Type -> Scoper Type Type
|
||||
traverseTypeM (TypeOf expr) = typeof expr
|
||||
traverseTypeM other = return other
|
||||
traverseTypeM (TypeOf expr) =
|
||||
traverseExprM expr >>= typeof
|
||||
traverseTypeM other =
|
||||
traverseTypeExprsM traverseExprM other
|
||||
>>= traverseSinglyNestedTypesM traverseTypeM
|
||||
|
||||
-- attempts to find the given (potentially hierarchical or generate-scoped)
|
||||
-- expression in the available scope information
|
||||
|
|
@ -92,11 +143,15 @@ lookupTypeOf expr = do
|
|||
details <- lookupElemM expr
|
||||
case details of
|
||||
Nothing -> return $ TypeOf expr
|
||||
Just (_, replacements, typ) ->
|
||||
Just (_, replacements, typ) -> do
|
||||
let typ' = toVarType typ
|
||||
return $ if Map.null replacements
|
||||
then typ
|
||||
else rewriteType replacements typ
|
||||
then typ'
|
||||
else rewriteType replacements typ'
|
||||
where
|
||||
toVarType :: Type -> Type
|
||||
toVarType (Net _ sg rs) = IntegerVector TLogic sg rs
|
||||
toVarType other = other
|
||||
rewriteType :: Replacements -> Type -> Type
|
||||
rewriteType replacements = traverseNestedTypes $ traverseTypeExprs $
|
||||
traverseNestedExprs (replace replacements)
|
||||
|
|
@ -155,6 +210,7 @@ typeof (orig @ (Dot e x)) = do
|
|||
case lookup x $ map swap fields of
|
||||
Just typ -> typ
|
||||
Nothing -> TypeOf orig
|
||||
typeof (Cast (Left t) _) = traverseTypeM t
|
||||
typeof (UniOp op expr) = typeofUniOp op expr
|
||||
typeof (BinOp op a b) = typeofBinOp op a b
|
||||
typeof (Mux _ a b) = largerSizeType a b
|
||||
|
|
@ -190,7 +246,6 @@ typeSignednessOverride fallback sg t =
|
|||
IntegerVector base _ rs -> IntegerVector base sg rs
|
||||
IntegerAtom base _ -> IntegerAtom base sg
|
||||
Net base _ rs -> Net base sg rs
|
||||
Implicit _ rs -> Implicit sg rs
|
||||
_ -> fallback
|
||||
|
||||
-- type of a unary operator expression
|
||||
|
|
@ -262,7 +317,6 @@ binopSignedness Signed Signed = Signed
|
|||
-- returns the signedness of the given type, if possible
|
||||
typeSignedness :: Type -> Signing
|
||||
typeSignedness (Net _ sg _) = signednessFallback Unsigned sg
|
||||
typeSignedness (Implicit sg _) = signednessFallback Unsigned sg
|
||||
typeSignedness (IntegerVector _ sg _) = signednessFallback Unsigned sg
|
||||
typeSignedness (IntegerAtom t sg ) = signednessFallback fallback sg
|
||||
where fallback = if t == TTime then Unsigned else Signed
|
||||
|
|
@ -295,7 +349,7 @@ largerSizeOf a b =
|
|||
typeOfSize :: Signing -> Expr -> Type
|
||||
typeOfSize sg size =
|
||||
IntegerVector TLogic sg [(hi, RawNum 0)]
|
||||
where hi = BinOp Sub size (RawNum 1)
|
||||
where hi = simplify $ BinOp Sub size (RawNum 1)
|
||||
|
||||
-- combines a type with unpacked ranges
|
||||
injectRanges :: Type -> [Range] -> Type
|
||||
|
|
@ -321,3 +375,32 @@ replaceRange r (IntegerAtom TInteger sg) =
|
|||
replaceRange r t =
|
||||
tf (r : rs)
|
||||
where (tf, _ : rs) = typeRanges t
|
||||
|
||||
-- checks for a cast type which already trivially matches the expression type
|
||||
typeCastUnneeded :: Type -> Type -> Bool
|
||||
typeCastUnneeded t1 t2 =
|
||||
sg1 == sg2 && sz1 == sz2 && sz1 /= Nothing && sz2 /= Nothing
|
||||
where
|
||||
sg1 = typeSignedness t1
|
||||
sg2 = typeSignedness t2
|
||||
sz1 = typeSize t1
|
||||
sz2 = typeSize t2
|
||||
typeSize :: Type -> Maybe Expr
|
||||
typeSize (Net _ _ rs) = Just $ dimensionsSize rs
|
||||
typeSize (IntegerVector _ _ rs) = Just $ dimensionsSize rs
|
||||
typeSize (t @ IntegerAtom{}) =
|
||||
typeSize $ tf [(RawNum 1, RawNum 1)]
|
||||
where (tf, []) = typeRanges t
|
||||
typeSize _ = Nothing
|
||||
|
||||
-- explicitly sizes top level numbers used in arithmetic expressions
|
||||
makeExplicit :: Expr -> Expr
|
||||
makeExplicit (Number (Decimal size signed values)) =
|
||||
Number $ Decimal (abs size) signed values
|
||||
makeExplicit (Number (Based size base signed values kinds)) =
|
||||
Number $ Based (abs size) base signed values kinds
|
||||
makeExplicit (BinOp op e1 e2) =
|
||||
BinOp op (makeExplicit e1) (makeExplicit e2)
|
||||
makeExplicit (UniOp op e) =
|
||||
UniOp op $ makeExplicit e
|
||||
makeExplicit other = other
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ baseSize Hex = 16
|
|||
|
||||
-- get the number of bits in a number
|
||||
numberBitLength :: Number -> Integer
|
||||
numberBitLength UnbasedUnsized{} = 32
|
||||
numberBitLength UnbasedUnsized{} = 1
|
||||
numberBitLength (Decimal size _ _) = fromIntegral $ abs size
|
||||
numberBitLength (Based size _ _ _ _) =
|
||||
fromIntegral $
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ nullRange t [] = t
|
|||
nullRange t [(RawNum 0, RawNum 0)] = t
|
||||
nullRange (IntegerAtom TInteger sg) rs =
|
||||
-- integer arrays are allowed in SystemVerilog but not in Verilog
|
||||
IntegerVector TBit sg (rs ++ [(RawNum 31, RawNum 0)])
|
||||
IntegerVector TBit sg' (rs ++ [(RawNum 31, RawNum 0)])
|
||||
where sg' = if sg == Unsigned then Unsigned else Signed
|
||||
nullRange t rs1 =
|
||||
if t == t'
|
||||
then error $ "non-vector type " ++ show t ++
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ executable sv2v
|
|||
Convert.AsgnOp
|
||||
Convert.Assertion
|
||||
Convert.BlockDecl
|
||||
Convert.Cast
|
||||
Convert.DimensionQuery
|
||||
Convert.DuplicateGenvar
|
||||
Convert.EmptyArgs
|
||||
|
|
@ -86,9 +87,7 @@ executable sv2v
|
|||
Convert.ParamType
|
||||
Convert.RemoveComments
|
||||
Convert.Scoper
|
||||
Convert.SignCast
|
||||
Convert.Simplify
|
||||
Convert.SizeCast
|
||||
Convert.StarPort
|
||||
Convert.Stream
|
||||
Convert.StringParam
|
||||
|
|
|
|||
|
|
@ -52,4 +52,19 @@ module top;
|
|||
$display("%b", W'(j));
|
||||
end
|
||||
|
||||
typedef integer T1;
|
||||
typedef integer signed T2;
|
||||
typedef integer unsigned T3;
|
||||
initial begin
|
||||
$display("T1 %0d", T1'(1'sb1));
|
||||
$display("T2 %0d", T2'(1'sb1));
|
||||
$display("T3 %0d", T3'(1'sb1));
|
||||
$display("T1 %0d", T1'(32'sd1));
|
||||
$display("T2 %0d", T2'(32'sd1));
|
||||
$display("T3 %0d", T3'(32'sd1));
|
||||
$display("T1 %0d", T1'(32'd1));
|
||||
$display("T2 %0d", T2'(32'd1));
|
||||
$display("T3 %0d", T3'(32'd1));
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -61,4 +61,16 @@ module top;
|
|||
$display("%b", j_extended);
|
||||
end
|
||||
|
||||
initial begin
|
||||
$display("T1 %0d", -1);
|
||||
$display("T2 %0d", -1);
|
||||
$display("T3 %0d", 32'hFFFF_FFFF);
|
||||
$display("T1 %0d", 1);
|
||||
$display("T2 %0d", 1);
|
||||
$display("T3 %0d", 1);
|
||||
$display("T1 %0d", 1);
|
||||
$display("T2 %0d", 1);
|
||||
$display("T3 %0d", 1);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
module top;
|
||||
reg signed x;
|
||||
initial x = 1;
|
||||
parameter ONE = 1;
|
||||
initial begin
|
||||
localparam A = ONE * 1;
|
||||
localparam B = ONE * 2;
|
||||
localparam C = ONE * 3;
|
||||
localparam D = ONE * 4;
|
||||
localparam E = ONE * 5;
|
||||
$display("%b", 5'(4'(3'(2'(1'(x))))));
|
||||
$display("%b", E'(D'(C'(B'(A'(x))))));
|
||||
$display("%b", E'(D'(C'(B'(A'(E'(D'(C'(B'(A'(x)))))))))));
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module top;
|
||||
reg signed x;
|
||||
initial x = 1;
|
||||
parameter ONE = 1;
|
||||
initial begin : blk
|
||||
reg signed [4:0] y;
|
||||
y = x;
|
||||
$display("%b", y);
|
||||
$display("%b", y);
|
||||
$display("%b", y);
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
`define TEST_CAST(expr, prefix, typ) \
|
||||
initial begin \
|
||||
localparam type T = type(prefix``typ); \
|
||||
logic [63:0] x; \
|
||||
T y; \
|
||||
x = T'(expr); \
|
||||
y = expr; \
|
||||
r``typ = expr; \
|
||||
tmp = r``typ; \
|
||||
$display(`"%b => prefix``typ %b %b %b`", expr, T'(expr), x, y); \
|
||||
end
|
||||
|
||||
module top;
|
||||
wire foo;
|
||||
type(foo) bar;
|
||||
initial bar = 1;
|
||||
|
||||
`include "cast_nettype.vh"
|
||||
|
||||
`TEST('1)
|
||||
`TEST('x)
|
||||
`TEST(1)
|
||||
`TEST(2)
|
||||
`TEST(-1)
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
`define TEST_CAST(expr, prefix, typ) \
|
||||
initial begin \
|
||||
r``typ = expr; \
|
||||
tmp = r``typ; \
|
||||
$display(`"%b => prefix``typ %b %b %b`", expr, r``typ, tmp, r``typ); \
|
||||
end
|
||||
|
||||
module top;
|
||||
wire foo;
|
||||
reg bar;
|
||||
initial bar = 1;
|
||||
|
||||
`include "cast_nettype.vh"
|
||||
|
||||
`TEST(1'sb1)
|
||||
`TEST(1'sbx)
|
||||
`TEST(1)
|
||||
`TEST(2)
|
||||
`TEST(-1)
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
`define TEST(expr) \
|
||||
`TEST_CAST(expr, w, t1) \
|
||||
`TEST_CAST(expr, w, t2) \
|
||||
`TEST_CAST(expr, w, t3) \
|
||||
`TEST_CAST(expr, w, s1) \
|
||||
`TEST_CAST(expr, w, s2) \
|
||||
`TEST_CAST(expr, w, s3) \
|
||||
`TEST_CAST(expr, r, t1) \
|
||||
`TEST_CAST(expr, r, t2) \
|
||||
`TEST_CAST(expr, r, t3) \
|
||||
`TEST_CAST(expr, r, s1) \
|
||||
`TEST_CAST(expr, r, s2) \
|
||||
`TEST_CAST(expr, r, s3)
|
||||
|
||||
wire wt1;
|
||||
wire signed wt2;
|
||||
wire unsigned wt3;
|
||||
|
||||
wire [1:0] ws1;
|
||||
wire signed [1:0] ws2;
|
||||
wire unsigned [1:0] ws3;
|
||||
|
||||
reg rt1;
|
||||
reg signed rt2;
|
||||
reg unsigned rt3;
|
||||
|
||||
reg [1:0] rs1;
|
||||
reg signed [1:0] rs2;
|
||||
reg unsigned [1:0] rs3;
|
||||
|
||||
reg [63:0] tmp;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
`define EXPR $unsigned(WIDTH'(ONES))
|
||||
`define TEST(size) \
|
||||
localparam WIDTH = ONE * size; \
|
||||
localparam x = $unsigned(WIDTH'(ONES)); \
|
||||
integer y, z; \
|
||||
localparam type T = logic [WIDTH-1:0]; \
|
||||
y = T'(ones); \
|
||||
z = $unsigned(WIDTH'(ones)); \
|
||||
$display(`"size: %b %b %b %b`", x, y, z, $unsigned(WIDTH'(ones)));
|
||||
|
||||
module top;
|
||||
parameter ONE = 1;
|
||||
parameter signed [0:0] ONES = 1'sb1;
|
||||
logic signed [0:0] ones;
|
||||
initial ones = 1'sb1;
|
||||
task t;
|
||||
`TEST(6)
|
||||
endtask
|
||||
function f;
|
||||
input integer unused;
|
||||
`TEST(7)
|
||||
endfunction
|
||||
initial t;
|
||||
initial begin
|
||||
integer a;
|
||||
a = f(0);
|
||||
end
|
||||
initial begin
|
||||
`TEST(8)
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
`define TEST(size) \
|
||||
localparam WIDTH = ONE * size; \
|
||||
localparam [WIDTH-1:0] short = ONES; \
|
||||
integer long; \
|
||||
long = short; \
|
||||
$display(`"size: %b %b %b %b`", short, long, long, short);
|
||||
|
||||
module top;
|
||||
parameter ONE = 1;
|
||||
parameter signed [0:0] ONES = 1'sb1;
|
||||
reg signed [0:0] ones;
|
||||
initial ones = 1'sb1;
|
||||
task t;
|
||||
begin : blk1
|
||||
`TEST(6)
|
||||
end
|
||||
endtask
|
||||
function f;
|
||||
input integer unused;
|
||||
begin : blk2
|
||||
`TEST(7)
|
||||
end
|
||||
endfunction
|
||||
initial t;
|
||||
initial begin : blk3
|
||||
integer a;
|
||||
a = f(0);
|
||||
end
|
||||
initial begin : blk4
|
||||
`TEST(8)
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
module top;
|
||||
typedef struct packed {
|
||||
logic x, y;
|
||||
} S;
|
||||
typedef struct packed {
|
||||
S x, y;
|
||||
} T;
|
||||
T t;
|
||||
initial begin
|
||||
t = 1'sb1;
|
||||
$display("%b", t);
|
||||
$display("%b", 5'(t));
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
module top;
|
||||
reg [3:0] t;
|
||||
initial begin : blk
|
||||
reg [4:0] x;
|
||||
t = 1'sb1;
|
||||
x = t;
|
||||
$display("%b", t);
|
||||
$display("%b", x);
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
module top;
|
||||
wire b;
|
||||
wire [1:0] a;
|
||||
function automatic val;
|
||||
input inp;
|
||||
val = inp;
|
||||
endfunction
|
||||
assign b = val(1);
|
||||
assign a = {2 {val(1)}};
|
||||
assign b = 1'b1;
|
||||
assign a = {2 {1'b1}};
|
||||
initial #1 $display("%b %b", a, b);
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
module top;
|
||||
parameter ONE = 1;
|
||||
localparam integer A [4] = { 1, 2, 3, 4 };
|
||||
localparam byte B [4] = { 1, 2, 3, 4 };
|
||||
localparam bit C [4] = { 1, 2, 3, 4 };
|
||||
|
|
@ -8,6 +9,12 @@ module top;
|
|||
localparam integer G [4] = '{ 1, 2, 3, 4 };
|
||||
localparam byte H [4] = '{ 1, 2, 3, 4 };
|
||||
localparam bit I [4] = '{ 1, 2, 3, 4 };
|
||||
localparam integer J [4] = { ONE * '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
localparam byte K [4] = { ONE * '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
localparam bit L [4] = { '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
localparam integer unsigned M [4] = { ONE * '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
localparam byte unsigned N [4] = { ONE * '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
localparam bit unsigned O [4] = { '0, ONE * '1, 5 * ONE, ONE * 6 };
|
||||
initial begin
|
||||
`define PRINT(X) \
|
||||
$display("%b %2d %2d", {X[0], X[1], X[2], X[3]}, $bits(X), $bits(X[0]));
|
||||
|
|
@ -20,6 +27,12 @@ module top;
|
|||
`PRINT(G);
|
||||
`PRINT(H);
|
||||
`PRINT(I);
|
||||
`PRINT(J);
|
||||
`PRINT(K);
|
||||
`PRINT(L);
|
||||
`PRINT(M);
|
||||
`PRINT(N);
|
||||
`PRINT(O);
|
||||
end
|
||||
|
||||
localparam [1:0][0:1] P = '{'{default:'d1}, '{default:'d2}};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ module top;
|
|||
localparam [0:127] G = { 32'h1, 32'h2, 32'h3, 32'h4 };
|
||||
localparam [0:31] H = { 8'h1, 8'h2, 8'h3, 8'h4 };
|
||||
localparam [0:3] I = { 1'h1, 1'h0, 1'h1, 1'h0 };
|
||||
localparam [0:127] J = { 32'h0, 32'hFFFFFFFF, 32'h5, 32'h6 };
|
||||
localparam [0:31] K = { 8'h0, 8'hFF, 8'h5, 8'h6 };
|
||||
localparam [0:3] L = { 1'h0, 1'h1, 1'h1, 1'h0 };
|
||||
localparam [0:127] M = { 32'h0, 32'hFFFFFFFF, 32'h5, 32'h6 };
|
||||
localparam [0:31] N = { 8'h0, 8'hFF, 8'h5, 8'h6 };
|
||||
localparam [0:3] O = { 1'h0, 1'h1, 1'h1, 1'h0 };
|
||||
initial begin
|
||||
$display("%b %2d %2d", A, $bits(A), 32);
|
||||
$display("%b %2d %2d", B, $bits(B), 8);
|
||||
|
|
@ -18,6 +24,12 @@ module top;
|
|||
$display("%b %2d %2d", G, $bits(G), 32);
|
||||
$display("%b %2d %2d", H, $bits(H), 8);
|
||||
$display("%b %2d %2d", I, $bits(I), 1);
|
||||
$display("%b %2d %2d", J, $bits(J), 32);
|
||||
$display("%b %2d %2d", K, $bits(K), 8);
|
||||
$display("%b %2d %2d", L, $bits(L), 1);
|
||||
$display("%b %2d %2d", M, $bits(M), 32);
|
||||
$display("%b %2d %2d", N, $bits(N), 8);
|
||||
$display("%b %2d %2d", O, $bits(O), 1);
|
||||
end
|
||||
|
||||
localparam [3:0] P = 4'b1100;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ module top;
|
|||
logic [2:0] test;
|
||||
logic [3:0] foo;
|
||||
logic [3:0] bar;
|
||||
integer x;
|
||||
reg [7:0] y;
|
||||
|
||||
initial begin
|
||||
test = BW'(0);
|
||||
|
|
@ -11,5 +13,15 @@ module top;
|
|||
$display(foo);
|
||||
bar = $bits(bar)'('1);
|
||||
$display(bar);
|
||||
x = 1'('1); $display("%b %0d", x, x);
|
||||
y = 1'('1); $display("%b %0d", y, y);
|
||||
x = 2'('0); $display("%b %0d", x, x);
|
||||
y = 2'('0); $display("%b %0d", y, y);
|
||||
x = 2'('1); $display("%b %0d", x, x);
|
||||
y = 2'('1); $display("%b %0d", y, y);
|
||||
x = 2'('x); $display("%b %0d", x, x);
|
||||
y = 2'('x); $display("%b %0d", y, y);
|
||||
x = 2'('z); $display("%b %0d", x, x);
|
||||
y = 2'('z); $display("%b %0d", y, y);
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ module top;
|
|||
reg [2:0] test;
|
||||
reg [3:0] foo;
|
||||
reg [3:0] bar;
|
||||
integer x;
|
||||
reg [7:0] y;
|
||||
|
||||
initial begin
|
||||
test = 0;
|
||||
|
|
@ -10,5 +12,15 @@ module top;
|
|||
$display(foo);
|
||||
bar = 4'b1111;
|
||||
$display(bar);
|
||||
x = 1'b1; $display("%b %0d", x, x);
|
||||
y = 1'b1; $display("%b %0d", y, y);
|
||||
x = 2'b00; $display("%b %0d", x, x);
|
||||
y = 2'b00; $display("%b %0d", y, y);
|
||||
x = 2'b11; $display("%b %0d", x, x);
|
||||
y = 2'b11; $display("%b %0d", y, y);
|
||||
x = 2'bxx; $display("%b %0d", x, x);
|
||||
y = 2'bxx; $display("%b %0d", y, y);
|
||||
x = 2'bzz; $display("%b %0d", x, x);
|
||||
y = 2'bzz; $display("%b %0d", y, y);
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -192,4 +192,8 @@ module top;
|
|||
`ASSERT_UNSIGNED(arr[5:0])
|
||||
`ASSERT_UNSIGNED(arr[1+:2])
|
||||
`ASSERT_UNSIGNED(arr[1-:2])
|
||||
`ASSERT_UNSIGNED(integer_signed[0])
|
||||
`ASSERT_UNSIGNED(integer_signed[1])
|
||||
`ASSERT_UNSIGNED(integer_unsigned[0])
|
||||
`ASSERT_UNSIGNED(integer_unsigned[1])
|
||||
endmodule
|
||||
|
|
|
|||
Loading…
Reference in New Issue