packages feed

sv2v-0.0.10: src/Language/SystemVerilog/AST/Stmt.hs

{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 - Initial Verilog AST Author: Tom Hawkins <tomahawkins@gmail.com>
 -
 - SystemVerilog procedural statements
 -}

module Language.SystemVerilog.AST.Stmt
    ( Stmt   (..)
    , Timing (..)
    , Event        (..)
    , EventExpr    (..)
    , Edge         (..)
    , CaseKW (..)
    , Case
    , ActionBlock  (..)
    , PropExpr     (..)
    , SeqMatchItem (..)
    , SeqExpr      (..)
    , AssertionItem
    , 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 s Null) = printf "%sif (%s)%s"         (showPad u) (show c) (showBranch s)
    show (If u c s1 s2 ) = printf "%sif (%s)%s\nelse%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)

showBlockedBranch :: Stmt -> String
showBlockedBranch stmt =
    showBranch $
    if isControl stmt
        then Block Seq "" [] [stmt]
        else stmt
    where
        isControl s = case s of
            If{} -> True
            For{} -> True
            While{} -> True
            RepeatL{} -> True
            DoWhile{} -> True
            Forever{} -> True
            Foreach{} -> True
            Timing _ subStmt -> isControl subStmt
            Block Seq "" [] [CommentStmt{}, subStmt] -> isControl subStmt
            _ -> False

showElseBranch :: Stmt -> String
showElseBranch stmt@If{} = ' ' : show stmt
showElseBranch stmt = 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

type AssertionItem = (Identifier, Assertion)

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"