2019-03-23 00:24:45 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
- Initial Verilog AST Author: Tom Hawkins <tomahawkins@gmail.com>
|
|
|
|
|
-
|
|
|
|
|
- This AST allows for the representation of many syntactically invalid things,
|
|
|
|
|
- like input regs or modport declarations inside a module. Representing only
|
|
|
|
|
- syntactically valid files would make working with the AST a nightmare. We
|
|
|
|
|
- have placed an emphasis on making the conversion procedures in this project
|
|
|
|
|
- more easier to write, interpret, and maintain.
|
|
|
|
|
-
|
|
|
|
|
- In the future, we may want to have a utility which performs some basic
|
|
|
|
|
- invariant checks. I want to avoid making a full type-checker though, as we
|
|
|
|
|
- should only be given valid SystemVerilog input files.
|
|
|
|
|
-}
|
|
|
|
|
|
2019-02-08 06:19:39 +01:00
|
|
|
module Language.SystemVerilog.AST
|
2019-03-23 00:24:45 +01:00
|
|
|
( Description(..)
|
|
|
|
|
, PackageItem(..)
|
|
|
|
|
, ModuleItem (..)
|
|
|
|
|
, Direction (..)
|
|
|
|
|
, GenItem (..)
|
|
|
|
|
, AlwaysKW (..)
|
|
|
|
|
, CaseKW (..)
|
|
|
|
|
, PartKW (..)
|
|
|
|
|
, Lifetime (..)
|
|
|
|
|
, NInputGateKW (..)
|
|
|
|
|
, NOutputGateKW (..)
|
|
|
|
|
, AST
|
|
|
|
|
, PortBinding
|
|
|
|
|
, ModportDecl
|
|
|
|
|
, GenCase
|
|
|
|
|
, simplify
|
|
|
|
|
, rangeSize
|
2019-03-25 18:29:35 +01:00
|
|
|
, module Decl
|
2019-03-23 00:24:45 +01:00
|
|
|
, module Expr
|
2019-03-25 18:29:35 +01:00
|
|
|
, module LHS
|
2019-03-23 00:24:45 +01:00
|
|
|
, module Op
|
2019-03-25 18:29:35 +01:00
|
|
|
, module Stmt
|
2019-03-23 00:24:45 +01:00
|
|
|
, module Type
|
|
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
import Data.List (intercalate)
|
|
|
|
|
import Data.Maybe (maybe, fromJust, isJust)
|
|
|
|
|
import Text.Printf (printf)
|
2019-03-06 06:51:09 +01:00
|
|
|
import Text.Read (readMaybe)
|
2019-02-08 05:49:12 +01:00
|
|
|
|
2019-03-25 18:29:35 +01:00
|
|
|
import Language.SystemVerilog.AST.Decl as Decl
|
2019-03-23 00:24:45 +01:00
|
|
|
import Language.SystemVerilog.AST.Expr as Expr
|
2019-03-25 18:29:35 +01:00
|
|
|
import Language.SystemVerilog.AST.LHS as LHS
|
2019-03-23 00:24:45 +01:00
|
|
|
import Language.SystemVerilog.AST.Op as Op
|
2019-03-25 18:29:35 +01:00
|
|
|
import Language.SystemVerilog.AST.Stmt as Stmt
|
2019-03-23 00:24:45 +01:00
|
|
|
import Language.SystemVerilog.AST.Type as Type
|
|
|
|
|
|
|
|
|
|
import Language.SystemVerilog.AST.ShowHelp
|
2019-02-08 05:49:12 +01:00
|
|
|
|
2019-02-09 23:35:31 +01:00
|
|
|
-- 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.
|
|
|
|
|
|
2019-02-18 09:59:17 +01:00
|
|
|
type AST = [Description]
|
|
|
|
|
|
2019-03-07 19:19:31 +01:00
|
|
|
data PackageItem
|
|
|
|
|
= Typedef Type Identifier
|
|
|
|
|
| Function (Maybe Lifetime) Type Identifier [Decl] [Stmt]
|
2019-03-07 19:58:20 +01:00
|
|
|
| Task (Maybe Lifetime) Identifier [Decl] [Stmt]
|
2019-03-07 19:19:31 +01:00
|
|
|
| Comment String
|
|
|
|
|
deriving Eq
|
|
|
|
|
|
|
|
|
|
instance Show PackageItem where
|
|
|
|
|
show (Typedef t x) = printf "typedef %s %s;" (show t) x
|
|
|
|
|
show (Function ml t x i b) =
|
|
|
|
|
printf "function %s%s%s;\n%s\n%s\nendfunction"
|
|
|
|
|
(showLifetime ml) (showPad t) x (indent $ show i)
|
|
|
|
|
(indent $ unlines' $ map show b)
|
2019-03-07 19:58:20 +01:00
|
|
|
show (Task ml x i b) =
|
|
|
|
|
printf "task %s%s;\n%s\n%s\nendtask"
|
|
|
|
|
(showLifetime ml) x (indent $ show i)
|
|
|
|
|
(indent $ unlines' $ map show b)
|
2019-03-07 19:19:31 +01:00
|
|
|
show (Comment c) = "// " ++ c
|
|
|
|
|
|
2019-02-18 09:59:17 +01:00
|
|
|
data Description
|
2019-03-04 08:58:00 +01:00
|
|
|
= Part PartKW Identifier [Identifier] [ModuleItem]
|
2019-03-07 19:19:31 +01:00
|
|
|
| PackageItem PackageItem
|
2019-03-18 10:00:23 +01:00
|
|
|
| Directive String
|
2019-02-09 23:35:31 +01:00
|
|
|
deriving Eq
|
2019-02-08 05:49:12 +01:00
|
|
|
|
2019-02-18 09:59:17 +01:00
|
|
|
instance Show Description where
|
|
|
|
|
showList descriptions _ = intercalate "\n" $ map show descriptions
|
2019-03-04 08:58:00 +01:00
|
|
|
show (Part kw name ports items) = unlines
|
|
|
|
|
[ (show kw) ++ " " ++ name ++ portsStr ++ ";"
|
2019-02-10 23:59:41 +01:00
|
|
|
, indent $ unlines' $ map show items
|
2019-03-04 08:58:00 +01:00
|
|
|
, "end" ++ (show kw) ]
|
2019-02-10 23:59:41 +01:00
|
|
|
where
|
|
|
|
|
portsStr =
|
|
|
|
|
if null ports
|
|
|
|
|
then ""
|
|
|
|
|
else indentedParenList ports
|
2019-03-07 19:19:31 +01:00
|
|
|
show (PackageItem i) = show i
|
2019-03-18 10:00:23 +01:00
|
|
|
show (Directive str) = str
|
2019-02-08 05:49:12 +01:00
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
data PartKW
|
|
|
|
|
= Module
|
|
|
|
|
| Interface
|
|
|
|
|
deriving Eq
|
|
|
|
|
|
|
|
|
|
instance Show PartKW where
|
|
|
|
|
show Module = "module"
|
|
|
|
|
show Interface = "interface"
|
|
|
|
|
|
2019-02-08 05:49:12 +01:00
|
|
|
data ModuleItem
|
2019-03-07 19:19:31 +01:00
|
|
|
= MIDecl Decl
|
2019-02-18 06:26:43 +01:00
|
|
|
| AlwaysC AlwaysKW Stmt
|
2019-02-08 05:49:12 +01:00
|
|
|
| Assign LHS Expr
|
2019-03-18 17:37:46 +01:00
|
|
|
| Defparam LHS Expr
|
2019-03-08 00:08:10 +01:00
|
|
|
| Instance Identifier [PortBinding] Identifier [PortBinding]
|
2019-02-18 00:33:20 +01:00
|
|
|
| Genvar Identifier
|
|
|
|
|
| Generate [GenItem]
|
2019-03-04 08:58:00 +01:00
|
|
|
| Modport Identifier [ModportDecl]
|
2019-03-05 02:58:09 +01:00
|
|
|
| Initial Stmt
|
2019-03-07 19:19:31 +01:00
|
|
|
| MIPackageItem PackageItem
|
2019-03-22 06:31:43 +01:00
|
|
|
| NInputGate NInputGateKW (Maybe Identifier) LHS [Expr]
|
|
|
|
|
| NOutputGate NOutputGateKW (Maybe Identifier) [LHS] Expr
|
2019-02-08 05:49:12 +01:00
|
|
|
deriving Eq
|
|
|
|
|
|
2019-02-18 06:26:43 +01:00
|
|
|
data AlwaysKW
|
|
|
|
|
= Always
|
|
|
|
|
| AlwaysComb
|
|
|
|
|
| AlwaysFF
|
|
|
|
|
| AlwaysLatch
|
|
|
|
|
deriving Eq
|
|
|
|
|
|
|
|
|
|
instance Show AlwaysKW where
|
|
|
|
|
show Always = "always"
|
|
|
|
|
show AlwaysComb = "always_comb"
|
|
|
|
|
show AlwaysFF = "always_ff"
|
|
|
|
|
show AlwaysLatch = "always_latch"
|
|
|
|
|
|
2019-02-08 05:49:12 +01:00
|
|
|
type PortBinding = (Identifier, Maybe Expr)
|
2019-03-04 08:58:00 +01:00
|
|
|
type ModportDecl = (Direction, Identifier, Maybe Expr)
|
2019-02-08 05:49:12 +01:00
|
|
|
|
|
|
|
|
instance Show ModuleItem where
|
2019-02-09 23:35:31 +01:00
|
|
|
show thing = case thing of
|
2019-02-24 09:06:40 +01:00
|
|
|
MIDecl nest -> show nest
|
2019-02-18 06:26:43 +01:00
|
|
|
AlwaysC k b -> printf "%s %s" (show k) (show b)
|
2019-02-08 05:49:12 +01:00
|
|
|
Assign a b -> printf "assign %s = %s;" (show a) (show b)
|
2019-03-18 17:37:46 +01:00
|
|
|
Defparam a b -> printf "defparam %s = %s;" (show a) (show b)
|
2019-02-08 05:49:12 +01:00
|
|
|
Instance m params i ports
|
2019-03-08 00:08:10 +01:00
|
|
|
| null params -> printf "%s %s%s;" m i (showPorts ports)
|
|
|
|
|
| otherwise -> printf "%s #%s %s%s;" m (showPorts params) i (showPorts ports)
|
2019-02-18 00:33:20 +01:00
|
|
|
Genvar x -> printf "genvar %s;" x
|
|
|
|
|
Generate b -> printf "generate\n%s\nendgenerate" (indent $ unlines' $ map show b)
|
2019-03-05 02:58:09 +01:00
|
|
|
Modport x l -> printf "modport %s(\n%s\n);" x (indent $ intercalate ",\n" $ map showModportDecl l)
|
|
|
|
|
Initial s -> printf "initial %s" (show s)
|
2019-03-07 19:19:31 +01:00
|
|
|
MIPackageItem i -> show i
|
2019-03-22 06:31:43 +01:00
|
|
|
NInputGate kw x lhs exprs -> printf "%s%s (%s, %s);" (show kw) (maybe "" (" " ++) x) (show lhs) (commas $ map show exprs)
|
|
|
|
|
NOutputGate kw x lhss expr -> printf "%s%s (%s, %s);" (show kw) (maybe "" (" " ++) x) (commas $ map show lhss) (show expr)
|
2019-02-08 05:49:12 +01:00
|
|
|
where
|
2019-02-24 09:06:40 +01:00
|
|
|
showPorts :: [PortBinding] -> String
|
|
|
|
|
showPorts ports = indentedParenList $ map showPort ports
|
|
|
|
|
showPort :: PortBinding -> String
|
2019-03-08 00:08:10 +01:00
|
|
|
showPort ("*", Nothing) = ".*"
|
2019-02-24 09:06:40 +01:00
|
|
|
showPort (i, arg) =
|
|
|
|
|
if i == ""
|
|
|
|
|
then show (fromJust arg)
|
|
|
|
|
else printf ".%s(%s)" i (if isJust arg then show $ fromJust arg else "")
|
2019-03-04 08:58:00 +01:00
|
|
|
showModportDecl :: ModportDecl -> String
|
|
|
|
|
showModportDecl (dir, ident, me) =
|
|
|
|
|
if me == Just (Ident ident)
|
|
|
|
|
then printf "%s %s" (show dir) ident
|
|
|
|
|
else printf "%s .%s(%s)" (show dir) ident (maybe "" show me)
|
2019-02-11 20:46:09 +01:00
|
|
|
|
2019-03-22 06:31:43 +01:00
|
|
|
data NInputGateKW
|
|
|
|
|
= GateAnd
|
|
|
|
|
| GateNand
|
|
|
|
|
| GateOr
|
|
|
|
|
| GateNor
|
|
|
|
|
| GateXor
|
|
|
|
|
| GateXnor
|
|
|
|
|
deriving Eq
|
|
|
|
|
data NOutputGateKW
|
|
|
|
|
= GateBuf
|
|
|
|
|
| GateNot
|
|
|
|
|
deriving Eq
|
|
|
|
|
|
|
|
|
|
instance Show NInputGateKW where
|
|
|
|
|
show GateAnd = "and"
|
|
|
|
|
show GateNand = "nand"
|
|
|
|
|
show GateOr = "or"
|
|
|
|
|
show GateNor = "nor"
|
|
|
|
|
show GateXor = "xor"
|
|
|
|
|
show GateXnor = "xnor"
|
|
|
|
|
instance Show NOutputGateKW where
|
|
|
|
|
show GateBuf = "buf"
|
|
|
|
|
show GateNot = "not"
|
|
|
|
|
|
2019-02-18 00:33:20 +01:00
|
|
|
type GenCase = ([Expr], GenItem)
|
|
|
|
|
|
|
|
|
|
data GenItem
|
|
|
|
|
= GenBlock (Maybe Identifier) [GenItem]
|
|
|
|
|
| GenCase Expr [GenCase] (Maybe GenItem)
|
2019-03-08 22:03:29 +01:00
|
|
|
| GenFor (Identifier, Expr) Expr (Identifier, AsgnOp, Expr) (Maybe Identifier) [GenItem]
|
2019-02-18 00:33:20 +01:00
|
|
|
| GenIf Expr GenItem GenItem
|
|
|
|
|
| GenNull
|
|
|
|
|
| GenModuleItem ModuleItem
|
|
|
|
|
deriving Eq
|
|
|
|
|
|
|
|
|
|
instance Show GenItem where
|
|
|
|
|
showList i _ = unlines' $ map show i
|
2019-02-24 09:06:40 +01:00
|
|
|
show (GenBlock Nothing i) = printf "begin\n%s\nend" (indent $ unlines' $ map show i)
|
2019-02-18 00:33:20 +01:00
|
|
|
show (GenBlock (Just x) i) = printf "begin : %s\n%s\nend" x (indent $ unlines' $ map show i)
|
|
|
|
|
show (GenCase e c Nothing ) = printf "case (%s)\n%s\nendcase" (show e) (indent $ unlines' $ map showCase c)
|
|
|
|
|
show (GenCase e c (Just d)) = printf "case (%s)\n%s\n\tdefault:\n%s\nendcase" (show e) (indent $ unlines' $ map showCase c) (indent $ indent $ show d)
|
2019-02-24 09:19:02 +01:00
|
|
|
show (GenIf e a GenNull) = printf "if (%s) %s" (show e) (show a)
|
|
|
|
|
show (GenIf e a b ) = printf "if (%s) %s\nelse %s" (show e) (show a) (show b)
|
2019-03-08 22:03:29 +01:00
|
|
|
show (GenFor (x1, e1) c (x2, o2, e2) mx is) = printf "for (%s = %s; %s; %s %s %s) %s" x1 (show e1) (show c) x2 (show o2) (show e2) (show $ GenBlock mx is)
|
2019-02-18 00:33:20 +01:00
|
|
|
show GenNull = ";"
|
|
|
|
|
show (GenModuleItem item) = show item
|
2019-03-04 20:25:38 +01:00
|
|
|
|
|
|
|
|
data Lifetime
|
|
|
|
|
= Static
|
|
|
|
|
| Automatic
|
|
|
|
|
deriving (Eq, Ord)
|
|
|
|
|
|
|
|
|
|
instance Show Lifetime where
|
|
|
|
|
show Static = "static"
|
|
|
|
|
show Automatic = "automatic"
|
|
|
|
|
|
|
|
|
|
showLifetime :: Maybe Lifetime -> String
|
|
|
|
|
showLifetime Nothing = ""
|
|
|
|
|
showLifetime (Just l) = show l ++ " "
|
2019-03-06 06:51:09 +01:00
|
|
|
|
|
|
|
|
-- basic expression simplfication utility to help us generate nicer code in the
|
|
|
|
|
-- common case of ranges like `[FOO-1:0]`
|
|
|
|
|
simplify :: Expr -> Expr
|
|
|
|
|
simplify (BinOp op e1 e2) =
|
|
|
|
|
case (op, e1', e2') of
|
|
|
|
|
(Add, Number "0", e) -> e
|
|
|
|
|
(Add, e, Number "0") -> e
|
|
|
|
|
(Sub, e, Number "0") -> e
|
|
|
|
|
(Add, BinOp Sub e (Number "1"), Number "1") -> e
|
|
|
|
|
(Add, e, BinOp Sub (Number "0") (Number "1")) -> BinOp Sub e (Number "1")
|
|
|
|
|
(_ , Number a, Number b) ->
|
|
|
|
|
case (op, readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of
|
|
|
|
|
(Add, Just x, Just y) -> Number $ show (x + y)
|
|
|
|
|
(Sub, Just x, Just y) -> Number $ show (x - y)
|
|
|
|
|
(Mul, Just x, Just y) -> Number $ show (x * y)
|
|
|
|
|
_ -> BinOp op e1' e2'
|
|
|
|
|
_ -> BinOp op e1' e2'
|
|
|
|
|
where
|
|
|
|
|
e1' = simplify e1
|
|
|
|
|
e2' = simplify e2
|
|
|
|
|
simplify other = other
|
|
|
|
|
|
|
|
|
|
rangeSize :: Range -> Expr
|
|
|
|
|
rangeSize (s, e) =
|
|
|
|
|
simplify $ BinOp Add (BinOp Sub s e) (Number "1")
|