mirror of https://github.com/zachjs/sv2v.git
extend typeof operator support
This commit is contained in:
parent
5eaecc6635
commit
e9f9696342
|
|
@ -40,6 +40,7 @@ module Convert.Scoper
|
|||
, withinProcedure
|
||||
, withinProcedureM
|
||||
, scopeModuleItemT
|
||||
, Replacements
|
||||
) where
|
||||
|
||||
import Control.Monad.State.Strict
|
||||
|
|
|
|||
|
|
@ -3,6 +3,14 @@
|
|||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for the `type` operator
|
||||
-
|
||||
- This conversion is responsible for explicit type resolution throughout sv2v.
|
||||
- It uses Scoper to resolve hierarchical expressions in a scope-aware manner.
|
||||
-
|
||||
- Some other conversions, such as the dimension query and streaming
|
||||
- concatenation conversions, defer the resolution of type information to this
|
||||
- conversion pass by producing nodes with the `type` operator during
|
||||
- elaboration.
|
||||
-}
|
||||
|
||||
module Convert.TypeOf (convert) where
|
||||
|
|
@ -19,9 +27,15 @@ convert :: [AST] -> [AST]
|
|||
convert = map $ traverseDescriptions $ partScoper
|
||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
||||
|
||||
-- internal representation of a fully implicit type
|
||||
pattern UnknownType :: Type
|
||||
pattern UnknownType = Implicit Unspecified []
|
||||
|
||||
-- single bit 4-state `logic` type
|
||||
pattern UnitType :: Type
|
||||
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)
|
||||
|
|
@ -29,7 +43,7 @@ traverseDeclM decl = do
|
|||
case decl' of
|
||||
Variable Local UnknownType ident [] Nil -> do
|
||||
-- functions with no return type implicitly return a single bit
|
||||
insertElem ident $ IntegerVector TLogic Unspecified []
|
||||
insertElem ident UnitType
|
||||
return decl'
|
||||
Variable d t ident a e -> do
|
||||
let t' = injectRanges t a
|
||||
|
|
@ -46,6 +60,7 @@ traverseDeclM decl = do
|
|||
ParamType{} -> return decl'
|
||||
CommentDecl{} -> return decl'
|
||||
|
||||
-- convert TypeOf in a ModuleItem
|
||||
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
|
||||
traverseModuleItemM (Genvar x) = do
|
||||
insertElem x $ IntegerAtom TInteger Unspecified
|
||||
|
|
@ -53,12 +68,15 @@ traverseModuleItemM (Genvar x) = do
|
|||
traverseModuleItemM item =
|
||||
traverseTypesM (traverseNestedTypesM traverseTypeM) item
|
||||
|
||||
-- convert TypeOf in a GenItem
|
||||
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
||||
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a Stmt
|
||||
traverseStmtM :: Stmt -> Scoper Type Stmt
|
||||
traverseStmtM = traverseStmtExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a Expr
|
||||
traverseExprM :: Expr -> Scoper Type Expr
|
||||
traverseExprM = traverseNestedExprsM $ traverseExprTypesM $
|
||||
traverseNestedTypesM traverseTypeM
|
||||
|
|
@ -67,6 +85,8 @@ traverseTypeM :: Type -> Scoper Type Type
|
|||
traverseTypeM (TypeOf expr) = typeof expr
|
||||
traverseTypeM other = return other
|
||||
|
||||
-- attempts to find the given (potentially hierarchical or generate-scoped)
|
||||
-- expression in the available scope information
|
||||
lookupTypeOf :: Expr -> Scoper Type Type
|
||||
lookupTypeOf expr = do
|
||||
details <- lookupElemM expr
|
||||
|
|
@ -75,15 +95,18 @@ lookupTypeOf expr = do
|
|||
Just (_, replacements, typ) ->
|
||||
return $ if Map.null replacements
|
||||
then typ
|
||||
else rewriteType typ
|
||||
where
|
||||
rewriteType = traverseNestedTypes $ traverseTypeExprs $
|
||||
traverseNestedExprs replace
|
||||
replace :: Expr -> Expr
|
||||
replace (Ident x) =
|
||||
Map.findWithDefault (Ident x) x replacements
|
||||
replace other = other
|
||||
else rewriteType replacements typ
|
||||
where
|
||||
rewriteType :: Replacements -> Type -> Type
|
||||
rewriteType replacements = traverseNestedTypes $ traverseTypeExprs $
|
||||
traverseNestedExprs (replace replacements)
|
||||
replace :: Replacements -> Expr -> Expr
|
||||
replace replacements (Ident x) =
|
||||
Map.findWithDefault (Ident x) x replacements
|
||||
replace _ other = other
|
||||
|
||||
-- determines the type of an expression based on the available scope information
|
||||
-- according the semantics defined in IEEE 1800-2017, especially Section 11.6
|
||||
typeof :: Expr -> Scoper Type Type
|
||||
typeof (Number n) =
|
||||
return $ IntegerVector TLogic sg [r]
|
||||
|
|
@ -91,14 +114,7 @@ typeof (Number n) =
|
|||
r = (RawNum $ size - 1, RawNum 0)
|
||||
size = numberBitLength n
|
||||
sg = if numberIsSigned n then Signed else Unspecified
|
||||
typeof (Call (Ident "$unsigned") (Args [e] [])) =
|
||||
typeof e
|
||||
typeof (Call (Ident "$signed") (Args [e] [])) =
|
||||
typeof e
|
||||
typeof (Call (Ident "$clog2") (Args [_] [])) =
|
||||
return $ IntegerAtom TInteger Unspecified
|
||||
typeof (Call (Ident x) _) =
|
||||
typeof $ Ident x
|
||||
typeof (Call (Ident x) args) = typeofCall x args
|
||||
typeof (orig @ (Bit e _)) = do
|
||||
t <- typeof e
|
||||
case t of
|
||||
|
|
@ -120,10 +136,8 @@ typeof (orig @ (Range e mode r)) = do
|
|||
typeof (orig @ (Dot e x)) = do
|
||||
t <- typeof e
|
||||
case t of
|
||||
Struct _ fields [] ->
|
||||
return $ fieldsType fields
|
||||
Union _ fields [] ->
|
||||
return $ fieldsType fields
|
||||
Struct _ fields [] -> return $ fieldsType fields
|
||||
Union _ fields [] -> return $ fieldsType fields
|
||||
_ -> lookupTypeOf orig
|
||||
where
|
||||
fieldsType :: [Field] -> Type
|
||||
|
|
@ -132,23 +146,8 @@ typeof (orig @ (Dot e x)) = do
|
|||
Just typ -> typ
|
||||
Nothing -> TypeOf orig
|
||||
typeof (Cast (Right s) _) = return $ typeOfSize s
|
||||
typeof (UniOp UniSub e ) = typeof e
|
||||
typeof (UniOp BitNot e ) = typeof e
|
||||
typeof (UniOp LogNot _ ) = return $ IntegerVector TLogic Unspecified []
|
||||
typeof (BinOp Pow e _) = typeof e
|
||||
typeof (BinOp ShiftL e _) = typeof e
|
||||
typeof (BinOp ShiftR e _) = typeof e
|
||||
typeof (BinOp ShiftAL e _) = typeof e
|
||||
typeof (BinOp ShiftAR e _) = typeof e
|
||||
typeof (BinOp Add a b) = largerSizeType a b
|
||||
typeof (BinOp Sub a b) = largerSizeType a b
|
||||
typeof (BinOp Mul a b) = largerSizeType a b
|
||||
typeof (BinOp Div a b) = largerSizeType a b
|
||||
typeof (BinOp Mod a b) = largerSizeType a b
|
||||
typeof (BinOp BitAnd a b) = largerSizeType a b
|
||||
typeof (BinOp BitXor a b) = largerSizeType a b
|
||||
typeof (BinOp BitXnor a b) = largerSizeType a b
|
||||
typeof (BinOp BitOr a b) = largerSizeType a b
|
||||
typeof (UniOp op expr) = typeofUniOp op expr
|
||||
typeof (BinOp op a b) = typeofBinOp op a b
|
||||
typeof (Mux _ a b) = largerSizeType a b
|
||||
typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs
|
||||
typeof (Repeat reps exprs) = return $ typeOfSize size
|
||||
|
|
@ -158,12 +157,65 @@ typeof (String str) =
|
|||
where
|
||||
r = (RawNum $ len - 1, RawNum 0)
|
||||
len = if null str then 1 else 8 * unescapedLength str
|
||||
unescapedLength :: String -> Integer
|
||||
unescapedLength [] = 0
|
||||
unescapedLength ('\\' : _ : rest) = 1 + unescapedLength rest
|
||||
unescapedLength (_ : rest) = 1 + unescapedLength rest
|
||||
typeof other = lookupTypeOf other
|
||||
|
||||
-- length of a string literal in characters
|
||||
unescapedLength :: String -> Integer
|
||||
unescapedLength [] = 0
|
||||
unescapedLength ('\\' : _ : rest) = 1 + unescapedLength rest
|
||||
unescapedLength (_ : rest) = 1 + unescapedLength rest
|
||||
|
||||
-- type of a standard (non-member) function call
|
||||
typeofCall :: String -> Args -> Scoper Type Type
|
||||
typeofCall "$unsigned" (Args [e] []) = typeof e
|
||||
typeofCall "$signed" (Args [e] []) = typeof e
|
||||
typeofCall "$clog2" (Args [_] []) =
|
||||
return $ IntegerAtom TInteger Unspecified
|
||||
typeofCall fnName _ = typeof $ Ident fnName
|
||||
|
||||
-- type of a unary operator expression
|
||||
typeofUniOp :: UniOp -> Expr -> Scoper Type Type
|
||||
typeofUniOp UniAdd e = typeof e
|
||||
typeofUniOp UniSub e = typeof e
|
||||
typeofUniOp BitNot e = typeof e
|
||||
typeofUniOp _ _ =
|
||||
-- unary reductions and logical negation
|
||||
return UnitType
|
||||
|
||||
-- type of a binary operator expression (Section 11.6.1)
|
||||
typeofBinOp :: BinOp -> Expr -> Expr -> Scoper Type Type
|
||||
typeofBinOp op a b =
|
||||
case op of
|
||||
LogAnd -> unitType
|
||||
LogOr -> unitType
|
||||
LogImp -> unitType
|
||||
LogEq -> unitType
|
||||
Eq -> unitType
|
||||
Ne -> unitType
|
||||
TEq -> unitType
|
||||
TNe -> unitType
|
||||
WEq -> unitType
|
||||
WNe -> unitType
|
||||
Lt -> unitType
|
||||
Le -> unitType
|
||||
Gt -> unitType
|
||||
Ge -> unitType
|
||||
Pow -> typeof a
|
||||
ShiftL -> typeof a
|
||||
ShiftR -> typeof a
|
||||
ShiftAL -> typeof a
|
||||
ShiftAR -> typeof a
|
||||
Add -> largerSizeType a b
|
||||
Sub -> largerSizeType a b
|
||||
Mul -> largerSizeType a b
|
||||
Div -> largerSizeType a b
|
||||
Mod -> largerSizeType a b
|
||||
BitAnd -> largerSizeType a b
|
||||
BitXor -> largerSizeType a b
|
||||
BitXnor -> largerSizeType a b
|
||||
BitOr -> largerSizeType a b
|
||||
where unitType = return UnitType
|
||||
|
||||
-- produces a type large enough to hold either expression
|
||||
largerSizeType :: Expr -> Expr -> Scoper Type Type
|
||||
largerSizeType a (Number (Based 1 _ _ _ _)) = typeof a
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
`define TEST(expr) \
|
||||
$display(`"expr = %b; $bits(expr) = %0d`", (expr), $bits(expr));
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
|
||||
`TEST(4'b1011)
|
||||
`TEST(5'b01110)
|
||||
|
||||
`TEST(! 3'b101)
|
||||
`TEST(~ 3'b101)
|
||||
`TEST(+ 3'b101)
|
||||
`TEST(- 3'b101)
|
||||
`TEST(& 3'b101)
|
||||
`TEST(~& 3'b101)
|
||||
`TEST(| 3'b101)
|
||||
`TEST(~| 3'b101)
|
||||
`TEST(^ 3'b101)
|
||||
`TEST(~^ 3'b101)
|
||||
|
||||
`TEST(4'b1011 && 5'b01110)
|
||||
`TEST(4'b1011 || 5'b01110)
|
||||
`TEST(4'b1011 & 5'b01110)
|
||||
`TEST(4'b1011 ^ 5'b01110)
|
||||
`TEST(4'b1011 ~^ 5'b01110)
|
||||
`TEST(4'b1011 | 5'b01110)
|
||||
`TEST(4'b1011 << 5'b01110)
|
||||
`TEST(4'b1011 >> 5'b01110)
|
||||
`TEST(4'b1011 <<< 5'b01110)
|
||||
`TEST(4'b1011 >>> 5'b01110)
|
||||
`TEST(4'b1011 == 5'b01110)
|
||||
`TEST(4'b1011 != 5'b01110)
|
||||
`TEST(4'b1011 === 5'b01110)
|
||||
`TEST(4'b1011 !== 5'b01110)
|
||||
`TEST(4'b1011 < 5'b01110)
|
||||
`TEST(4'b1011 <= 5'b01110)
|
||||
`TEST(4'b1011 > 5'b01110)
|
||||
`TEST(4'b1011 >= 5'b01110)
|
||||
|
||||
// TODO: iverilog incorrectly handles width of these
|
||||
// `TEST(4'b1011 * 5'b01110)
|
||||
// `TEST(4'b1011 / 5'b01110)
|
||||
// `TEST(4'b1011 % 5'b01110)
|
||||
// `TEST(4'b1011 + 5'b01110)
|
||||
// `TEST(4'b1011 - 5'b01110)
|
||||
// `TEST(4'b1011 ** 5'b01110)
|
||||
|
||||
// TODO: not yet supported by iverilog
|
||||
// `TEST(4'b1011 -> 5'b01110)
|
||||
// `TEST(4'b1011 <-> 5'b01110)
|
||||
// `TEST(4'b1011 ==? 5'b01110)
|
||||
// `TEST(4'b1011 !=? 5'b01110)
|
||||
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "typeof_op.sv"
|
||||
Loading…
Reference in New Issue