diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f3d567..8d69d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ static prefixes, which could cause deep recursion and run out of memory on some designs +### Other Enhancements + +* Added elaboration for accesses to fields of struct constants, which can + substantially improve performance on some designs + ## v0.0.10 ### Breaking Changes diff --git a/src/Convert.hs b/src/Convert.hs index 2b1aac2..593c5f4 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -48,6 +48,7 @@ import qualified Convert.Simplify import qualified Convert.Stream import qualified Convert.StringParam import qualified Convert.Struct +import qualified Convert.StructConst import qualified Convert.TFBlock import qualified Convert.Typedef import qualified Convert.TypeOf @@ -114,6 +115,7 @@ initialPhases selectExclude = , selectExclude Job.Assert Convert.Assertion.convert , selectExclude Job.Always Convert.AlwaysKW.convert , Convert.Package.convert + , Convert.StructConst.convert , Convert.PortDecl.convert , Convert.ParamNoDefault.convert , Convert.ResolveBindings.convert diff --git a/src/Convert/StructConst.hs b/src/Convert/StructConst.hs new file mode 100644 index 0000000..9cfca3d --- /dev/null +++ b/src/Convert/StructConst.hs @@ -0,0 +1,97 @@ +{- sv2v + - Author: Zachary Snow + - + - High-level elaboration for struct constant accesses + - + - This greatly simplifies designs with long sequences of struct parameters + - which extend and reference one another, as seen in BlackParrot. + -} + +module Convert.StructConst (convert) where + +import Control.Monad.State.Strict +import Data.Maybe (fromMaybe) +import Data.Tuple (swap) +import qualified Data.Map.Strict as Map + +import Convert.Traverse +import Language.SystemVerilog.AST + +type StructType = [Field] +type StructValue = [(TypeOrExpr, Expr)] + +type Const = (StructType, StructValue) +type Consts = Map.Map Identifier Const +type Types = Map.Map Identifier StructType + +type SC = State (Types, Consts) + +convert :: [AST] -> [AST] +convert = map $ traverseDescriptions convertDescription + +convertDescription :: Description -> Description +convertDescription = + flip evalState mempty . + traverseModuleItemsM (traverseDeclsM elaborateDecl) + +insertType :: Identifier -> [Field] -> SC () +insertType ident typ = do + (types, consts) <- get + let types' = Map.insert ident typ types + put (types', consts) + +insertConst :: Identifier -> Const -> SC () +insertConst ident cnst = do + (types, consts) <- get + let consts' = Map.insert ident cnst consts + put (types, consts') + +lookupType :: Type -> SC [Field] +lookupType (Alias ident []) = do + maybeFields <- gets $ Map.lookup ident . fst + return $ fromMaybe [] maybeFields +lookupType (Struct (Packed Unspecified) fields []) = + return fields +lookupType _ = return [] + +lookupConst :: Identifier -> SC (Maybe Const) +lookupConst param = gets $ Map.lookup param . snd + +elaborateDecl :: Decl -> SC Decl +-- track struct type parameters +elaborateDecl decl@(ParamType Localparam x t) + | Struct (Packed Unspecified) fields [] <- t = + insertType x fields >> return decl +-- track and resolve struct constants +elaborateDecl (Param Localparam t x e) = do + e' <- elaborateExpr e + fields <- lookupType t + when (not $ null fields) $ do + maybeValues <- extractStructValue e' + case maybeValues of + Just values -> insertConst x (fields, values) + Nothing -> return () + return $ Param Localparam t x e' +elaborateDecl decl = return decl + +-- extract the pattern items, including for simple aliases +extractStructValue :: Expr -> SC (Maybe StructValue) +extractStructValue (Pattern values) = return $ Just values +extractStructValue (Ident param) = fmap (fmap snd) $ lookupConst param +extractStructValue _ = return Nothing + +-- elaborate constant field accesses +elaborateExpr :: Expr -> SC Expr +elaborateExpr expr@(Dot (Ident param) field) = + fmap (fromMaybe expr . join . fmap (resolveParam field)) (lookupConst param) +elaborateExpr expr = + traverseSinglyNestedExprsM elaborateExpr expr + +-- lookup value in struct constant +resolveParam :: Identifier -> Const -> Maybe Expr +resolveParam field (fields, values) = do + fieldType <- lookup field (map swap fields) + value <- mplus + (lookup (Right $ Ident field) values) + (lookup (Left UnknownType) values) + Just $ Cast (Left fieldType) value diff --git a/sv2v.cabal b/sv2v.cabal index b0abdf1..7abd994 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -101,6 +101,7 @@ executable sv2v Convert.Stream Convert.StringParam Convert.Struct + Convert.StructConst Convert.TFBlock Convert.Traverse Convert.Typedef diff --git a/test/core/struct_const.sv b/test/core/struct_const.sv new file mode 100644 index 0000000..c1f85a2 --- /dev/null +++ b/test/core/struct_const.sv @@ -0,0 +1,76 @@ +package pkg; + typedef struct packed { + integer unsigned a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z; + } T; + + `define step(b, o, f) f: o.f == "inv" ? b.f : o.f + `define extend(_b, _o) '{ \ + `step(_b, _o, a), \ + `step(_b, _o, b), \ + `step(_b, _o, c), \ + `step(_b, _o, d), \ + `step(_b, _o, e), \ + `step(_b, _o, f), \ + `step(_b, _o, g), \ + `step(_b, _o, h), \ + `step(_b, _o, i), \ + `step(_b, _o, j), \ + `step(_b, _o, k), \ + `step(_b, _o, l), \ + `step(_b, _o, m), \ + `step(_b, _o, n), \ + `step(_b, _o, o), \ + `step(_b, _o, p), \ + `step(_b, _o, q), \ + `step(_b, _o, r), \ + `step(_b, _o, s), \ + `step(_b, _o, t), \ + `step(_b, _o, u), \ + `step(_b, _o, v), \ + `step(_b, _o, w), \ + `step(_b, _o, x), \ + `step(_b, _o, y), \ + `step(_b, _o, z) \ + } + + localparam X = 1'd0; + localparam Y = 1'd1; + + localparam T a_cfg = '{a: X, b: X, c: X, d: X, e: X, f: X, default: Y}; + + `define expand(let_a, let_b) \ + localparam T let_a``_ext = '{let_a: Y, default: "inv"}; \ + localparam T let_b``_cfg = `extend(let_a``_cfg, let_a``_ext); + + `expand(a, b) + `expand(b, c) + `expand(c, d) + `expand(d, e) + `expand(e, f) + `expand(f, g) + `expand(g, h) + `expand(h, i) + `expand(i, j) + `expand(j, k) + `expand(k, l) + `expand(l, m) + `expand(m, n) + `expand(n, o) + `expand(o, p) + `expand(p, q) + `expand(q, r) + `expand(r, s) + `expand(s, t) + `expand(t, u) + `expand(u, v) + `expand(v, w) + `expand(w, x) + `expand(x, y) + `expand(y, z) + + localparam P = z_cfg.z; +endpackage + +module top; + initial $display(pkg::P); +endmodule diff --git a/test/core/struct_const.v b/test/core/struct_const.v new file mode 100644 index 0000000..b72b3db --- /dev/null +++ b/test/core/struct_const.v @@ -0,0 +1,5 @@ + +module top; + localparam P = 32'd1; + initial $display(P); +endmodule