{- sv2v - Author: Zachary Snow - Initial Verilog AST Author: Tom Hawkins - - SystemVerilog procedural statements -} module Language.SystemVerilog.AST.Stmt ( Stmt (..) , Timing (..) , Event (..) , EventExpr (..) , Edge (..) , CaseKW (..) , Case , ActionBlock (..) , PropExpr (..) , SeqMatchItem (..) , SeqExpr (..) , Assertion (..) , AssertionKind(..) , Deferral (..) , PropertySpec (..) , ViolationCheck (..) , BlockKW (..) ) where import Text.Printf (printf) import Language.SystemVerilog.AST.ShowHelp (commas, indent, unlines', showPad, showBlock) import Language.SystemVerilog.AST.Attr (Attr) import Language.SystemVerilog.AST.Decl (Decl) import Language.SystemVerilog.AST.Expr (Expr(Call, Ident, Nil), Args(..), Range, showRange, showAssignment) import Language.SystemVerilog.AST.LHS (LHS) import Language.SystemVerilog.AST.Op (AsgnOp(AsgnOpEq)) import Language.SystemVerilog.AST.Type (Identifier) data Stmt = StmtAttr Attr Stmt | Block BlockKW Identifier [Decl] [Stmt] | Case ViolationCheck CaseKW Expr [Case] | For [(LHS, Expr)] Expr [(LHS, AsgnOp, Expr)] Stmt | Asgn AsgnOp (Maybe Timing) LHS Expr | While Expr Stmt | RepeatL Expr Stmt | DoWhile Expr Stmt | Forever Stmt | Foreach Identifier [Identifier] Stmt | If ViolationCheck Expr Stmt Stmt | Timing Timing Stmt | Return Expr | Subroutine Expr Args | Trigger Bool Identifier | Assertion Assertion | Force Bool LHS Expr | Continue | Break | Null | CommentStmt String deriving Eq instance Show Stmt where showList l _ = unlines' $ map show l show (StmtAttr attr stmt) = printf "%s\n%s" (show attr) (show stmt) show (Block kw name decls stmts) = printf "%s%s\n%s\n%s" (show kw) header body (blockEndToken kw) where header = if null name then "" else " : " ++ name body = showBlock decls stmts show (Case u kw e cs) = printf "%s%s (%s)%s\n%s\nendcase" (showPad u) (show kw) (show e) insideStr bodyStr where insideStr = if kw == CaseInside then " inside" else "" bodyStr = indent $ unlines' $ map showCase cs show (For inits cond assigns stmt) = printf "for (%s; %s; %s)\n%s" (showInits inits) (show cond) (commas $ map showAssign assigns) (indent $ show stmt) where showInits :: [(LHS, Expr)] -> String showInits = commas . map showInit where showInit (l, e) = showAssign (l, AsgnOpEq, e) show (Subroutine e a) = printf "%s%s;" (show e) aStr where aStr = if a == Args [] [] then "" else show a show (Asgn o t v e) = printf "%s %s %s%s;" (show v) (show o) tStr (show e) where tStr = maybe "" showPad t show (If u c s1 s2) = -- print the then branch inside a block to avoid dangling else issues printf "%sif (%s)%s%s" (showPad u) (show c) (showBlockedBranch s1) (showElseBranch s2) show (While e s) = printf "while (%s) %s" (show e) (show s) show (RepeatL e s) = printf "repeat (%s) %s" (show e) (show s) show (DoWhile e s) = printf "do %s while (%s);" (show s) (show e) show (Forever s) = printf "forever %s" (show s) show (Foreach x i s) = printf "foreach (%s [ %s ]) %s" x (commas i) (show s) show (Return e ) = printf "return %s;" (show e) show (Timing t s) = printf "%s%s" (show t) (showShortBranch s) show (Trigger b x) = printf "->%s %s;" (if b then "" else ">") x show (Assertion a) = show a show (Force kw l e) = printf "%s %s%s;" kwStr (show l) (showAssignment e) where kwStr = case (kw, e /= Nil) of (True , True ) -> "force" (True , False) -> "release" (False, True ) -> "assign" (False, False) -> "deassign" show (Continue ) = "continue;" show (Break ) = "break;" show (Null ) = ";" show (CommentStmt c) = "// " ++ c showAssign :: (LHS, AsgnOp, Expr) -> String showAssign (l, op, e) = (showPad l) ++ (showPad op) ++ (show e) showBranch :: Stmt -> String showBranch (Block Seq "" [] stmts@[CommentStmt{}, _]) = '\n' : (indent $ show stmts) showBranch block@Block{} = ' ' : show block showBranch stmt = '\n' : (indent $ show stmt) -- add a block around the true branch of an if statement when a dangling else is -- possible to avoid any potential ambiguity downstream showBlockedBranch :: Stmt -> String showBlockedBranch stmt = showBranch $ if danglingElse stmt then Block Seq "" [] [stmt] else stmt danglingElse :: Stmt -> Bool danglingElse s = case s of If{} -> True For _ _ _ subStmt -> danglingElse subStmt While _ subStmt -> danglingElse subStmt RepeatL _ subStmt -> danglingElse subStmt Forever subStmt -> danglingElse subStmt Foreach _ _ subStmt -> danglingElse subStmt Timing _ subStmt -> danglingElse subStmt StmtAttr _ subStmt -> danglingElse subStmt Block Seq "" [] [CommentStmt{}, subStmt] -> danglingElse subStmt _ -> False showElseBranch :: Stmt -> String showElseBranch Null = "" showElseBranch stmt@If{} = "\nelse " ++ show stmt showElseBranch stmt = "\nelse" ++ showBranch stmt showShortBranch :: Stmt -> String showShortBranch stmt@Asgn{} = ' ' : show stmt showShortBranch stmt = showBranch stmt showCase :: Case -> String showCase (a, b) = printf "%s:%s" exprStr (showShortBranch b) where exprStr = case a of [] -> "default" _ -> commas $ map show a data CaseKW = CaseN | CaseZ | CaseX | CaseInside deriving Eq instance Show CaseKW where show CaseN = "case" show CaseZ = "casez" show CaseX = "casex" show CaseInside = "case" type Case = ([Expr], Stmt) data Timing = Event Event | Delay Expr | Cycle Expr deriving Eq instance Show Timing where show (Event e) = printf "@(%s)" (show e) show (Delay e) = printf "#(%s)" (show e) show (Cycle e) = printf "##(%s)" (show e) data Event = EventStar | EventExpr EventExpr deriving Eq instance Show Event where show EventStar = "*" show (EventExpr e) = show e data EventExpr = EventExprEdge Edge Expr | EventExprOr EventExpr EventExpr deriving Eq instance Show EventExpr where show (EventExprEdge g e) = printf "%s%s" (showPad g) (show e) show (EventExprOr a b) = printf "%s or %s" (show a) (show b) data Edge = Posedge | Negedge | Edge | NoEdge deriving Eq instance Show Edge where show Posedge = "posedge" show Negedge = "negedge" show Edge = "edge" show NoEdge = "" data ActionBlock = ActionBlock Stmt Stmt deriving Eq instance Show ActionBlock where show (ActionBlock s Null) = printf " %s" (show s) show (ActionBlock Null s) = printf " else %s" (show s) show (ActionBlock s1 s2) = printf " %s else %s" (show s1) (show s2) data PropExpr = PropExpr SeqExpr | PropExprImpliesO SeqExpr PropExpr | PropExprImpliesNO SeqExpr PropExpr | PropExprFollowsO SeqExpr PropExpr | PropExprFollowsNO SeqExpr PropExpr | PropExprIff PropExpr PropExpr deriving Eq instance Show PropExpr where show (PropExpr se) = show se show (PropExprImpliesO a b) = printf "(%s |-> %s)" (show a) (show b) show (PropExprImpliesNO a b) = printf "(%s |=> %s)" (show a) (show b) show (PropExprFollowsO a b) = printf "(%s #-# %s)" (show a) (show b) show (PropExprFollowsNO a b) = printf "(%s #=# %s)" (show a) (show b) show (PropExprIff a b) = printf "(%s iff %s)" (show a) (show b) data SeqMatchItem = SeqMatchAsgn (LHS, AsgnOp, Expr) | SeqMatchCall Identifier Args deriving Eq instance Show SeqMatchItem where show (SeqMatchAsgn asgn) = showAssign asgn show (SeqMatchCall ident args) = show $ Call (Ident ident) args data SeqExpr = SeqExpr Expr | SeqExprAnd SeqExpr SeqExpr | SeqExprOr SeqExpr SeqExpr | SeqExprIntersect SeqExpr SeqExpr | SeqExprThroughout Expr SeqExpr | SeqExprWithin SeqExpr SeqExpr | SeqExprDelay (Maybe SeqExpr) Range SeqExpr | SeqExprFirstMatch SeqExpr [SeqMatchItem] deriving Eq instance Show SeqExpr where show (SeqExpr a ) = show a show (SeqExprAnd a b) = printf "(%s %s %s)" (show a) "and" (show b) show (SeqExprOr a b) = printf "(%s %s %s)" (show a) "or" (show b) show (SeqExprIntersect a b) = printf "(%s %s %s)" (show a) "intersect" (show b) show (SeqExprThroughout a b) = printf "(%s %s %s)" (show a) "throughout" (show b) show (SeqExprWithin a b) = printf "(%s %s %s)" (show a) "within" (show b) show (SeqExprDelay me r s) = printf "%s##%s %s" (maybe "" showPad me) (showCycleDelayRange r) (show s) show (SeqExprFirstMatch e a) = printf "first_match(%s, %s)" (show e) (commas $ map show a) showCycleDelayRange :: Range -> String showCycleDelayRange (Nil, e) = printf "(%s)" (show e) showCycleDelayRange (e, Nil) = printf "[%s:$]" (show e) showCycleDelayRange r = showRange r data Assertion = Assert AssertionKind ActionBlock | Assume AssertionKind ActionBlock | Cover AssertionKind Stmt deriving Eq instance Show Assertion where show (Assert k a) = printf "assert %s%s" (show k) (show a) show (Assume k a) = printf "assume %s%s" (show k) (show a) show (Cover k a) = printf "cover %s%s" (show k) (show a) data AssertionKind = Concurrent PropertySpec | Immediate Deferral Expr deriving Eq instance Show AssertionKind where show (Concurrent e) = printf "property (%s\n)" (show e) show (Immediate d e) = printf "%s(%s)" (showPad d) (show e) data Deferral = NotDeferred | ObservedDeferred | FinalDeferred deriving Eq instance Show Deferral where show NotDeferred = "" show ObservedDeferred = "#0" show FinalDeferred = "final" data PropertySpec = PropertySpec (Maybe EventExpr) Expr PropExpr deriving Eq instance Show PropertySpec where show (PropertySpec mv e pe) = printf "%s%s\n\t%s" mvStr eStr (show pe) where mvStr = case mv of Nothing -> "" Just v -> printf "@(%s) " (show v) eStr = case e of Nil -> "" _ -> printf "disable iff (%s)" (show e) data ViolationCheck = Unique | Unique0 | Priority | NoCheck deriving Eq instance Show ViolationCheck where show Unique = "unique" show Unique0 = "unique0" show Priority = "priority" show NoCheck = "" data BlockKW = Seq | Par deriving Eq instance Show BlockKW where show Seq = "begin" show Par = "fork" blockEndToken :: BlockKW -> Identifier blockEndToken Seq = "end" blockEndToken Par = "join"