Commit d7f641b8 by Zachary Snow

pivoted to general Verilog-2005 targeting

parent 9f0857d6
# sv2v: SystemVerilog to Verilog
sv2v is a tool for converting synthesizable SystemVerilog into Verilog that is
synthesizable by tools with more limited feature sets. This project is primarily
focused on converting SystemVerilog into the subset of Verilog supported by
[Yosys]. However, sv2v also has support for targeting the [limited subset of
Verilog] supported by [VTR]. In the long term, we hope for sv2v to be more
configurable and extensible so that it can be used with new and different
toolchains and as Verilog support evolves.
sv2v is a tool for converting [SystemVerilog] into [Verilog-2005], with an
emphasis on supporting synthesizable SystemVerilog features. This project was
originally developed to target [Yosys], and so allows for disabling the
conversion of those [SystemVerilog features which Yosys supports].
[SystemVerilog]: http://ecee.colorado.edu/~mathys/ecen2350/IntelSoftware/pdf/IEEE_Std1800-2017_8299595.pdf
[Verilog-2005]: https://www.eg.bucknell.edu/~csci320/2016-fall/wp-content/uploads/2015/08/verilog-std-1364-2005.pdf
[Yosys]: http://www.clifford.at/yosys/
[limited subset of Verilog]: https://docs.verilogtorouting.org/en/latest/odin/#verilog-synthesizable-keyword-support
[VTR]: https://github.com/verilog-to-routing/vtr-verilog-to-routing
[SystemVerilog features which Yosys supports]: https://github.com/YosysHQ/yosys#supported-features-from-systemverilog
## Installation
### Pre-built binaries
Given the infamy of Haskell's build system, we aim to release pre-built binaries
and installation files. This has not been done yet.
We plan on releasing pre-built binaries in the near future.
### Building from source
......@@ -33,7 +30,8 @@ stack setup
make
```
This creates the executable at `./bin/sv2v`
This creates the executable at `./bin/sv2v` You can install the binary by
running `stack install`.
## Usage
......@@ -45,18 +43,14 @@ path/to/file.sv` will output the converted file to `stdout`.
sv2v [OPTIONS] [FILE]
Common flags:
-t --target=TARGET target sythesizer (yosys, vtr; defaults to yosys)
-e --exclude=CONV conversion to exclude (always, interface, logic); can
be specified multiple times
-? --help Display help message
-V --version Print version information
--numeric-version Print just the version number
```
## VTR Support
sv2v can target VTR by specifying `--target=vtr` on the command line. Note that
VTR does not support `generate` blocks, and this tool is not capable of
converting those at this time.
## SystemVerilog Parser/AST
This project contains a basic preprocessor, lexer, parser, and abstract syntax
......@@ -65,7 +59,7 @@ strict, and the AST allows for the representation of syntactically (and
semantically) invalid Verilog. The goal is to be more general in the
representation to enable more standardized and straightforward conversion
procedures. This could be extended into an independent and more fully-featured
parer if there is significant interest.
parser if there is significant interest.
## License
......
......@@ -7,18 +7,16 @@
module Convert (convert) where
import Language.SystemVerilog.AST
import Job (Target(..))
import qualified Job (Exclude(..))
import qualified Convert.AlwaysKW
import qualified Convert.AsgnOp
import qualified Convert.CaseKW
import qualified Convert.Enum
import qualified Convert.FuncRet
import qualified Convert.Interface
import qualified Convert.Logic
import qualified Convert.PackedArray
import qualified Convert.Return
import qualified Convert.SplitPortDecl
import qualified Convert.StarPort
import qualified Convert.Struct
import qualified Convert.Typedef
......@@ -26,10 +24,10 @@ import qualified Convert.Unique
type Phase = AST -> AST
phases :: Target -> [Phase]
phases YOSYS =
phases :: [Job.Exclude] -> [Phase]
phases excludes =
extras ++
[ Convert.AsgnOp.convert
, Convert.Interface.convert
, Convert.FuncRet.convert
, Convert.Enum.convert
, Convert.PackedArray.convert
......@@ -39,23 +37,27 @@ phases YOSYS =
, Convert.Typedef.convert
, Convert.Unique.convert
]
phases VTR =
(phases YOSYS) ++
[ Convert.AlwaysKW.convert
, Convert.CaseKW.convert
, Convert.Logic.convert
, Convert.SplitPortDecl.convert
]
where
availableExcludes =
[ (Job.Interface, Convert.Interface.convert)
, (Job.Logic , Convert.Logic.convert)
, (Job.Always , Convert.AlwaysKW.convert) ]
extras = map selectExclude availableExcludes
selectExclude :: (Job.Exclude, Phase) -> Phase
selectExclude (exclude, phase) =
if elem exclude excludes
then id
else phase
run :: Target -> Phase
run target = foldr (.) id $ phases target
run :: [Job.Exclude] -> Phase
run excludes = foldr (.) id $ phases excludes
convert :: Target -> Phase
convert target = convert'
convert :: [Job.Exclude] -> Phase
convert excludes = convert'
where
convert' :: Phase
convert' descriptions =
if descriptions == descriptions'
then descriptions
else convert' descriptions'
where descriptions' = run target descriptions
where descriptions' = run excludes descriptions
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `casez` and `casex`
-
- Note that this conversion does not completely replicate the behavior of
- `casex` and `casez` in cases where that case expression itself (rather than
- just the case item patterns) contains wildcard values. This is apparently
- rarely ever intentionally done.
-}
module Convert.CaseKW (convert) where
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: AST -> AST
convert = traverseDescriptions (traverseModuleItems (traverseStmts convertStmt))
-- Conversions:
-- `casez` -> `case` with wildcards (?, z) expanded
-- `casex` -> `case` with wildcards (?, z, x) expanded
-- to be either 0 or 1
wildcards :: CaseKW -> [Char]
wildcards CaseN = [] -- CaseN == `case`
wildcards CaseZ = ['?', 'z', 'Z']
wildcards CaseX = ['?', 'z', 'Z', 'x', 'X']
possibilities :: [Char]
possibilities = ['0', '1']
explodeBy :: [Char] -> String -> [String]
explodeBy _ "" = [""]
explodeBy wilds (x : xs) =
(map (:) chars) <*> (explodeBy wilds xs)
where chars = if elem x wilds then possibilities else [x]
expandExpr :: [Char] -> Expr -> [Expr]
expandExpr wilds (Number s) = map Number $ explodeBy wilds s
expandExpr [] other = [other]
-- TODO: Hopefully they only give us constant expressions...
-- TODO: We could be given a constant identifier...
expandExpr _ other = error $ "CaseKW conversion encountered case that was not a number, which is dubious..." ++ (show other)
-- Note that we don't have to convert the statements within the cases, as the
-- conversion template takes care of that for us.
convertStmt :: Stmt -> Stmt
convertStmt (Case u kw expr cases def) =
Case u CaseN expr cases' def
where
wilds = wildcards kw
cases' = map convertCase cases
convertCase :: Case -> Case
convertCase (exprs, stmt) = (exprs', stmt)
where exprs' = concat $ map (expandExpr wilds) exprs
convertStmt other = other
......@@ -13,8 +13,11 @@ convert :: AST -> AST
convert = traverseDescriptions $ traverseModuleItems convertFunction
convertFunction :: ModuleItem -> ModuleItem
convertFunction (MIPackageItem (Function ml (Reg r) f decls stmts)) =
MIPackageItem $ Function ml (Implicit r) f decls stmts
convertFunction (MIPackageItem (Function ml (Logic r) f decls stmts)) =
MIPackageItem $ Function ml (Implicit r) f decls stmts
convertFunction (MIPackageItem (Function ml t f decls stmts)) =
MIPackageItem $ Function ml t' f decls stmts
where
t' = case t of
Reg rs -> Implicit rs
Logic rs -> Implicit rs
_ -> t
convertFunction other = other
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for splitting up complex port declarations. VTR doesn't support:
- `input wire foo;` but does suport: `input foo; wire foo;`.
-}
module Convert.SplitPortDecl (convert) where
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: AST -> AST
convert = traverseDescriptions convertDescription
convertDescription :: Description -> Description
convertDescription (Part kw name ports items) =
Part kw name ports (concat $ map splitPortDecl items)
convertDescription other = other
splitPortDecl :: ModuleItem -> [ModuleItem]
splitPortDecl (orig @ (MIDecl (Variable Local _ _ _ _))) = [orig]
splitPortDecl (orig @ (MIDecl (Variable _ (Implicit _) _ _ _))) = [orig]
splitPortDecl (MIDecl (Variable d t x a me)) =
[ MIDecl $ Variable d (Implicit r) x a Nothing
, MIDecl $ Variable Local t x a me ]
where (_, r) = typeRanges t
splitPortDecl other = [other]
......@@ -9,18 +9,23 @@ module Job where
import System.Console.CmdArgs
data Target = VTR | YOSYS
deriving (Show, Typeable, Data)
data Exclude
= Always
| Interface
| Logic
deriving (Show, Typeable, Data, Eq)
data Job = Job
{ target :: Target
{ exclude :: [Exclude]
, file :: FilePath
} deriving (Show, Typeable, Data)
defaultJob :: Job
defaultJob = Job
{ target = YOSYS &= typ "TARGET"
&= help "target sythesizer (yosys, vtr; defaults to yosys)"
{ exclude = [] &= typ "CONV"
&= help
("conversion to exclude (always, interface, logic)"
++ "; can be specified multiple times")
, file = def &= args &= typFile
}
&= program "sv2v"
......
......@@ -7,7 +7,7 @@
import System.IO
import System.Exit
import Job (readJob, file, target)
import Job (readJob, file, exclude)
import Convert (convert)
import Language.SystemVerilog.Parser
......@@ -19,7 +19,7 @@ main = do
content <- readFile filePath
let ast = parseFile [] filePath content
-- convert the file
let ast' = convert (target job) ast
let ast' = convert (exclude job) ast
-- print the converted file out
hPrint stdout ast'
exitSuccess
......@@ -42,14 +42,12 @@ executable sv2v
Convert
Convert.AlwaysKW
Convert.AsgnOp
Convert.CaseKW
Convert.Enum
Convert.FuncRet
Convert.Interface
Convert.Logic
Convert.PackedArray
Convert.Return
Convert.SplitPortDecl
Convert.StarPort
Convert.Struct
Convert.Typedef
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment