packages feed

clashilator (empty) → 0.1.0

raw patch · 12 files changed

+756/−0 lines, 12 filesdep +Cabaldep +aesondep +base

Dependencies added: Cabal, aeson, base, clash-ghc, clash-lib, containers, filepath, ghc, lens, optparse-applicative, shake, stache, text, unordered-containers

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2020 Gergő Érdi (http://gergo.erdi.hu/)++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,64 @@+# Clashilator: Automated Clash - Verilator integration++This package provides Cabal `Setup.hs` functionality to automatically+integrate Verilator into your Clash project.++* Detailed introduction: https://unsafeperform.io/blog/2020-05-07-integrating_verilator_and_clash_via_cabal/+* Example project: https://github.com/gergoerdi/clashilator-example++## Usage++Suppose you have a Clash circuit that you want to simulate using+Verilator, and then write Haskell code to interact with that+simulation. If your Clash code looks like this:++```+topEntity+    :: "CLK" ::: Clock System+    -> "FOO" ::: Signal System Bit+    -> "BAR" ::: Signal System (Unsigned 4)+    -> ("BAZ" ::: Signal System (Unsigned 10), "QUUX" ::: Signal System Bit)+topEntity = ...+makeTopEntity 'topEntity+```++and you put this in your Cabal file:++```+custom-setup+  setup-depends: clashilator++executable MySim+  main-is: simulator.hs+  x-clashilator-clock: CLK+  x-clashilator-top-is: MyCircuit+```++then in your `simulator.hs`, you can import the "virtual" module+`Clash.Clashilator.FFI` which provides the following definitions:++```+data INPUT = INPUT+    { iFOO :: Bit+    , iBAR :: Word8+    }+    deriving (Show)+instance Storable INPUT++data OUTPUT = OUTPUT+    { oBAZ :: Word16+    , oQUUX :: Bit+    }+    deriving (Show)+instance Storable OUTPUT++data Sim++simInit     :: IO (Ptr Sim)+simShutdown :: Ptr Sim -> IO ()+simStep     :: Ptr Sim -> Ptr INPUT -> Ptr OUTPUT -> IO ()+```++Note that input and output buses are represented as the smallest+possible `Word` type, to improve marshalling cost when crossing the+Haskell-C++ barrier.
+ clashilator.cabal view
@@ -0,0 +1,85 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.4.+--+-- see: https://github.com/sol/hpack+--+-- hash: 2a7cd4d926c1778ae4d73a15781b9025b1afc514077e52df91e0841f7543c1f8++name:           clashilator+version:        0.1.0+synopsis:       Automated Clash to Verilator bridge+description:    Code generator and @Setup.hs@ hooks to generate a Verilator simulation and access it from Clash+category:       Hardware, Development+homepage:       https://github.com/gergoerdi/clashilator#readme+bug-reports:    https://github.com/gergoerdi/clashilator/issues+author:         Gergő Érdi+maintainer:     gergo@erdi.hu+license:        MIT+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    template/Makefile.mustache+    template/Interface.h.mustache+    template/Impl.cpp.mustache+    template/Impl.h.mustache+    template/FFI.hsc.mustache++source-repository head+  type: git+  location: https://github.com/gergoerdi/clashilator++library+  exposed-modules:+      Clash.Clashilator+      Clash.Clashilator.Setup+  other-modules:+      Clash.Clashilator.Cabal+      Paths_clashilator+  hs-source-dirs:+      src+  ghc-options: -Wunused-imports+  build-depends:+      Cabal >=3.2.1.0+    , aeson+    , base >=4.14 && <5+    , clash-ghc >=1.4.2 && <1.5+    , clash-lib >=1.4.2 && <1.5+    , containers+    , filepath+    , ghc+    , lens+    , optparse-applicative+    , shake+    , stache+    , text+    , unordered-containers+  default-language: Haskell2010++executable clashilator+  main-is: main.hs+  other-modules:+      Clash.Clashilator+      Clash.Clashilator.Cabal+      Clash.Clashilator.Setup+      Paths_clashilator+  hs-source-dirs:+      src+  ghc-options: -Wunused-imports+  build-depends:+      Cabal >=3.2.1.0+    , aeson+    , base >=4.14 && <5+    , clash-ghc >=1.4.2 && <1.5+    , clash-lib >=1.4.2 && <1.5+    , containers+    , filepath+    , ghc+    , lens+    , optparse-applicative+    , shake+    , stache+    , text+    , unordered-containers+  default-language: Haskell2010
+ src/Clash/Clashilator.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE RecordWildCards, OverloadedStrings, ViewPatterns #-}+{-# LANGUAGE TemplateHaskell #-}+module Clash.Clashilator (generateFiles) where++import Clash.Driver.Manifest++import Control.Monad (forM_)+import Data.List (partition)++import System.FilePath++import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import Development.Shake (writeFileChanged)++import Text.Mustache+import qualified Text.Mustache.Compile.TH as TH+import Data.Aeson hiding (Options)+import qualified Data.HashMap.Strict as H++data Port = Port Text Int+    deriving Show++data FFIType+    = FFIBit+    | FFIU8+    | FFIU16+    | FFIU32+    | FFIU64++ffiType :: Int -> FFIType+ffiType 1 = FFIBit+ffiType n+  | n <= 8 = FFIU8+  | n <= 16 = FFIU16+  | n <= 32 = FFIU32+  | n <= 64 = FFIU64+  | otherwise = error $ unwords ["ffiType:", show n]++cType :: FFIType -> Text+cType FFIBit = "bit"+cType FFIU8 = "uint8_t"+cType FFIU16 = "uint16_t"+cType FFIU32 = "uint32_t"+cType FFIU64 = "uint64_t"++hsType :: FFIType -> Text+hsType FFIBit = "Bit"+hsType FFIU8 = "Word8"+hsType FFIU16 = "Word16"+hsType FFIU32 = "Word32"+hsType FFIU64 = "Word64"++cName :: Text -> Text+cName = id++hsName :: Text -> Text -> Text+hsName tag s = tag <> s++getClockAndInPorts :: Maybe Text -> [ManifestPort] -> (Maybe Text, [Port])+getClockAndInPorts clkName inPorts = (clk, [ Port mpName mpWidth | ManifestPort{..} <- inPorts' ])+  where+    (map mpName -> clks, inPorts') = partition mpIsClock inPorts+    clk = case (clkName, clks) of+        (Just clkName, clks) | clkName `elem` clks -> Just clkName+        (Nothing, [clk]) -> Just clk+        _ -> Nothing++portInfo :: Text -> Port -> Value+portInfo tag (Port name width) = object+    [ "cName" .= cName name+    , "cType" .= cType ty+    , "hsName" .= hsName tag name+    , "hsType" .= hsType ty+    ]+  where+    ty = ffiType width++manifestInfo :: Maybe String -> FilePath -> FilePath -> Maybe Text -> Manifest -> Value+manifestInfo cflags srcDir outputDir clkName Manifest{..} = object+    [ "inPorts"      .= (markEnds $ map (portInfo "i") ins)+    , "outPorts"     .= (markEnds $ map (portInfo "o") outs)+    , "clock"        .= fmap (\clock -> object ["cName" .= cName clock]) clock+    , "hdlDir"       .= srcDir+    , "srcs"         .= [ object ["verilogPath" .= TL.pack (srcDir </> T.unpack component <.> "v")]+                        | component <- componentNames+                        ]+    , "verilator"    .= fmap (\cflags -> object [ "cflags" .= TL.strip (TL.pack cflags) ]) cflags+    , "outputDir"    .= outputDir+    ]+  where+    (clock, ins) = getClockAndInPorts clkName inPorts+    outs = [ Port mpName mpWidth | ManifestPort{..} <- outPorts ]++markEnds :: [Value] -> [Value]+markEnds [] = []+markEnds (v:vs) = markStart v : vs+  where+    markStart (Object o) = Object $ o <> H.fromList [ "first" .= True ]++templates =+    [ ("src/Interface.h", $(TH.compileMustacheFile "template/Interface.h.mustache"))+    , ("src/Impl.cpp", $(TH.compileMustacheFile "template/Impl.cpp.mustache"))+    , ("src/Impl.h", $(TH.compileMustacheFile "template/Impl.h.mustache"))+    , ("Makefile",  $(TH.compileMustacheFile "template/Makefile.mustache"))+    , ("src/Clash/Clashilator/FFI.hsc", $(TH.compileMustacheFile "template/FFI.hsc.mustache"))+    ]++generateFiles :: Maybe String -> FilePath -> FilePath -> Maybe Text -> Manifest -> IO ()+generateFiles cflags inputDir outputDir clkName manifest = do+    let vals = manifestInfo cflags inputDir outputDir clkName manifest+    forM_ templates $ \(fname, template) -> do+        writeFileChanged (outputDir </> fname) $ TL.unpack $ renderMustache template vals
+ src/Clash/Clashilator/Cabal.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE GADTs, RankNTypes #-}+module Clash.Clashilator.Cabal+    ( BuildHook+    , ComponentHook+    , withComponentHook+    , packageDBs+    ) where++import Distribution.Simple+import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.BuildTarget+import Distribution.Simple.Setup+import Distribution.Simple.Register+import Distribution.Types.ComponentRequestedSpec++import Distribution.Types.Lens+import Control.Lens hiding ((<.>))+import Control.Monad (unless, when)++type BuildHook = PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()+type ComponentHook = LocalBuildInfo -> BuildFlags -> Component -> IO BuildInfo++withComponentHook :: ComponentHook -> BuildHook -> BuildHook+withComponentHook componentHook nextBuildHook pkg lbi userHooks flags = do+    let reqSpec = componentEnabledSpec lbi+    withAllComponentsInBuildOrder pkg lbi $ \c clbi -> do+        flags <- return $ restrictBuildFlags pkg c flags+        when (componentEnabled reqSpec c && not (null $ buildArgs flags)) $ do+            bi <- componentHook lbi flags c+            pkg <- return $ updateBuildInfo c bi pkg+            nextBuildHook pkg lbi userHooks flags++packageDBs :: LocalBuildInfo -> BuildFlags -> IO [PackageDB]+packageDBs lbi flags = do+    pkgdb0 <- do+        let dbPath = internalPackageDBPath lbi distPref+        existsAlready <- doesPackageDBExist dbPath+        unless existsAlready $ do+            createPackageDB verbosity (compiler lbi) (withPrograms lbi) False dbPath+        return $ SpecificPackageDB dbPath+    pkgdbs <- absolutePackageDBPaths $ withPackageDB lbi++    return $ pkgdb0 : pkgdbs+  where+    verbosity = fromFlag (buildVerbosity flags)+    distPref  = fromFlag (buildDistPref flags)++data NamedComponent where+    NamedComponent+        :: (HasBuildInfo a)+        => Traversal' PackageDescription a+        -> (a -> ComponentName)+        -> NamedComponent++namedComponents :: [NamedComponent]+namedComponents =+    [ NamedComponent (library . each)      (CLibName . view libName)+    , NamedComponent (subLibraries . each) (CLibName . view libName)+    , NamedComponent (executables . each)  (CExeName . view exeName)+    , NamedComponent (testSuites . each)   (CTestName . view testName)+    , NamedComponent (benchmarks . each)   (CBenchName . view benchmarkName)+    ]++itagged :: Traversal' s a -> (a -> b) -> IndexedTraversal' b s a+itagged l f = reindexed f (l . selfIndex)++updateBuildInfo :: Component -> BuildInfo -> PackageDescription -> PackageDescription+updateBuildInfo c bi pkg = foldr ($) pkg $+    [ iover focus $ \ name -> if name == componentName c then const bi else id+    | NamedComponent component getName <- namedComponents+    , let focus = itagged component getName <. buildInfo+    ]++restrictBuildFlags :: PackageDescription -> Component -> BuildFlags -> BuildFlags+restrictBuildFlags pkg c buildFlags = buildFlags+    { buildArgs = selectedArgs+    }+  where+    selectedArgs = [showBuildTarget (packageId pkg) $ BuildTargetComponent $ componentName c]
+ src/Clash/Clashilator/Setup.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE CPP, GADTs, RankNTypes, FlexibleContexts #-}+module Clash.Clashilator.Setup+    ( clashToVerilog+    , buildVerilator+    , clashilate++    , clashilatorMain+    , clashilatorBuildHook+    ) where++import qualified Clash.Main as Clash+import qualified Clash.Clashilator as Clashilator+import Clash.Clashilator.Cabal+import Clash.Driver.Manifest (Manifest, readManifest)++import Distribution.Simple+import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.Setup+import Distribution.Simple.Program+import Distribution.Simple.Utils (infoNoWrap)+import Distribution.Verbosity+import Distribution.ModuleName+import Distribution.Types.UnqualComponentName++import Distribution.Types.Lens+import Control.Lens hiding ((<.>))+import Data.List (intercalate, sort, nub)+import Data.Maybe (fromMaybe)+import System.FilePath+import GHC (Ghc)+#if MIN_VERSION_ghc(8,10,0)+import GHC (getSession, setSession)+import HscTypes (HscEnv (..))+import Linker+#endif++lookupX :: String -> BuildInfo -> Maybe String+lookupX key buildInfo = lookup ("x-clashilator-" <> key) (view customFieldsBI buildInfo)++clashilatorBuildHook :: BuildHook+clashilatorBuildHook = withComponentHook clashilate $ buildHook simpleUserHooks++clashToVerilog :: Ghc () -> LocalBuildInfo -> BuildFlags -> [FilePath] -> BuildInfo -> ModuleName -> String -> FilePath -> IO (FilePath, Manifest)+clashToVerilog startAction lbi flags srcDirs buildInfo mod entity outDir = do+    pkgdbs <- packageDBs lbi flags+    let dbpaths = nub . sort $ [ path | SpecificPackageDB path <- pkgdbs ]+        dbflags = concat [ ["-package-db", path] | path <- dbpaths ]+        iflags = [ "-i" <> dir | dir <- srcDirs ]+        clashflags = maybe [] words $ lookupX "clash-flags" buildInfo++    let args = concat+            [ [ "--verilog"+              , "-outputdir", outDir+              , "-main-is", entity+              , intercalate "." (components mod)+              ]+            , iflags+            , dbflags+            , clashflags+            ]+    infoNoWrap verbosity $ unwords $ "Clash.defaultMain" : args+    Clash.defaultMainWithAction startAction args++    let modDir = intercalate "." (components mod)+        verilogDir = outDir </> modDir <.> entity+    Just manifest <- readManifest (verilogDir </> "clash-manifest.json")++    return (verilogDir, manifest)+  where+    verbosity = fromFlagOrDefault normal (buildVerbosity flags)++buildVerilator :: Ghc () -> LocalBuildInfo -> BuildFlags -> Maybe UnqualComponentName -> BuildInfo -> IO BuildInfo+buildVerilator startAction lbi flags compName buildInfo = case top of+    Nothing -> return buildInfo+    Just mod -> buildVerilator' startAction lbi flags compName buildInfo (fromString mod) entity+  where+    top = lookupX "top-is" buildInfo+    entity = fromMaybe "topEntity" $ lookupX "entity" buildInfo++buildVerilator' :: Ghc () -> LocalBuildInfo -> BuildFlags -> Maybe UnqualComponentName -> BuildInfo -> ModuleName -> String -> IO BuildInfo+buildVerilator' startAction lbi flags compName buildInfo mod entity = do+    cflags <- do+        mpkgConfig <- needProgram verbosity pkgConfigProgram (withPrograms lbi)+        case mpkgConfig of+            Nothing -> error "Cannot find pkg-config program"+            Just (pkgConfig, _) -> getProgramOutput verbosity pkgConfig ["--cflags", "verilator"]++    -- TODO: dependency tracking+    (verilogDir, manifest) <- clashToVerilog startAction lbi flags srcDirs buildInfo mod entity synDir+    Clashilator.generateFiles (Just cflags) verilogDir verilatorDir (fromString <$> clk) manifest++    -- TODO: get `make` location from configuration+    _ <- getProgramInvocationOutput verbosity $+         simpleProgramInvocation "make" ["-f", verilatorDir </> "Makefile"]++    let incDir = verilatorDir </> "src"+        libDir = verilatorDir </> "obj"+        lib = "VerilatorFFI"++    let fixupOptions f (PerCompilerFlavor x y) = PerCompilerFlavor (f x) (f y)++        compileFlags =+            [ "-fPIC"+            , "-pgml c++"+            ]++        ldFlags =+            [ "-Wl,--whole-archive"+            , "-Wl,-Bstatic"+            , "-Wl,-l" <> lib+            , "-Wl,-Bdynamic"+            , "-Wl,--no-whole-archive"+            ]++    return $ buildInfo+      & includeDirs %~ (incDir:)+      & extraLibDirs %~ (libDir:)+      & extraLibs %~ ("stdc++":)+      & options %~ fixupOptions (compileFlags++)+      & ldOptions %~ (ldFlags++)+      & hsSourceDirs %~ (incDir:)+      & otherModules %~ (fromComponents ["Clash", "Clashilator", "FFI"]:)+  where+    verbosity = fromFlagOrDefault normal (buildVerbosity flags)++    clk = lookup "x-clashilator-clock" $ view customFieldsBI buildInfo++    -- TODO: Maybe we could add extra source dirs from "x-clashilator-source-dirs"?+    srcDirs = view hsSourceDirs buildInfo+    outDir = case compName of+        Nothing -> buildDir lbi+        Just name -> buildDir lbi </> unUnqualComponentName name+    verilatorDir = outDir </> "_clashilator" </> "verilator"+    synDir = outDir </> "_clashilator" </> "clash-syn"++clashilate :: LocalBuildInfo -> BuildFlags -> Component -> IO BuildInfo+clashilate lbi flags c = do+#if MIN_VERSION_ghc(8,10,0)+    linker <- uninitializedLinker+    let startAction = do+            env <- getSession+            setSession (env {hsc_dynLinker = linker})+#else+    let startAction = return ()+#endif+    buildVerilator startAction lbi flags (componentNameString $ componentName c) (c ^. buildInfo)++clashilatorMain :: IO ()+clashilatorMain = defaultMainWithHooks simpleUserHooks+    { buildHook = clashilatorBuildHook+    }
+ src/main.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE RecordWildCards, ApplicativeDo #-}++import Clash.Driver.Manifest+import Clash.Clashilator+import System.FilePath+import Options.Applicative+import Data.String (fromString)++data Options = Options+    { manifestPath :: FilePath+    , outputDir :: FilePath+    , clkName :: Maybe String+    }++options :: Parser Options+options = do+    manifestPath <- strOption $ mconcat+        [ long "input"+        , short 'i'+        , metavar "FILENAME"+        , help "Clash manifest file"+        ]+    outputDir <- strOption $ mconcat+        [ long "output"+        , short 'o'+        , metavar "DIRECTORY"+        , help "Where to put generated files"+        ]+    clkName <- optional $ strOption $ mconcat+        [ long "clock"+        , short 'c'+        , metavar "NAME"+        , help "Clock signal name"+        ]+    pure Options{..}++optionsInfo = info (options <**> helper) $ mconcat+    [ fullDesc+    , header "Clashilator - Clash <-> Verilator interface"+    , progDesc "Generate Verilator source files and FFI interface from Clash manifest"+    ]++main :: IO ()+main = do+    Options{..} <- execParser optionsInfo++    Just manifest <- readManifest manifestPath+    let inputDir = takeDirectory manifestPath++    generateFiles Nothing inputDir outputDir (fromString <$> clkName) manifest
+ template/FFI.hsc.mustache view
@@ -0,0 +1,70 @@+{-# LANGUAGE RecordWildCards, ForeignFunctionInterface #-}+module Clash.Clashilator.FFI where++import Prelude+import Clash.Prelude++import Data.Word+import Data.Int+import Foreign.Storable+import Foreign.Ptr+import Foreign.Marshal.Alloc++data INPUT = INPUT {+{{#inPorts}}+    {{^first}}, {{/first}}{{hsName}} :: {{hsType}}+{{/inPorts}}+    }+    deriving (Show)++data OUTPUT = OUTPUT{+{{#outPorts}}+    {{^first}}, {{/first}}{{hsName}} :: {{hsType}}+{{/outPorts}}+    }+    deriving (Show)+++#include "Interface.h"++data Sim++foreign import ccall unsafe "vinit" simInit :: IO (Ptr Sim)+foreign import ccall unsafe "vshutdown" simShutdown :: Ptr Sim -> IO ()+foreign import ccall unsafe "vstep" simStep :: Ptr Sim -> Ptr INPUT -> Ptr OUTPUT -> IO ()++instance Storable Bit where+    alignment = alignment . bitToBool+    sizeOf = sizeOf . bitToBool+    peek = fmap boolToBit . peek . castPtr+    poke ptr = poke (castPtr ptr) . bitToBool++instance Storable INPUT where+    alignment _ = #alignment INPUT+    sizeOf _ = #size INPUT+    {-# INLINE peek #-}+    peek ptr = const INPUT <$> pure ()+{{#inPorts}}+        <*> (#peek INPUT, {{cName}}) ptr+{{/inPorts}}+    {-# INLINE poke #-}+    poke ptr this = do+{{#inPorts}}+        (#poke INPUT, {{cName}}) ptr ({{hsName}} this)+{{/inPorts}}+        return ()++instance Storable OUTPUT where+    alignment _ = #alignment OUTPUT+    sizeOf _ = #size OUTPUT+    {-# INLINE peek #-}+    peek ptr = const OUTPUT <$> pure ()+{{#outPorts}}+        <*> (#peek OUTPUT, {{cName}}) ptr+{{/outPorts}}+    {-# INLINE poke #-}+    poke ptr this = do+{{#outPorts}}+        (#poke OUTPUT, {{cName}}) ptr ({{hsName}} this)+{{/outPorts}}+        return ()
+ template/Impl.cpp.mustache view
@@ -0,0 +1,43 @@+#include "VSim.h"+#include "verilated.h"+#include "Impl.h"++vluint64_t main_time = 0;++double sc_time_stamp ()+{+    return main_time;+}++VSim* vinit()+{+    // Verilated::commandArgs(0, 0);+    return new VSim();+}++void vshutdown(VSim *top)+{+    delete top;+}++void vstep(VSim* top, const INPUT* input, OUTPUT* output)+{+    {{#inPorts}}+    top->{{cName}} = input->{{cName}};+    {{/inPorts}}++    {{#clock}}+    top->{{cName}} = true;+    {{/clock}}+    top->eval();+    ++main_time;+    {{#clock}}+    top->{{cName}} = false;+    top->eval();+    ++main_time;+    {{/clock}}++    {{#outPorts}}+    output->{{cName}} = top->{{cName}};+    {{/outPorts}}+}
+ template/Impl.h.mustache view
@@ -0,0 +1,11 @@+#pragma once++#include "VSim.h"+#include "verilated.h"+#include "Interface.h"++extern "C" {+    VSim* vinit();+    void vstep(VSim* top, const INPUT* input, OUTPUT* output);+    void vshutdown(VSim* top);+}
+ template/Interface.h.mustache view
@@ -0,0 +1,19 @@+#pragma once++#include <stdint.h>++typedef int bit;++typedef struct+{+{{#inPorts}}+    {{cType}} {{cName}};+{{/inPorts}}+} INPUT;++typedef struct+{+{{#outPorts}}+    {{cType}} {{cName}};+{{/outPorts}}+} OUTPUT;
+ template/Makefile.mustache view
@@ -0,0 +1,49 @@+VERILOG_SRCS	= {{#srcs}}{{verilogPath}} {{/srcs}}++HDL_DIR         = {{hdlDir}}+OUT_DIR		= {{outputDir}}/obj+VERILATOR_HDRS	= $(OUT_DIR)/VSim.h+VERILATOR_LIB	= $(OUT_DIR)/VSim__ALL.a+VERILATOR_OBJS  = $(OUT_DIR)/verilated.o++SRC_DIR         = {{outputDir}}/src+SRCS	        = $(foreach file, Impl.cpp Impl.h Interface.h, $(SRC_DIR)/$(file))++{{#verilator}}+CPPFLAGS	= {{cflags}}+{{/verilator}}+{{^verilator}}+CPPFLAGS	= $(shell pkg-config --cflags verilator)+{{/verilator}}+CPPFLAGS	+= -I$(OUT_DIR)+CXXFLAGS	= -fPIC -O3+VERILATOR_FLAGS	= -CFLAGS '-O3 -fPIC' -Wno-fatal --prefix VSim +1364-2001ext+v -I$(HDL_DIR)++all: $(OUT_DIR)/libVerilatorFFI.a++clean:+	rm -rf $(OUT_DIR)++.PHONY: all clean++$(OUT_DIR)/VSim.mk: $(VERILOG_SRCS)+	verilator $(VERILATOR_FLAGS) --cc -Mdir $(OUT_DIR) $(VERILOG_SRCS)++$(OUT_DIR)/verilated.o: $(shell pkg-config --variable=includedir verilator)/verilated.cpp+	$(COMPILE.cc) $(OUTPUT_OPTION) $<++$(VERILATOR_LIB) $(VERILATOR_HDRS): $(OUT_DIR)/VSim.mk +	cd $(OUT_DIR) && make -f VSim.mk CXX=$(CXX)+        +$(OUT_DIR)/VerilatorFFI.o: $(SRCS) $(VERILATOR_HDRS)+	$(COMPILE.cc) $(OUTPUT_OPTION) $<++$(OUT_DIR)/libVerilatorFFI.a: $(OUT_DIR)/VerilatorFFI.o $(VERILATOR_LIB) $(VERILATOR_OBJS)+	rm -f $@+	mkdir -p $(OUT_DIR)+	ar rcsT $@ $^++$(OUT_DIR)/%.o : %.cpp+	mkdir -p $(OUT_DIR)+	$(COMPILE.cc) $(OUTPUT_OPTION) $<+