From e80db124227e1316f36de3fd552e6e408645d3da Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 12 Aug 2020 21:47:24 -0400 Subject: [PATCH] conversion for implicitly variably sized parameters --- src/Convert.hs | 2 + src/Convert/StringParam.hs | 99 ++++++++++++++++++++++++++++++++++++++ src/Convert/TypeOf.hs | 52 ++++++++++++-------- sv2v.cabal | 1 + test/basic/string.sv | 2 +- test/basic/string.v | 2 +- test/basic/string_param.sv | 16 ++++++ test/basic/string_param.v | 16 ++++++ test/basic/string_param.vh | 33 +++++++++++++ 9 files changed, 202 insertions(+), 21 deletions(-) create mode 100644 src/Convert/StringParam.hs create mode 100644 test/basic/string_param.sv create mode 100644 test/basic/string_param.v create mode 100644 test/basic/string_param.vh diff --git a/src/Convert.hs b/src/Convert.hs index e8f8b3c..83ab3ed 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -39,6 +39,7 @@ import qualified Convert.Simplify import qualified Convert.SizeCast import qualified Convert.StarPort import qualified Convert.Stream +import qualified Convert.StringParam import qualified Convert.Struct import qualified Convert.TFBlock import qualified Convert.Typedef @@ -89,6 +90,7 @@ phases excludes = , Convert.ForDecl.convert , Convert.Jump.convert , Convert.Foreach.convert + , Convert.StringParam.convert , selectExclude (Job.Interface, Convert.Interface.convert) , selectExclude (Job.Always , Convert.AlwaysKW.convert) , selectExclude (Job.Succinct , Convert.RemoveComments.convert) diff --git a/src/Convert/StringParam.hs b/src/Convert/StringParam.hs new file mode 100644 index 0000000..83b610c --- /dev/null +++ b/src/Convert/StringParam.hs @@ -0,0 +1,99 @@ +{-# LANGUAGE PatternSynonyms #-} +{- sv2v + - Author: Zachary Snow + - + - Conversion for variable-length string parameters + -} + +module Convert.StringParam (convert) where + +import Control.Monad.Writer.Strict +import qualified Data.Map.Strict as Map + +import Convert.Traverse +import Language.SystemVerilog.AST + +type PartStringParams = Map.Map Identifier [(Identifier, Int)] + +convert :: [AST] -> [AST] +convert files = + if Map.null partStringParams + then files + else map traverseModuleItem files' + where + (files', partStringParams) = runWriter $ + mapM (traverseDescriptionsM traverseDescriptionM) files + traverseModuleItem = traverseDescriptions $ traverseModuleItems $ + mapInstance partStringParams + +-- adds automatic width parameters for string parameters +traverseDescriptionM :: Description -> Writer PartStringParams Description +traverseDescriptionM (Part attrs extern kw lifetime name ports items) = + if null stringParamNames + then return $ Part attrs extern kw lifetime name ports items + else do + tell $ Map.singleton name stringParamIds + return $ Part attrs extern kw lifetime name ports items' + where + (items', stringParamNames) = runWriter $ + mapM (traverseNestedModuleItemsM traverseModuleItemM) items + allParamNames = parameterNames items + stringParamIds = filter (flip elem stringParamNames . fst) $ + zip allParamNames [0..] +traverseDescriptionM other = return other + +-- given a list of module items, produces the parameter names in order +parameterNames :: [ModuleItem] -> [Identifier] +parameterNames = + execWriter . mapM (collectNestedModuleItemsM $ collectDeclsM collectDeclM) + where + collectDeclM :: Decl -> Writer [Identifier] () + collectDeclM (Param Parameter _ x _) = tell [x] + collectDeclM (ParamType Parameter x _) = tell [x] + collectDeclM _ = return () + +pattern UnknownType :: Type +pattern UnknownType = Implicit Unspecified [] + +-- rewrite an existing string parameter +traverseModuleItemM :: ModuleItem -> Writer [Identifier] ModuleItem +traverseModuleItemM (orig @ (MIPackageItem (Decl (Param Parameter t x e)))) = + case (t, e) of + (UnknownType, String str) -> do + tell [x] + return $ Generate $ map wrap [width str, param str] + where wrap = GenModuleItem . MIPackageItem . Decl + _ -> return orig + where + w = widthName x + r = (BinOp Sub (Ident w) (RawNum 1), RawNum 0) + t' = IntegerVector TBit Unspecified [r] + defaultWidth str = DimsFn FnBits $ Right $ String str + width str = Param Parameter UnknownType w (defaultWidth str) + param str = Param Parameter t' x (String str) +traverseModuleItemM other = return other + +widthName :: Identifier -> Identifier +widthName paramName = "_sv2v_width_" ++ paramName + +-- convert isntances which use the converted string parameters +mapInstance :: PartStringParams -> ModuleItem -> ModuleItem +mapInstance partStringParams (Instance m params x rs ports) = + case Map.lookup m partStringParams of + Nothing -> Instance m params x rs ports + Just stringParams -> Instance m params' x rs ports + where params' = concat $ zipWith (expand stringParams) params [0..] + where + expand :: [(Identifier, Int)] -> ParamBinding -> Int -> [ParamBinding] + expand _ (paramName, Left t) _ = [(paramName, Left t)] + expand stringParams (orig @ ("", Right expr)) idx = + if elem idx $ map snd stringParams + then [("", Right width), orig] + else [orig] + where width = DimsFn FnBits $ Right expr + expand stringParams (orig @ (paramName, Right expr)) _ = + if elem paramName $ map fst stringParams + then [(widthName paramName, Right width), orig] + else [orig] + where width = DimsFn FnBits $ Right expr +mapInstance _ other = other diff --git a/src/Convert/TypeOf.hs b/src/Convert/TypeOf.hs index 88f707e..eba8e71 100644 --- a/src/Convert/TypeOf.hs +++ b/src/Convert/TypeOf.hs @@ -37,12 +37,12 @@ traverseDeclM decl = do return $ case t' of UnpackedType t'' a' -> Variable d t'' ident a' e _ -> Variable d t' ident [] e - Param _ t ident e -> do - t' <- if t == UnknownType - then typeof e - else return t - insertElem ident t' - return decl' + Param _ UnknownType ident String{} -> + insertElem ident UnknownType >> return decl' + Param _ UnknownType ident e -> + typeof e >>= insertElem ident >> return decl' + Param _ t ident _ -> + insertElem ident t >> return decl' ParamType{} -> return decl' CommentDecl{} -> return decl' @@ -137,25 +137,39 @@ 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) = return $ largerSizeType a b -typeof (BinOp Sub a b) = return $ largerSizeType a b -typeof (BinOp Mul a b) = return $ largerSizeType a b -typeof (BinOp Div a b) = return $ largerSizeType a b -typeof (BinOp Mod a b) = return $ largerSizeType a b -typeof (BinOp BitAnd a b) = return $ largerSizeType a b -typeof (BinOp BitXor a b) = return $ largerSizeType a b -typeof (BinOp BitXnor a b) = return $ largerSizeType a b -typeof (BinOp BitOr a b) = return $ largerSizeType a b -typeof (Mux _ a b) = return $ largerSizeType a b +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 (Mux _ a b) = largerSizeType a b typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs typeof (Repeat reps exprs) = return $ typeOfSize size where size = BinOp Mul reps (concatSize exprs) -typeof String{} = return UnknownType +typeof (String str) = + return $ IntegerVector TBit Unspecified [r] + 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 -- produces a type large enough to hold either expression -largerSizeType :: Expr -> Expr -> Type -largerSizeType a b = typeOfSize $ largerSizeOf a b +largerSizeType :: Expr -> Expr -> Scoper Type Type +largerSizeType a (Number (Based 1 _ _ _ _)) = typeof a +largerSizeType a b = do + t <- typeof a + u <- typeof b + return $ if t == u + then t + else typeOfSize $ largerSizeOf a b -- returns the total size of concatenated list of expressions concatSize :: [Expr] -> Expr diff --git a/sv2v.cabal b/sv2v.cabal index f4b1f43..24dbc5f 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -89,6 +89,7 @@ executable sv2v Convert.SizeCast Convert.StarPort Convert.Stream + Convert.StringParam Convert.Struct Convert.TFBlock Convert.Traverse diff --git a/test/basic/string.sv b/test/basic/string.sv index 09eddda..e18f906 100644 --- a/test/basic/string.sv +++ b/test/basic/string.sv @@ -1,5 +1,5 @@ module top; - parameter FOO = "some useful string"; + localparam FOO = "some useful string"; localparam type T = type(FOO); localparam T BAR = "some other useful string"; initial $display("'%s' '%s'", FOO, BAR); diff --git a/test/basic/string.v b/test/basic/string.v index 10fd93f..239d86a 100644 --- a/test/basic/string.v +++ b/test/basic/string.v @@ -1,5 +1,5 @@ module top; - parameter FOO = "some useful string"; + localparam FOO = "some useful string"; localparam BAR = "some other useful string"; initial $display("'%s' '%s'", FOO, BAR); endmodule diff --git a/test/basic/string_param.sv b/test/basic/string_param.sv new file mode 100644 index 0000000..2e001be --- /dev/null +++ b/test/basic/string_param.sv @@ -0,0 +1,16 @@ +`include "string_param.vh" + +module Example(inp, out); + parameter PATTERN = "whatever"; + parameter UNUSED = 0; + localparam IN_WIDTH = $bits(PATTERN); + localparam OUT_WIDTH = `COUNT_ONES(PATTERN); + + input [IN_WIDTH - 1:0] inp; + output [OUT_WIDTH - 1:0] out; + if (PATTERN[0]) + assign out[0] = inp[0]; + for (genvar j = 1; j < IN_WIDTH; ++j) + if (PATTERN[j]) + assign out[`COUNT_ONES(PATTERN[j - 1:0])] = inp[j]; +endmodule diff --git a/test/basic/string_param.v b/test/basic/string_param.v new file mode 100644 index 0000000..221e87b --- /dev/null +++ b/test/basic/string_param.v @@ -0,0 +1,16 @@ +`include "string_param.vh" + +module Example(inp, out); + parameter PATTERN = "whatever"; + parameter IN_WIDTH = $bits(PATTERN); + localparam OUT_WIDTH = `COUNT_ONES(PATTERN); + + input wire [IN_WIDTH - 1:0] inp; + output wire [OUT_WIDTH - 1:0] out; + if (PATTERN[0]) + assign out[0] = inp[0]; + genvar j; + for (j = 1; j < IN_WIDTH; j = j + 1) + if (PATTERN[j]) + assign out[`COUNT_ONES(PATTERN[j - 1:0])] = inp[j]; +endmodule diff --git a/test/basic/string_param.vh b/test/basic/string_param.vh new file mode 100644 index 0000000..b886519 --- /dev/null +++ b/test/basic/string_param.vh @@ -0,0 +1,33 @@ +`define COUNT_ONES(expr) (0 \ + + ((expr) >> 0 & 1'b1) + ((expr) >> 1 & 1'b1) + ((expr) >> 2 & 1'b1) + ((expr) >> 3 & 1'b1) \ + + ((expr) >> 4 & 1'b1) + ((expr) >> 5 & 1'b1) + ((expr) >> 6 & 1'b1) + ((expr) >> 7 & 1'b1) \ + + ((expr) >> 8 & 1'b1) + ((expr) >> 9 & 1'b1) + ((expr) >> 10 & 1'b1) + ((expr) >> 11 & 1'b1) \ + + ((expr) >> 12 & 1'b1) + ((expr) >> 13 & 1'b1) + ((expr) >> 14 & 1'b1) + ((expr) >> 15 & 1'b1) \ + + ((expr) >> 16 & 1'b1) + ((expr) >> 17 & 1'b1) + ((expr) >> 18 & 1'b1) + ((expr) >> 19 & 1'b1) \ + + ((expr) >> 20 & 1'b1) + ((expr) >> 21 & 1'b1) + ((expr) >> 22 & 1'b1) + ((expr) >> 23 & 1'b1) \ + + ((expr) >> 24 & 1'b1) + ((expr) >> 25 & 1'b1) + ((expr) >> 26 & 1'b1) + ((expr) >> 27 & 1'b1) \ + + ((expr) >> 28 & 1'b1) + ((expr) >> 29 & 1'b1) + ((expr) >> 30 & 1'b1) + ((expr) >> 31 & 1'b1) \ + ) + +module top; + reg [31:0] data; + +`define TEST(idx, pattern, in_width, out_width) \ + localparam p``idx = pattern; \ + wire [in_width - 1:0] i``idx; \ + wire [out_width - 1:0] o``idx; \ + assign i``idx = data[0+:in_width]; \ + Example #(p``idx, in_width) e``idx(i``idx, o``idx); + + `TEST(1, 5'b10101, 5, 3) + `TEST(2, 10'b1110001111, 10, 7) + + integer i; + initial begin + data = 0; + for (i = 0; i < 100; i = i + 1) begin + data = 1664525 * data + 1013904223; + #1 $display("%b %b %b", data, o1, o2); + end + end +endmodule