Commit 4de585ec by Zachary Snow

initial parameter type conversion

parent 73e961d7
...@@ -27,6 +27,7 @@ import qualified Convert.NamedBlock ...@@ -27,6 +27,7 @@ import qualified Convert.NamedBlock
import qualified Convert.NestPI import qualified Convert.NestPI
import qualified Convert.Package import qualified Convert.Package
import qualified Convert.PackedArray import qualified Convert.PackedArray
import qualified Convert.ParamType
import qualified Convert.RemoveComments import qualified Convert.RemoveComments
import qualified Convert.Return import qualified Convert.Return
import qualified Convert.StarPort import qualified Convert.StarPort
...@@ -54,6 +55,7 @@ phases excludes = ...@@ -54,6 +55,7 @@ phases excludes =
, Convert.KWArgs.convert , Convert.KWArgs.convert
, Convert.Mux.convert , Convert.Mux.convert
, Convert.PackedArray.convert , Convert.PackedArray.convert
, Convert.ParamType.convert
, Convert.StarPort.convert , Convert.StarPort.convert
, Convert.StmtBlock.convert , Convert.StmtBlock.convert
, Convert.Stream.convert , Convert.Stream.convert
......
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `parameter type` in module instantiations
-}
module Convert.ParamType (convert) where
import Control.Monad.Writer
import Data.Either (isLeft)
import Data.Maybe (isJust, isNothing, fromJust)
import qualified Data.Map.Strict as Map
import Convert.Traverse
import Language.SystemVerilog.AST
type MaybeTypeMap = Map.Map Identifier (Maybe Type)
type Info = Map.Map Identifier ([Identifier], MaybeTypeMap)
type Instance = Map.Map Identifier Type
type Instances = [(Identifier, Instance)]
convert :: [AST] -> [AST]
convert files =
concatMap (map explodeDescription) files'
where
info = execWriter $
mapM (collectDescriptionsM collectDescriptionM) files
(files', instancesRaw) = runWriter $ mapM
(mapM $ traverseModuleItemsM $ mapInstance info) files
instances = reverse $ uniq [] instancesRaw
-- TODO: use the unique package
uniq curr [] = curr
uniq curr (x : xs) =
if elem x curr
then uniq curr xs
else uniq (x : curr) xs
explodeDescription :: Description -> [Description]
explodeDescription (part @ (Part _ _ _ name _ _)) =
if null theseInstances
then [part]
else map (rewriteModule part) theseInstances
where theseInstances = map snd $ filter ((== name) . fst) instances
explodeDescription other = [other]
-- TODO FIXME: Need to keep around the default instance and not perform
-- substitutions in it.
-- substitute in a particular instance's paramter types
rewriteModule :: Description -> Instance -> Description
rewriteModule part typeMap =
Part extern kw ml m' p items'
where
Part extern kw ml m p items = part
m' = renameModule info m typeMap
items' = map rewriteDecl items
rewriteDecl :: ModuleItem -> ModuleItem
rewriteDecl (MIPackageItem (Decl (ParamType Parameter x _))) =
MIPackageItem $ Typedef (typeMap Map.! x) x
rewriteDecl other = other
-- TODO FIXME: Typedef conversion must be made to handle
-- ParamTypes!
-----items' = map (traverseDecls rewriteDecl) items
-----rewriteDecl :: Decl -> Decl
-----rewriteDecl (ParamType Parameter x _) =
----- ParamType Localparam x (Just $ typeMap Map.! x)
-----rewriteDecl other = other
-- write down module parameter names and type parameters
collectDescriptionM :: Description -> Writer Info ()
collectDescriptionM (part @ (Part _ _ _ name _ _)) =
tell $ Map.singleton name (paramNames, maybeTypeMap)
where
params = execWriter $
collectModuleItemsM (collectDeclsM collectDeclM) part
paramNames = map fst params
maybeTypeMap = Map.fromList $
map (\(x, y) -> (x, fromJust y)) $
filter (isJust . snd) params
collectDeclM :: Decl -> Writer [(Identifier, Maybe (Maybe Type))] ()
collectDeclM (Param Parameter _ x _) = tell [(x, Nothing)]
collectDeclM (ParamType Parameter x v) = tell [(x, Just v )]
collectDeclM _ = return ()
collectDescriptionM _ = return ()
-- produces the default type mapping of a module, if there is one
defaultInstance :: MaybeTypeMap -> Maybe Instance
defaultInstance maybeTypeMap =
if any isNothing maybeTypeMap
then Nothing
else Just $ Map.map fromJust maybeTypeMap
-- generate a "unique" name for a particular module type instance
renameModule :: Info -> Identifier -> Instance -> Identifier
renameModule info m inst =
if defaultInstance maybeTypeMap == Just inst
then m -- default instances keep the original module name
else m ++ "_" ++ shortHash (m, inst)
where maybeTypeMap = snd $ info Map.! m
mapInstance :: Info -> ModuleItem -> Writer Instances ModuleItem
mapInstance info (orig @ (Instance m bindings x r p)) =
if Map.notMember m info then
return orig
else if any (isLeft . snd) bindings' then
error $ "param type resolution left type params: " ++ show orig
++ " converted to: " ++ show bindings'
else do
tell [(m, resolvedTypes)]
let m' = renameModule info m resolvedTypes
return $ Instance m' bindings' x r p
where
(paramNames, maybeTypeMap) = info Map.! m
-- attach names to unnamed parameters
bindingsNamed =
if all (== "") (map fst bindings) then
zip paramNames (map snd bindings)
else if any (== "") (map fst bindings) then
error $ "instance has a mix of named and unnamed params: "
++ show orig
else bindings
-- determine the types corresponding to each type parameter
bindingsMap = Map.fromList bindingsNamed
resolvedTypes = Map.mapWithKey resolveType maybeTypeMap
resolveType :: Identifier -> Maybe Type -> Type
resolveType paramName defaultType =
case (Map.lookup paramName bindingsMap, defaultType) of
(Nothing, Just t) -> t
(Nothing, Nothing) ->
error $ "instantiation " ++ show orig ++
" is missing a type parameter: " ++ paramName
(Just (Left t), _) -> t
(Just (Right e), _) ->
-- TODO: Some types could have been parsed as an expression
-- (i.e. aliases). Ideally we should have any such aliases
-- resolved before applying this conversion.
error $ "instantiation " ++ show orig ++ " has expr "
++ show e ++ " for type param: " ++ paramName
-- leave only the normal expression params behind
isParamType = flip Map.member maybeTypeMap
bindings' = filter (not . isParamType . fst) bindingsNamed
mapInstance _ other = return other
...@@ -71,6 +71,7 @@ executable sv2v ...@@ -71,6 +71,7 @@ executable sv2v
Convert.NestPI Convert.NestPI
Convert.Package Convert.Package
Convert.PackedArray Convert.PackedArray
Convert.ParamType
Convert.RemoveComments Convert.RemoveComments
Convert.Return Convert.Return
Convert.StarPort Convert.StarPort
......
module m_def #(
parameter type T = logic
);
T x = 0;
initial begin
$display("m_def %b %b %d", x, x+1, $bits(T));
end
endmodule
module m_nodef #(
parameter type T
);
T x = 0;
initial begin
$display("m_nodef %b %b %d", x, x+1, $bits(T));
end
endmodule
module n_nodef #(
parameter type T,
parameter type U
);
T x = 0;
U y = 1;
initial begin
$display("n_nodef %b %b %d", x, x+1, $bits(T));
$display("n_nodef %b %b %d", y, y+1, $bits(U));
end
endmodule
module n_def #(
parameter type T = logic,
parameter type U = logic
);
T x = 0;
U y = 1;
initial begin
$display("n_def %b %b %d", x, x+1, $bits(T));
$display("n_def %b %b %d", y, y+1, $bits(U));
end
endmodule
module n_tdef #(
parameter type T,
parameter type U = logic
);
T x = 0;
U y = 1;
initial begin
$display("n_tdef %b %b %d", x, x+1, $bits(T));
$display("n_tdef %b %b %d", y, y+1, $bits(U));
end
endmodule
// TODO Add support for parameters without default values.
module o_nodef #(
parameter a = 0,
parameter type T,
parameter type U,
parameter b = 0
);
T x = a;
U y = b;
initial begin
$display("n_nodef a=%d %b %b %d", a, x, x+1, $bits(T));
$display("n_nodef b=%d %b %b %d", b, y, y+1, $bits(U));
end
endmodule
module top; endmodule
// Top level modules appear to be generally instantiated in lexicographic order,
// but instances within a module do not. This silliness helps produce more
// consistent output.
module a_1; m_def x(); endmodule
module a_2; m_def #(logic [1:0]) x(); endmodule
module a_3; m_def #(.T(logic [1:0])) x(); endmodule
module b_1; m_nodef #(logic [1:0]) x(); endmodule
module b_2; m_nodef #(.T(logic [1:0])) x(); endmodule
module c_1; n_nodef #(logic [1:0], logic [2:0]) x(); endmodule
module c_2; n_nodef #(.T(logic [1:0]), .U(logic)) x(); endmodule
module c_3; n_nodef #(.U(logic), .T(logic [1:0])) x(); endmodule
module d_1; n_def #(logic [1:0], logic [2:0]) x(); endmodule
module d_2; n_def #(.T(logic [1:0])) x(); endmodule
module d_3; n_def #(.U(logic [1:0])) x(); endmodule
module d_4; n_def #(.U(logic), .T(logic [1:0])) x(); endmodule
module e_1; n_tdef #(logic [1:0], logic [2:0]) x(); endmodule
module e_2; n_tdef #(.T(logic [1:0]), .U(logic)) x(); endmodule
module e_3; n_tdef #(.U(logic), .T(logic [1:0])) x(); endmodule
module f_1; o_nodef #(1, logic [1:0], logic [2:0], 0) x(); endmodule
module f_2; o_nodef #(.T(logic [1:0]), .U(logic), .b(1), .a(0)) x(); endmodule
module f_3; o_nodef #(0, logic [1:0], logic [2:0], 1) x(); endmodule
module f_4; o_nodef #(.T(logic [1:0]), .U(logic), .b(0), .a(1)) x(); endmodule
module top;
initial begin
// generated by running a commercial simulator
$display("m_def 0 00000000000000000000000000000001 1");
$display("m_def 00 00000000000000000000000000000001 2");
$display("m_def 00 00000000000000000000000000000001 2");
$display("m_nodef 00 00000000000000000000000000000001 2");
$display("m_nodef 00 00000000000000000000000000000001 2");
$display("n_nodef 00 00000000000000000000000000000001 2");
$display("n_nodef 001 00000000000000000000000000000010 3");
$display("n_nodef 00 00000000000000000000000000000001 2");
$display("n_nodef 1 00000000000000000000000000000010 1");
$display("n_nodef 00 00000000000000000000000000000001 2");
$display("n_nodef 1 00000000000000000000000000000010 1");
$display("n_def 00 00000000000000000000000000000001 2");
$display("n_def 001 00000000000000000000000000000010 3");
$display("n_def 00 00000000000000000000000000000001 2");
$display("n_def 1 00000000000000000000000000000010 1");
$display("n_def 0 00000000000000000000000000000001 1");
$display("n_def 01 00000000000000000000000000000010 2");
$display("n_def 00 00000000000000000000000000000001 2");
$display("n_def 1 00000000000000000000000000000010 1");
$display("n_tdef 00 00000000000000000000000000000001 2");
$display("n_tdef 001 00000000000000000000000000000010 3");
$display("n_tdef 00 00000000000000000000000000000001 2");
$display("n_tdef 1 00000000000000000000000000000010 1");
$display("n_tdef 00 00000000000000000000000000000001 2");
$display("n_tdef 1 00000000000000000000000000000010 1");
$display("n_nodef a= 1 01 00000000000000000000000000000010 2");
$display("n_nodef b= 0 000 00000000000000000000000000000001 3");
$display("n_nodef a= 0 00 00000000000000000000000000000001 2");
$display("n_nodef b= 1 1 00000000000000000000000000000010 1");
$display("n_nodef a= 0 00 00000000000000000000000000000001 2");
$display("n_nodef b= 1 001 00000000000000000000000000000010 3");
$display("n_nodef a= 1 01 00000000000000000000000000000010 2");
$display("n_nodef b= 0 0 00000000000000000000000000000001 1");
end
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment