Stmt.hs 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
{- 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 (..)
11 12 13
    , Event        (..)
    , EventExpr    (..)
    , Edge         (..)
14 15
    , CaseKW (..)
    , Case
16
    , ActionBlock  (..)
17
    , PropExpr     (..)
18
    , SeqMatchItem (..)
19 20
    , SeqExpr      (..)
    , Assertion    (..)
21 22
    , AssertionKind(..)
    , Deferral     (..)
23
    , PropertySpec (..)
24
    , ViolationCheck (..)
25
    , BlockKW (..)
26 27 28 29
    ) where

import Text.Printf (printf)

30
import Language.SystemVerilog.AST.ShowHelp (commas, indent, unlines', showPad, showBlock)
31
import Language.SystemVerilog.AST.Attr (Attr)
32
import Language.SystemVerilog.AST.Decl (Decl)
33
import Language.SystemVerilog.AST.Expr (Expr(Call, Ident, Nil), Args(..), Range, showRange, showAssignment)
34
import Language.SystemVerilog.AST.LHS (LHS)
35
import Language.SystemVerilog.AST.Op (AsgnOp(AsgnOpEq))
36 37 38
import Language.SystemVerilog.AST.Type (Identifier)

data Stmt
39
    = StmtAttr Attr Stmt
40
    | Block   BlockKW Identifier [Decl] [Stmt]
41
    | Case    ViolationCheck CaseKW Expr [Case]
42
    | For     [(LHS, Expr)] Expr [(LHS, AsgnOp, Expr)] Stmt
43
    | Asgn    AsgnOp (Maybe Timing) LHS Expr
44 45 46 47
    | While   Expr Stmt
    | RepeatL Expr Stmt
    | DoWhile Expr Stmt
    | Forever Stmt
48
    | Foreach Identifier [Identifier] Stmt
49
    | If      ViolationCheck Expr Stmt Stmt
50 51
    | Timing  Timing Stmt
    | Return  Expr
52
    | Subroutine Expr Args
53
    | Trigger Bool Identifier
54
    | Assertion Assertion
55
    | Force Bool LHS Expr
56
    | Wait Expr Stmt
57 58
    | Continue
    | Break
59
    | Null
60
    | CommentStmt String
61 62 63
    deriving Eq

instance Show Stmt where
64
    showList l _ = unlines' $ map show l
65
    show (StmtAttr attr stmt) = printf "%s\n%s" (show attr) (show stmt)
66 67
    show (Block kw name decls stmts) =
        printf "%s%s\n%s\n%s" (show kw) header body (blockEndToken kw)
68
        where
69
            header = if null name then "" else " : " ++ name
70
            body = showBlock decls stmts
71
    show (Case u kw e cs) =
72 73 74 75 76
        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
77
    show (For inits cond assigns stmt) =
78
        printf "for (%s; %s; %s)\n%s"
79 80
            (showInits inits)
            (show cond)
81 82 83
            (commas $ map showAssign assigns)
            (indent $ show stmt)
        where
84 85
            showInits :: [(LHS, Expr)] -> String
            showInits = commas . map showInit
86
                where showInit (l, e) = showAssign (l, AsgnOpEq, e)
87
    show (Subroutine e a) = printf "%s%s;" (show e) aStr
88
        where aStr = if a == Args [] [] then "" else show a
89 90
    show (Asgn  o t v e) = printf "%s %s %s%s;" (show v) (show o) tStr (show e)
        where tStr = maybe "" showPad t
91 92 93
    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)
94 95 96 97 98 99 100 101 102
    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
103 104 105 106 107 108 109
    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"
110
    show (Wait      e s) = printf "wait (%s)%s" (show e) (showShortBranch s)
111 112 113
    show (Continue     ) = "continue;"
    show (Break        ) = "break;"
    show (Null         ) = ";"
Zachary Snow committed
114
    show (CommentStmt c) = "// " ++ c
115

116 117 118
showAssign :: (LHS, AsgnOp, Expr) -> String
showAssign (l, op, e) = (showPad l) ++ (showPad op) ++ (show e)

Zachary Snow committed
119
showBranch :: Stmt -> String
120
showBranch (Block Seq "" [] stmts@[CommentStmt{}, _]) =
121
    '\n' : (indent $ show stmts)
122
showBranch block@Block{} = ' ' : show block
Zachary Snow committed
123 124
showBranch stmt = '\n' : (indent $ show stmt)

125 126
-- add a block around the true branch of an if statement when a dangling else is
-- possible to avoid any potential ambiguity downstream
127 128 129
showBlockedBranch :: Stmt -> String
showBlockedBranch stmt =
    showBranch $
130
    if danglingElse stmt
131 132
        then Block Seq "" [] [stmt]
        else stmt
133 134 135 136 137 138 139 140 141 142 143 144 145

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
146

Zachary Snow committed
147
showElseBranch :: Stmt -> String
148 149 150
showElseBranch Null = ""
showElseBranch stmt@If{} = "\nelse " ++ show stmt
showElseBranch stmt = "\nelse" ++ showBranch stmt
Zachary Snow committed
151 152

showShortBranch :: Stmt -> String
153
showShortBranch stmt@Asgn{} = ' ' : show stmt
Zachary Snow committed
154 155
showShortBranch stmt = showBranch stmt

156 157
showCase :: Case -> String
showCase (a, b) = printf "%s:%s" exprStr (showShortBranch b)
158 159 160 161
    where
        exprStr = case a of
            [] -> "default"
            _ -> commas $ map show a
Zachary Snow committed
162

163 164 165 166
data CaseKW
    = CaseN
    | CaseZ
    | CaseX
167
    | CaseInside
168 169 170 171 172 173
    deriving Eq

instance Show CaseKW where
    show CaseN = "case"
    show CaseZ = "casez"
    show CaseX = "casex"
174
    show CaseInside = "case"
175 176 177 178

type Case = ([Expr], Stmt)

data Timing
179
    = Event Event
180 181 182 183 184
    | Delay Expr
    | Cycle Expr
    deriving Eq

instance Show Timing where
185
    show (Event e) = printf  "@(%s)" (show e)
186 187 188
    show (Delay e) = printf  "#(%s)" (show e)
    show (Cycle e) = printf "##(%s)" (show e)

189 190 191
data Event
    = EventStar
    | EventExpr EventExpr
192 193
    deriving Eq

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
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  = ""
219 220

data ActionBlock
221
    = ActionBlock Stmt Stmt
222 223
    deriving Eq
instance Show ActionBlock where
224 225 226
    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)
227

228 229 230 231 232 233 234
data PropExpr
    = PropExpr SeqExpr
    | PropExprImpliesO  SeqExpr PropExpr
    | PropExprImpliesNO SeqExpr PropExpr
    | PropExprFollowsO  SeqExpr PropExpr
    | PropExprFollowsNO SeqExpr PropExpr
    | PropExprIff PropExpr PropExpr
235
    deriving Eq
236 237 238 239 240 241
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)
242 243 244 245 246 247 248 249
    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
250 251 252 253 254 255 256
data SeqExpr
    = SeqExpr Expr
    | SeqExprAnd        SeqExpr SeqExpr
    | SeqExprOr         SeqExpr SeqExpr
    | SeqExprIntersect  SeqExpr SeqExpr
    | SeqExprThroughout Expr    SeqExpr
    | SeqExprWithin     SeqExpr SeqExpr
257
    | SeqExprDelay (Maybe SeqExpr) Range SeqExpr
258 259 260 261 262 263 264 265 266
    | 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)
267
    show (SeqExprDelay   me r s) = printf "%s##%s %s" (maybe "" showPad me) (showCycleDelayRange r) (show s)
268
    show (SeqExprFirstMatch e a) = printf "first_match(%s, %s)" (show e) (commas $ map show a)
269

270 271 272 273 274
showCycleDelayRange :: Range -> String
showCycleDelayRange (Nil, e) = printf "(%s)" (show e)
showCycleDelayRange (e, Nil) = printf "[%s:$]" (show e)
showCycleDelayRange r = showRange r

275
data Assertion
276 277 278
    = Assert AssertionKind ActionBlock
    | Assume AssertionKind ActionBlock
    | Cover  AssertionKind Stmt
279 280
    deriving Eq
instance Show Assertion where
281 282 283 284 285 286 287 288 289 290 291
    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)
292

293 294 295 296 297 298 299 300 301
data Deferral
    = NotDeferred
    | ObservedDeferred
    | FinalDeferred
    deriving Eq
instance Show Deferral where
    show NotDeferred = ""
    show ObservedDeferred = "#0"
    show FinalDeferred = "final"
302 303

data PropertySpec
304
    = PropertySpec (Maybe EventExpr) Expr PropExpr
305 306
    deriving Eq
instance Show PropertySpec where
307 308
    show (PropertySpec mv e pe) =
        printf "%s%s\n\t%s" mvStr eStr (show pe)
309
        where
310
            mvStr = case mv of
311
                Nothing -> ""
312
                Just v -> printf "@(%s) " (show v)
Zachary Snow committed
313 314 315
            eStr = case e of
                Nil -> ""
                _ -> printf "disable iff (%s)" (show e)
316

317
data ViolationCheck
318 319 320
    = Unique
    | Unique0
    | Priority
321
    | NoCheck
322 323
    deriving Eq

324
instance Show ViolationCheck where
325 326 327
    show Unique   = "unique"
    show Unique0  = "unique0"
    show Priority = "priority"
328
    show NoCheck  = ""
329 330 331 332 333 334 335 336 337 338 339 340 341

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"