sv2v/Language/SystemVerilog/AST.hs

350 lines
10 KiB
Haskell

module Language.SystemVerilog.AST
( Identifier
, Module (..)
, ModuleItem (..)
, Direction (..)
, Type (..)
, Stmt (..)
, LHS (..)
, Expr (..)
, UniOp (..)
, BinOp (..)
, Sense (..)
, Call (..)
, PortBinding
, Case
, Range
) where
import Data.Bits
import Data.List
import Data.Maybe
import Text.Printf
import Data.BitVec
type Identifier = String
-- Note: Verilog allows modules to be declared with either a simple list of
-- ports _identifiers_, or a list of port _declarations_. If only the
-- identifiers are used, they must be declared with a type and direction
-- (potentially separately!) within the module itself.
-- Note: This AST will allow for the representation of syntactically invalid
-- things, like input regs. We might want to have a function for doing some
-- basing invariant checks. I want to avoid making a full type-checker though,
-- as we should only be given valid SystemVerilog input files.
data Module
= Module Identifier [Identifier] [ModuleItem]
deriving Eq
instance Show Module where
showList modules _ = intercalate "\n" $ map show modules
show (Module name ports items) = unlines
[ "module " ++ name ++ portsStr ++ ";"
, indent $ unlines' $ map show items
, "endmodule" ]
where
portsStr =
if null ports
then ""
else indentedParenList ports
data Direction
= Input
| Output
| Inout
deriving Eq
instance Show Direction where
show Input = "input"
show Output = "output"
show Inout = "inout"
-- TODO: Support for arrays (multi-dimensional, too!)
data Type
= Reg (Maybe Range)
| Wire (Maybe Range)
deriving Eq
instance Show Type where
show (Reg r) = "reg " ++ (showRange r)
show (Wire r) = "wire " ++ (showRange r)
data ModuleItem
= Comment String
| Parameter (Maybe Range) Identifier Expr
| Localparam (Maybe Range) Identifier Expr
| PortDecl Direction (Maybe Range) Identifier
| LocalNet Type Identifier (Maybe Expr)
| Integer [Identifier]
| Initial Stmt
| Always (Maybe Sense) Stmt
| Assign LHS Expr
| Instance Identifier [PortBinding] Identifier [PortBinding]
deriving Eq
type PortBinding = (Identifier, Maybe Expr)
instance Show ModuleItem where
show thing = case thing of
Comment c -> "// " ++ c
Parameter r n e -> printf "parameter %s%s = %s;" (showRange r) n (showExprConst e)
Localparam r n e -> printf "localparam %s%s = %s;" (showRange r) n (showExprConst e)
PortDecl d r x -> printf "%s %s%s;" (show d) (showRange r) x
LocalNet t x v -> (show t) ++ " " ++ x ++ assignment ++ ";"
where
assignment =
if v == Nothing
then ""
else " = " ++ show (fromJust v)
Integer a -> printf "integer %s;" $ commas a
Initial a -> printf "initial\n%s" $ indent $ show a
Always Nothing b -> printf "always\n%s" $ indent $ show b
Always (Just a) b -> printf "always @(%s)\n%s" (show a) $ indent $ show b
Assign a b -> printf "assign %s = %s;" (show a) (show b)
Instance m params i ports
| null params -> printf "%s %s %s;" m i (showPorts show ports)
| otherwise -> printf "%s #%s %s %s;" m (showPorts showExprConst params) i (showPorts show ports)
where
showPorts :: (Expr -> String) -> [(Identifier, Maybe Expr)] -> String
showPorts s ports = indentedParenList [ if i == "" then show (fromJust arg) else printf ".%s(%s)" i (if isJust arg then s $ fromJust arg else "") | (i, arg) <- ports ]
showRange :: Maybe Range -> String
showRange Nothing = ""
showRange (Just (h, l)) = printf "[%s:%s] " (showExprConst h) (showExprConst l)
indent :: String -> String
indent a = '\t' : f a
where
f [] = []
f (x : xs)
| x == '\n' = "\n\t" ++ f xs
| otherwise = x : f xs
unlines' :: [String] -> String
unlines' = intercalate "\n"
data Expr
= String String
| Number BitVec
| ConstBool Bool
| Ident Identifier
| IdentRange Identifier Range
| IdentBit Identifier Expr
| Repeat Expr [Expr]
| Concat [Expr]
| ExprCall Call
| UniOp UniOp Expr
| BinOp BinOp Expr Expr
| Mux Expr Expr Expr
| Bit Expr Int
deriving Eq
data UniOp
= Not
| BWNot
| UAdd
| USub
| RedAnd
| RedNand
| RedOr
| RedNor
| RedXor
| RedXnor
deriving Eq
instance Show UniOp where
show Not = "!"
show BWNot = "~"
show UAdd = "+"
show USub = "-"
show RedAnd = "&"
show RedNand = "~&"
show RedOr = "|"
show RedNor = "~|"
show RedXor = "^"
show RedXnor = "~^"
data BinOp
= And
| Or
| BWAnd
| BWXor
| BWOr
| Mul
| Div
| Mod
| Add
| Sub
| ShiftL
| ShiftR
| Eq
| Ne
| Lt
| Le
| Gt
| Ge
deriving Eq
instance Show BinOp where
show a = case a of
And -> "&&"
Or -> "||"
BWAnd -> "&"
BWXor -> "^"
BWOr -> "|"
Mul -> "*"
Div -> "/"
Mod -> "%"
Add -> "+"
Sub -> "-"
ShiftL -> "<<"
ShiftR -> ">>"
Eq -> "=="
Ne -> "!="
Lt -> "<"
Le -> "<="
Gt -> ">"
Ge -> ">="
showBitVecDefault :: BitVec -> String
showBitVecDefault a = printf "%d'h%x" (width a) (value a)
showBitVecConst :: BitVec -> String
showBitVecConst a = show $ value a
instance Show Expr where show = showExpr showBitVecDefault
showExprConst :: Expr -> String
showExprConst = showExpr showBitVecConst
showExpr :: (BitVec -> String) -> Expr -> String
showExpr bv x = case x of
String a -> printf "\"%s\"" a
Number a -> bv a
ConstBool a -> printf "1'b%s" (if a then "1" else "0")
Ident a -> a
IdentBit a b -> printf "%s[%s]" a (showExprConst b)
IdentRange a (b, c) -> printf "%s[%s:%s]" a (showExprConst b) (showExprConst c)
Repeat a b -> printf "{%s {%s}}" (showExprConst a) (commas $ map s b)
Concat a -> printf "{%s}" (commas $ map show a)
ExprCall a -> show a
UniOp a b -> printf "(%s %s)" (show a) (s b)
BinOp a b c -> printf "(%s %s %s)" (s b) (show a) (s c)
Mux a b c -> printf "(%s ? %s : %s)" (s a) (s b) (s c)
Bit a b -> printf "(%s [%d])" (s a) b
where
s = showExpr bv
instance Num Expr where
(+) = BinOp Add
(-) = BinOp Sub
(*) = BinOp Mul
negate = UniOp USub
abs = undefined
signum = undefined
fromInteger = Number . fromInteger
instance Bits Expr where
(.&.) = BinOp BWAnd
(.|.) = BinOp BWOr
xor = BinOp BWXor
complement = UniOp BWNot
isSigned _ = False
shift = error "Not supported: shift"
rotate = error "Not supported: rotate"
bitSize = error "Not supported: bitSize"
bitSizeMaybe = error "Not supported: bitSizeMaybe"
testBit = error "Not supported: testBit"
bit = error "Not supported: bit"
popCount = error "Not supported: popCount"
instance Semigroup Expr where
(<>) = mappend
instance Monoid Expr where
mempty = 0
mappend a b = mconcat [a, b]
mconcat = Concat
data LHS
= LHS Identifier
| LHSBit Identifier Expr
| LHSRange Identifier Range
| LHSConcat [LHS]
deriving Eq
instance Show LHS where
show (LHS a ) = a
show (LHSBit a b ) = printf "%s[%s]" a (showExprConst b)
show (LHSRange a (b, c)) = printf "%s[%s:%s]" a (showExprConst b) (showExprConst c)
show (LHSConcat a ) = printf "{%s}" (commas $ map show a)
data Stmt
= Block (Maybe Identifier) [Stmt]
| StmtReg (Maybe Range) [(Identifier, Maybe Range)]
| StmtInteger [Identifier]
| Case Expr [Case] (Maybe Stmt)
| BlockingAssignment LHS Expr
| NonBlockingAssignment LHS Expr
| For (Identifier, Expr) Expr (Identifier, Expr) Stmt
| If Expr Stmt Stmt
| StmtCall Call
| Delay Expr Stmt
| Null
deriving Eq
commas :: [String] -> String
commas = intercalate ", "
instance Show Stmt where
show (Block Nothing b ) = printf "begin\n%s\nend" $ indent $ unlines' $ map show b
show (Block (Just a) b ) = printf "begin : %s\n%s\nend" a $ indent $ unlines' $ map show b
show (StmtReg a b ) = printf "reg %s%s;" (showRange a) (commas [ x ++ showRange r | (x, r) <- b ])
show (StmtInteger a ) = printf "integer %s;" $ commas a
show (Case a b Nothing ) = printf "case (%s)\n%s\nendcase" (show a) (indent $ unlines' $ map showCase b)
show (Case a b (Just c) ) = printf "case (%s)\n%s\n\tdefault:\n%s\nendcase" (show a) (indent $ unlines' $ map showCase b) (indent $ indent $ show c)
show (BlockingAssignment a b ) = printf "%s = %s;" (show a) (show b)
show (NonBlockingAssignment a b ) = printf "%s <= %s;" (show a) (show b)
show (For (a, b) c (d, e) f) = printf "for (%s = %s; %s; %s = %s)\n%s" a (show b) (show c) d (show e) $ indent $ show f
show (If a b Null ) = printf "if (%s)\n%s" (show a) (indent $ show b)
show (If a b c ) = printf "if (%s)\n%s\nelse\n%s" (show a) (indent $ show b) (indent $ show c)
show (StmtCall a ) = printf "%s;" (show a)
show (Delay a b ) = printf "#%s %s" (showExprConst a) (show b)
show (Null ) = ";"
type Case = ([Expr], Stmt)
showCase :: Case -> String
showCase (a, b) = printf "%s:\n%s" (commas $ map show a) (indent $ show b)
data Call = Call Identifier [Expr] deriving Eq
instance Show Call where
show (Call a b) = printf "%s(%s)" a (commas $ map show b)
data Sense
= Sense LHS
| SenseOr Sense Sense
| SensePosedge LHS
| SenseNegedge LHS
| SenseStar
deriving Eq
instance Show Sense where
show (Sense a ) = show a
show (SenseOr a b) = printf "%s or %s" (show a) (show b)
show (SensePosedge a ) = printf "posedge %s" (show a)
show (SenseNegedge a ) = printf "negedge %s" (show a)
show (SenseStar ) = "*"
type Range = (Expr, Expr)
indentedParenList :: [String] -> String
indentedParenList [] = "()"
indentedParenList [x] = "(" ++ x ++ ")"
indentedParenList l =
"(\n" ++ (indent $ intercalate ",\n" l) ++ "\n)"