From af4711a8cf8283e5839f77067345ca122cfda8a0 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 3 Sep 2019 23:36:29 -0400 Subject: [PATCH] preliminary stream conversion --- src/Convert.hs | 2 + src/Convert/AsgnOp.hs | 8 -- src/Convert/Bits.hs | 13 +- src/Convert/Stream.hs | 108 +++++++++++++++++ src/Convert/Traverse.hs | 3 +- src/Language/SystemVerilog/AST.hs | 9 ++ src/Language/SystemVerilog/AST/Expr.hs | 4 + sv2v.cabal | 1 + test/basic/stream.sv | 72 ++++++++++++ test/basic/stream.v | 157 +++++++++++++++++++++++++ 10 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 src/Convert/Stream.hs create mode 100644 test/basic/stream.sv create mode 100644 test/basic/stream.v diff --git a/src/Convert.hs b/src/Convert.hs index ba902c6..0e0ae57 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -31,6 +31,7 @@ import qualified Convert.RemoveComments import qualified Convert.Return import qualified Convert.StarPort import qualified Convert.StmtBlock +import qualified Convert.Stream import qualified Convert.Struct import qualified Convert.Typedef import qualified Convert.UnbasedUnsized @@ -56,6 +57,7 @@ phases excludes = , Convert.PackedArray.convert , Convert.StarPort.convert , Convert.StmtBlock.convert + , Convert.Stream.convert , Convert.Struct.convert , Convert.Typedef.convert , Convert.UnbasedUnsized.convert diff --git a/src/Convert/AsgnOp.hs b/src/Convert/AsgnOp.hs index 2275d90..36b24d0 100644 --- a/src/Convert/AsgnOp.hs +++ b/src/Convert/AsgnOp.hs @@ -35,11 +35,3 @@ convertStmt (For inits cc asgns stmt) = convertStmt (AsgnBlk (AsgnOp op) lhs expr) = AsgnBlk AsgnOpEq lhs (BinOp op (lhsToExpr lhs) expr) convertStmt other = other - -lhsToExpr :: LHS -> Expr -lhsToExpr (LHSIdent x ) = Ident x -lhsToExpr (LHSBit l e ) = Bit (lhsToExpr l) e -lhsToExpr (LHSRange l m r ) = Range (lhsToExpr l) m r -lhsToExpr (LHSDot l x ) = Dot (lhsToExpr l) x -lhsToExpr (LHSConcat ls) = Concat $ map lhsToExpr ls -lhsToExpr (LHSStream o e ls) = Stream o e $ map lhsToExpr ls diff --git a/src/Convert/Bits.hs b/src/Convert/Bits.hs index 1de13fc..0143ec8 100644 --- a/src/Convert/Bits.hs +++ b/src/Convert/Bits.hs @@ -17,6 +17,7 @@ module Convert.Bits (convert) where import Control.Monad.State +import Data.List (elemIndex) import qualified Data.Map.Strict as Map import Convert.Traverse @@ -37,7 +38,9 @@ traverseDeclM decl = do Variable _ t ident a _ -> modify $ Map.insert ident (t, a) Parameter t ident _ -> modify $ Map.insert ident (t, []) Localparam t ident _ -> modify $ Map.insert ident (t, []) - return decl + item <- traverseModuleItemM (MIPackageItem $ Decl decl) + let MIPackageItem (Decl decl') = item + return decl' traverseModuleItemM :: ModuleItem -> State Info ModuleItem traverseModuleItemM item = traverseExprsM traverseExprM item @@ -46,7 +49,8 @@ traverseStmtM :: Stmt -> State Info Stmt traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt traverseExprM :: Expr -> State Info Expr -traverseExprM = traverseNestedExprsM $ stately convertExpr +traverseExprM = traverseNestedExprsM $ stately converter + where converter a b = simplify $ (traverseNestedExprs (convertExpr a) b) -- simplify a bits expression given scoped type information convertExpr :: Info -> Expr -> Expr @@ -83,6 +87,11 @@ convertExpr info (Bits (Right e)) = Just (t, rs) -> convertExpr info $ Bits $ Left t' where t' = popRange t rs + Stream _ _ exprs -> convertExpr info $ Bits $ Right $ Concat exprs + Number n -> + case elemIndex '\'' n of + Nothing -> Bits $ Right $ Number n + Just idx -> Number $ take idx n _ -> Bits $ Right e convertExpr _ other = other diff --git a/src/Convert/Stream.hs b/src/Convert/Stream.hs new file mode 100644 index 0000000..ff5b14e --- /dev/null +++ b/src/Convert/Stream.hs @@ -0,0 +1,108 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion of streaming concatenations. + -} + +module Convert.Stream (convert) where + +import Control.Monad.Writer +import Data.Hashable (hash) + +import Convert.Traverse +import Language.SystemVerilog.AST + +type Funcs = [ModuleItem] + +convert :: [AST] -> [AST] +convert = map $ traverseDescriptions convertDescription + +convertDescription :: Description -> Description +convertDescription (description @ (Part _ _ _ _ _ _)) = + Part extern kw lifetime name ports (items ++ funcs) + where + (description', funcSet) = + runWriter $ traverseModuleItemsM (traverseStmtsM traverseStmtM) description + Part extern kw lifetime name ports items = description' + funcs = reverse $ uniq [] funcSet + uniq curr [] = curr + uniq curr (x : xs) = + if elem x curr + then uniq curr xs + else uniq (x : curr) xs +convertDescription other = other + +streamerBlock :: Expr -> Expr -> (LHS -> Expr -> Stmt) -> LHS -> Expr -> Stmt +streamerBlock chunk size asgn output input = + Block Nothing + [ Variable Local t inp [] $ Just input + , Variable Local t out [] Nothing + , Variable Local (IntegerAtom TInteger Unspecified) idx [] Nothing + , Variable Local (IntegerAtom TInteger Unspecified) bas [] Nothing + ] + [ For inits cmp incr stmt + , AsgnBlk AsgnOpEq (LHSIdent bas) (Ident idx) + , For inits cmp2 incr2 stmt2 + , asgn output (Ident out) + ] + where + lo = Number "0" + hi = BinOp Sub size (Number "1") + t = IntegerVector TLogic Unspecified [(hi, lo)] + name = streamerBlockName chunk size + inp = name ++ "_inp" + out = name ++ "_out" + idx = name ++ "_idx" + bas = name ++ "_bas" + -- main chunk loop + inits = [Right (LHSIdent idx, lo)] + cmp = Just $ BinOp Le (Ident idx) (BinOp Sub hi chunk) + incr = [(LHSIdent idx, AsgnOp Add, chunk)] + lhs = LHSRange (LHSIdent out) IndexedMinus (BinOp Sub hi (Ident idx), chunk) + expr = Range (Ident inp) IndexedPlus (Ident idx, chunk) + stmt = AsgnBlk AsgnOpEq lhs expr + -- final chunk loop + cmp2 = Just $ BinOp Lt (Ident idx) (BinOp Sub size (Ident bas)) + incr2 = [(LHSIdent idx, AsgnOp Add, Number "1")] + lhs2 = LHSBit (LHSIdent out) (Ident idx) + expr2 = Bit (Ident inp) (BinOp Add (Ident idx) (Ident bas)) + stmt2 = AsgnBlk AsgnOpEq lhs2 expr2 + +streamerBlockName :: Expr -> Expr -> Identifier +streamerBlockName chunk size = + "_sv2v_strm_" ++ take 5 str + where + val = hash $ show (chunk, size) + str = tail $ show val + +traverseStmtM :: Stmt -> Writer Funcs Stmt +traverseStmtM (AsgnBlk op lhs expr) = + traverseAsgnM (lhs, expr) (AsgnBlk op) +traverseStmtM (Asgn mt lhs expr) = + traverseAsgnM (lhs, expr) (Asgn mt) +traverseStmtM other = return other + +traverseAsgnM :: (LHS, Expr) -> (LHS -> Expr -> Stmt) -> Writer Funcs Stmt +traverseAsgnM (lhs, Stream StreamR _ exprs) constructor = + return $ constructor lhs expr + where + expr = Concat $ exprs ++ [Repeat delta [Number "1'b0"]] + size = Bits $ Right $ lhsToExpr lhs + exprSize = Bits $ Right (Concat exprs) + delta = BinOp Sub size exprSize +traverseAsgnM (LHSStream StreamR _ lhss, expr) constructor = + return $ constructor (LHSConcat lhss) expr +traverseAsgnM (lhs, Stream StreamL chunk exprs) constructor = do + return $ streamerBlock chunk size constructor lhs expr + where + expr = Concat $ Repeat delta [Number "1'b0"] : exprs + size = Bits $ Right $ lhsToExpr lhs + exprSize = Bits $ Right (Concat exprs) + delta = BinOp Sub size exprSize +traverseAsgnM (LHSStream StreamL chunk lhss, expr) constructor = do + return $ streamerBlock chunk size constructor lhs expr + where + lhs = LHSConcat lhss + size = Bits $ Right expr +traverseAsgnM (lhs, expr) constructor = + return $ constructor lhs expr diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index a6cdc55..4d90153 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -543,6 +543,7 @@ traverseExprsM' strat exprMapper = moduleItemMapper expr' <- exprMapper expr return $ Assign delay' lhs' expr' moduleItemMapper (MIPackageItem (Function lifetime ret f decls stmts)) = do + ret' <- typeMapper ret decls' <- if strat == IncludeTFs then mapM declMapper decls @@ -551,7 +552,7 @@ traverseExprsM' strat exprMapper = moduleItemMapper if strat == IncludeTFs then mapM stmtMapper stmts else return stmts - return $ MIPackageItem $ Function lifetime ret f decls' stmts' + return $ MIPackageItem $ Function lifetime ret' f decls' stmts' moduleItemMapper (MIPackageItem (Task lifetime f decls stmts)) = do decls' <- if strat == IncludeTFs diff --git a/src/Language/SystemVerilog/AST.hs b/src/Language/SystemVerilog/AST.hs index 54a401c..46864f3 100644 --- a/src/Language/SystemVerilog/AST.hs +++ b/src/Language/SystemVerilog/AST.hs @@ -26,6 +26,7 @@ module Language.SystemVerilog.AST , module Stmt , module Type , exprToLHS + , lhsToExpr ) where import Language.SystemVerilog.AST.Attr as Attr @@ -59,3 +60,11 @@ exprToLHS (Stream o e ls) = do ls' <- mapM exprToLHS ls Just $ LHSStream o e ls' exprToLHS _ = Nothing + +lhsToExpr :: LHS -> Expr +lhsToExpr (LHSIdent x ) = Ident x +lhsToExpr (LHSBit l e ) = Bit (lhsToExpr l) e +lhsToExpr (LHSRange l m r ) = Range (lhsToExpr l) m r +lhsToExpr (LHSDot l x ) = Dot (lhsToExpr l) x +lhsToExpr (LHSConcat ls) = Concat $ map lhsToExpr ls +lhsToExpr (LHSStream o e ls) = Stream o e $ map lhsToExpr ls diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index c91cf17..529e718 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -123,6 +123,10 @@ readNumber n = -- basic expression simplfication utility to help us generate nicer code in the -- common case of ranges like `[FOO-1:0]` simplify :: Expr -> Expr +simplify (Repeat (Number "0") _) = Concat [] +simplify (Concat [expr]) = expr +simplify (Concat exprs) = + Concat $ filter (/= Concat []) exprs simplify (orig @ (Call Nothing "$clog2" (Args [Just (Number n)] []))) = case readNumber n of Nothing -> orig diff --git a/sv2v.cabal b/sv2v.cabal index 89bb68d..cc6cdee 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -75,6 +75,7 @@ executable sv2v Convert.Return Convert.StarPort Convert.StmtBlock + Convert.Stream Convert.Struct Convert.Typedef Convert.Traverse diff --git a/test/basic/stream.sv b/test/basic/stream.sv new file mode 100644 index 0000000..a856003 --- /dev/null +++ b/test/basic/stream.sv @@ -0,0 +1,72 @@ +module top; + + // Derived from: https://www.amiq.com/consulting/2017/05/29/how-to-pack-data-using-systemverilog-streaming-operators/ + typedef struct packed { + logic [3:0] addr; + logic [3:0] data; + } packet_t; + initial begin + // TODO: Add support for implicitly sized arrays. + logic [1:0] array[4] = '{ 2'b10, 2'b01, 2'b11, 2'b00 }; + packet_t packet = {<<4{ {<<2{array}} }}; + $display("packet addr = %b", packet.addr); + $display("packet data = %b", packet.data); + end + + initial begin + logic [23:0] temp; + + temp = {>>byte{24'h060708}}; + $display("%h", temp); + temp = {<>bit{24'h060708}}; + $display("%h", temp); + temp = {<>7{24'h060708}}; + $display("%h", temp); + temp = {<<7{24'h060708}}; + $display("%h", temp); + + temp = {>>7{20'h60708}}; + $display("%h", temp); + // TODO: Handle this edge case. + //temp = {<<7{20'h60708}}; + //$display("%h", temp); + + temp = {>>7{16'h0708}}; + $display("%h", temp); + temp = {<<7{16'h0708}}; + $display("%h", temp); + end + + task test_unpack; + input logic [23:0] in; + logic [0:0] i; + logic [1:0] j; + logic [2:0] k; + logic [5:0] l; + logic [11:0] m; + {>>byte{i, j, k, l, m}} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {<>bit{i, j, k, l, m}} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {<>7{i, j, k, l, m}} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {<<7{i, j, k, l, m}} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + endtask + initial begin + test_unpack(24'h060708); + test_unpack(24'hC02375); + test_unpack(24'h12E3B8); + end + +endmodule diff --git a/test/basic/stream.v b/test/basic/stream.v new file mode 100644 index 0000000..8efa9a8 --- /dev/null +++ b/test/basic/stream.v @@ -0,0 +1,157 @@ +module top; + + initial begin + $display("packet addr = %b", {2'b01, 2'b10}); + $display("packet data = %b", {2'b00, 2'b11}); + end + + function automatic [23:0] pack_r_8_24; + input [23:0] in; + integer i; + for (i = 0; i < 24; i = i + 8) begin + pack_r_8_24[i+:8] = in[i+:8]; + end + endfunction + function automatic [23:0] pack_l_8_24; + input [23:0] in; + integer i; + for (i = 0; i < 24; i = i + 8) begin + pack_l_8_24[i+:8] = in[23-i-:8]; + end + endfunction + function automatic [23:0] pack_r_1_24; + input [23:0] in; + integer i; + for (i = 0; i < 24; i = i + 1) begin + pack_r_1_24[i] = in[i]; + end + endfunction + function automatic [23:0] pack_l_1_24; + input [23:0] in; + integer i; + for (i = 0; i < 24; i = i + 1) begin + pack_l_1_24[i] = in[23-i]; + end + endfunction + function automatic [23:0] pack_r_7_24; + input [23:0] in; + integer i; + begin + for (i = 0; i < 24; i = i + 7) begin + pack_r_7_24[i+:7] = in[i+:7]; + end + for (i = 0; i < 24; i = i + 7) begin + pack_r_7_24[i+:7] = in[i+:7]; + end + end + endfunction + function automatic [23:0] pack_l_7_24; + input [23:0] in; + integer i; + integer e; + begin + for (i = 0; i < 24; i = i + 7) begin + pack_l_7_24[23-i-:7] = in[i+:7]; + end + e = i - 7; + for (i = 0; i < 24-e; i = i + 1) begin + pack_l_7_24[i] = in[i+e]; + end + end + endfunction + initial begin + $display("%h", pack_r_8_24(24'h060708)); + $display("%h", pack_l_8_24(24'h060708)); + + $display("%h", pack_r_1_24(24'h060708)); + $display("%h", pack_l_1_24(24'h060708)); + + $display("%h", pack_r_7_24(24'h060708)); + $display("%h", pack_l_7_24(24'h060708)); + + $display("%h", pack_r_7_24(24'h607080)); + //$display("%h", pack_l_7_24(24'h0c0708)); + + $display("%h", pack_r_7_24(24'h070800)); + $display("%h", pack_l_7_24(24'h000708)); + end + + task test_unpack; + input [23:0] in; + reg [0:0] i; + reg [1:0] j; + reg [2:0] k; + reg [5:0] l; + reg [11:0] m; + begin + {i, j, k, l, m} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {i, j, k, l, m} = pack_l_8_24(in); + $display("%b %b %b %b %b", i, j, k, l, m); + {i, j, k, l, m} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {i, j, k, l, m} = pack_l_1_24(in); + $display("%b %b %b %b %b", i, j, k, l, m); + {i, j, k, l, m} = in; + $display("%b %b %b %b %b", i, j, k, l, m); + {i, j, k, l, m} = pack_l_7_24(in); + $display("%b %b %b %b %b", i, j, k, l, m); + end + endtask + initial begin + test_unpack(24'h060708); + test_unpack(24'hC02375); + test_unpack(24'h12E3B8); + end + +endmodule + +// 060708 +// 080706 +// 060708 +// 10e060 +// 060708 +// 1038c0 +// + +// 1 11 010 110001 100000000110 +// 0 00 110 111000 010001100000 +// +// 00 001 100000 011100001000 +// 0 00 010 000000 011100000110 +// 0 00 001 100000 011100001000 +// 0 00 100 001110 000001100000 +// 0 00 001 100000 011100001000 +// 0 00 110 000100 000010000011 +// 1 10 000 000010 001101110101 +// 0 11 101 010010 001111000000 +// 1 10 000 000010 001101110101 +// 1 01 011 101100 010000000011 +// 1 10 000 000010 001101110101 +// 0 00 110 111000 010001100000 +// 0 00 100 101110 001110111000 +// 1 01 110 001110 001100010010 +// 0 00 100 101110 001110111000 +// 0 00 111 011100 011101001000 +// 0 00 100 101110 001110111000 +// 0 00 111 011101 110000001001 + + +// 0 00 001 100000 011100001000 +// 0 00 010 000000 011100000110 +// 0 00 001 100000 011100001000 +// 0 00 100 001110 000001100000 +// 0 00 001 100000 011100001000 +// 0 00 100 000011 100011000000 +// 1 10 000 000010 001101110101 +// 0 11 101 010010 001111000000 +// 1 10 000 000010 001101110101 +// 1 01 011 101100 010000000011 +// 1 10 000 000010 001101110101 +// 1 11 010 110001 100000000110 +// 0 00 100 101110 001110111000 +// 1 01 110 001110 001100010010 +// 0 00 100 101110 001110111000 +// 0 00 111 011100 011101001000 +// 0 00 100 101110 001110111000 +// 0 11 100 010001 111001011000