conversion for implicitly variably sized parameters

This commit is contained in:
Zachary Snow 2020-08-12 21:47:24 -04:00
parent e4135bb896
commit e80db12422
9 changed files with 202 additions and 21 deletions

View File

@ -39,6 +39,7 @@ import qualified Convert.Simplify
import qualified Convert.SizeCast import qualified Convert.SizeCast
import qualified Convert.StarPort import qualified Convert.StarPort
import qualified Convert.Stream import qualified Convert.Stream
import qualified Convert.StringParam
import qualified Convert.Struct import qualified Convert.Struct
import qualified Convert.TFBlock import qualified Convert.TFBlock
import qualified Convert.Typedef import qualified Convert.Typedef
@ -89,6 +90,7 @@ phases excludes =
, Convert.ForDecl.convert , Convert.ForDecl.convert
, Convert.Jump.convert , Convert.Jump.convert
, Convert.Foreach.convert , Convert.Foreach.convert
, Convert.StringParam.convert
, selectExclude (Job.Interface, Convert.Interface.convert) , selectExclude (Job.Interface, Convert.Interface.convert)
, selectExclude (Job.Always , Convert.AlwaysKW.convert) , selectExclude (Job.Always , Convert.AlwaysKW.convert)
, selectExclude (Job.Succinct , Convert.RemoveComments.convert) , selectExclude (Job.Succinct , Convert.RemoveComments.convert)

View File

@ -0,0 +1,99 @@
{-# LANGUAGE PatternSynonyms #-}
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- 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

View File

@ -37,12 +37,12 @@ traverseDeclM decl = do
return $ case t' of return $ case t' of
UnpackedType t'' a' -> Variable d t'' ident a' e UnpackedType t'' a' -> Variable d t'' ident a' e
_ -> Variable d t' ident [] e _ -> Variable d t' ident [] e
Param _ t ident e -> do Param _ UnknownType ident String{} ->
t' <- if t == UnknownType insertElem ident UnknownType >> return decl'
then typeof e Param _ UnknownType ident e ->
else return t typeof e >>= insertElem ident >> return decl'
insertElem ident t' Param _ t ident _ ->
return decl' insertElem ident t >> return decl'
ParamType{} -> return decl' ParamType{} -> return decl'
CommentDecl{} -> return decl' CommentDecl{} -> return decl'
@ -137,25 +137,39 @@ typeof (BinOp ShiftL e _) = typeof e
typeof (BinOp ShiftR e _) = typeof e typeof (BinOp ShiftR e _) = typeof e
typeof (BinOp ShiftAL e _) = typeof e typeof (BinOp ShiftAL e _) = typeof e
typeof (BinOp ShiftAR e _) = typeof e typeof (BinOp ShiftAR e _) = typeof e
typeof (BinOp Add a b) = return $ largerSizeType a b typeof (BinOp Add a b) = largerSizeType a b
typeof (BinOp Sub a b) = return $ largerSizeType a b typeof (BinOp Sub a b) = largerSizeType a b
typeof (BinOp Mul a b) = return $ largerSizeType a b typeof (BinOp Mul a b) = largerSizeType a b
typeof (BinOp Div a b) = return $ largerSizeType a b typeof (BinOp Div a b) = largerSizeType a b
typeof (BinOp Mod a b) = return $ largerSizeType a b typeof (BinOp Mod a b) = largerSizeType a b
typeof (BinOp BitAnd a b) = return $ largerSizeType a b typeof (BinOp BitAnd a b) = largerSizeType a b
typeof (BinOp BitXor a b) = return $ largerSizeType a b typeof (BinOp BitXor a b) = largerSizeType a b
typeof (BinOp BitXnor a b) = return $ largerSizeType a b typeof (BinOp BitXnor a b) = largerSizeType a b
typeof (BinOp BitOr a b) = return $ largerSizeType a b typeof (BinOp BitOr a b) = largerSizeType a b
typeof (Mux _ a b) = return $ largerSizeType a b typeof (Mux _ a b) = largerSizeType a b
typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs
typeof (Repeat reps exprs) = return $ typeOfSize size typeof (Repeat reps exprs) = return $ typeOfSize size
where size = BinOp Mul reps (concatSize exprs) 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 typeof other = lookupTypeOf other
-- produces a type large enough to hold either expression -- produces a type large enough to hold either expression
largerSizeType :: Expr -> Expr -> Type largerSizeType :: Expr -> Expr -> Scoper Type Type
largerSizeType a b = typeOfSize $ largerSizeOf a b 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 -- returns the total size of concatenated list of expressions
concatSize :: [Expr] -> Expr concatSize :: [Expr] -> Expr

View File

@ -89,6 +89,7 @@ executable sv2v
Convert.SizeCast Convert.SizeCast
Convert.StarPort Convert.StarPort
Convert.Stream Convert.Stream
Convert.StringParam
Convert.Struct Convert.Struct
Convert.TFBlock Convert.TFBlock
Convert.Traverse Convert.Traverse

View File

@ -1,5 +1,5 @@
module top; module top;
parameter FOO = "some useful string"; localparam FOO = "some useful string";
localparam type T = type(FOO); localparam type T = type(FOO);
localparam T BAR = "some other useful string"; localparam T BAR = "some other useful string";
initial $display("'%s' '%s'", FOO, BAR); initial $display("'%s' '%s'", FOO, BAR);

View File

@ -1,5 +1,5 @@
module top; module top;
parameter FOO = "some useful string"; localparam FOO = "some useful string";
localparam BAR = "some other useful string"; localparam BAR = "some other useful string";
initial $display("'%s' '%s'", FOO, BAR); initial $display("'%s' '%s'", FOO, BAR);
endmodule endmodule

View File

@ -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

16
test/basic/string_param.v Normal file
View File

@ -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

View File

@ -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