diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -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.
diff --git a/clashilator.cabal b/clashilator.cabal
new file mode 100644
--- /dev/null
+++ b/clashilator.cabal
@@ -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
diff --git a/src/Clash/Clashilator.hs b/src/Clash/Clashilator.hs
new file mode 100644
--- /dev/null
+++ b/src/Clash/Clashilator.hs
@@ -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
diff --git a/src/Clash/Clashilator/Cabal.hs b/src/Clash/Clashilator/Cabal.hs
new file mode 100644
--- /dev/null
+++ b/src/Clash/Clashilator/Cabal.hs
@@ -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]
diff --git a/src/Clash/Clashilator/Setup.hs b/src/Clash/Clashilator/Setup.hs
new file mode 100644
--- /dev/null
+++ b/src/Clash/Clashilator/Setup.hs
@@ -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
+    }
diff --git a/src/main.hs b/src/main.hs
new file mode 100644
--- /dev/null
+++ b/src/main.hs
@@ -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
diff --git a/template/FFI.hsc.mustache b/template/FFI.hsc.mustache
new file mode 100644
--- /dev/null
+++ b/template/FFI.hsc.mustache
@@ -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 ()
diff --git a/template/Impl.cpp.mustache b/template/Impl.cpp.mustache
new file mode 100644
--- /dev/null
+++ b/template/Impl.cpp.mustache
@@ -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}}
+}
diff --git a/template/Impl.h.mustache b/template/Impl.h.mustache
new file mode 100644
--- /dev/null
+++ b/template/Impl.h.mustache
@@ -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);
+}
diff --git a/template/Interface.h.mustache b/template/Interface.h.mustache
new file mode 100644
--- /dev/null
+++ b/template/Interface.h.mustache
@@ -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;
diff --git a/template/Makefile.mustache b/template/Makefile.mustache
new file mode 100644
--- /dev/null
+++ b/template/Makefile.mustache
@@ -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) $<
+
