mirror of https://github.com/zachjs/sv2v.git
pivoted to general Verilog-2005 targeting
This commit is contained in:
parent
9f0857d68e
commit
d7f641b850
36
README.md
36
README.md
|
|
@ -1,24 +1,21 @@
|
|||
# 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
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
{- 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
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
{- 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]
|
||||
15
src/Job.hs
15
src/Job.hs
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue