diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Changelog for the [`clash-systemverilog`](http://hackage.haskell.org/package/clash-systemverilog) package
+
+## 0.5 *March 11th 2015*
+* Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2015, University of Twente
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# Support
+For updates and questions join the mailing list clash-language+subscribe@googlegroups.com or read the [forum](https://groups.google.com/d/forum/clash-language)
+
+# `clash-systemverilog`
+  * See the LICENSE file for license and copyright details
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/clash-systemverilog.cabal b/clash-systemverilog.cabal
new file mode 100644
--- /dev/null
+++ b/clash-systemverilog.cabal
@@ -0,0 +1,79 @@
+Name:                 clash-systemverilog
+Version:              0.5
+Synopsis:             CAES Language for Synchronous Hardware - As a Library
+Description:
+  CλaSH (pronounced ‘clash’) is a functional hardware description language that
+  borrows both its syntax and semantics from the functional programming language
+  Haskell. The merits of using a functional language to describe hardware comes
+  from the fact that combinational circuits can be directly modelled as
+  mathematical functions and that functional languages lend themselves very well
+  at describing and (de-)composing mathematical functions.
+  .
+  This package provides:
+  .
+  * SystemVerilog Backend
+Homepage:             http://www.clash-lang.org/
+bug-reports:          http://github.com/clash-lang/clash-compiler/issues
+License:              BSD2
+License-file:         LICENSE
+Author:               Christiaan Baaij
+Maintainer:           Christiaan Baaij <christiaan.baaij@gmail.com>
+Copyright:            Copyright © 2015 University of Twente
+Category:             Hardware
+Build-type:           Simple
+
+Extra-source-files:   README.md,
+                      CHANGELOG.md
+
+Data-files:           primitives/CLaSH.Driver.TestbenchGen.json
+                      primitives/CLaSH.GHC.GHC2Core.json
+                      primitives/CLaSH.Prelude.BlockRam.json
+                      primitives/CLaSH.Prelude.Testbench.json
+                      primitives/CLaSH.Promoted.Nat.json
+                      primitives/CLaSH.Promoted.Symbol.json
+                      primitives/CLaSH.Signal.Bundle.json
+                      primitives/CLaSH.Signal.Explicit.json
+                      primitives/CLaSH.Signal.Internal.json
+                      primitives/CLaSH.Sized.Internal.BitVector.json
+                      primitives/CLaSH.Sized.Internal.Index.json
+                      primitives/CLaSH.Sized.Internal.Signed.json
+                      primitives/CLaSH.Sized.Internal.Unsigned.json
+                      primitives/CLaSH.Sized.Vector.json
+                      primitives/Control.Exception.Base.json
+                      primitives/GHC.Base.json
+                      primitives/GHC.Classes.json
+                      primitives/GHC.CString.json
+                      primitives/GHC.Err.json
+                      primitives/GHC.Integer.Type.json
+                      primitives/GHC.Prim.json
+                      primitives/GHC.Real.json
+                      primitives/GHC.Typelits.json
+                      primitives/GHC.Types.json
+                      primitives/Unsafe.Coerce.json
+
+Cabal-version:        >=1.10
+
+source-repository head
+  type: git
+  location: https://github.com/clash-lang/clash-compiler.git
+
+Library
+  HS-Source-Dirs:     src
+
+  default-language:   Haskell2010
+  ghc-options:        -Wall -fwarn-tabs
+  CPP-Options:        -DCABAL
+
+  Build-depends:      base                    >= 4.6.0.1 && < 5,
+                      clash-lib               >= 0.5,
+                      clash-prelude           >= 0.7,
+                      fgl                     >= 5.4.2.4,
+                      lens                    >= 3.9.2,
+                      mtl                     >= 2.1.2,
+                      text                    >= 0.11.3.1,
+                      unordered-containers    >= 0.2.3.3,
+                      wl-pprint-text          >= 1.1.0.0
+
+  Exposed-modules:    CLaSH.Backend.SystemVerilog
+
+  other-modules:      Paths_clash_systemverilog
diff --git a/primitives/CLaSH.Driver.TestbenchGen.json b/primitives/CLaSH.Driver.TestbenchGen.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Driver.TestbenchGen.json
@@ -0,0 +1,55 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.clockGen"
+    , "templateD" :
+"// pragma translate_off
+always begin
+  ~RESULT = 0;
+  #~LIT[0] forever begin
+    ~RESULT = ~ ~RESULT;
+    #~LIT[1];
+    ~RESULT = ~ ~RESULT;
+    #~LIT[2];
+  end
+end
+// pragma translate_on"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.resetGen"
+    , "templateD" :
+"// pragma translate_off
+initial begin
+  ~RESULT = 0;
+  #~LIT[0] ~RESULT = 1;
+end
+// pragma translate_on"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.doneGen"
+    , "templateD" :
+"assign ~RESULT = ~ARG[0];
+
+// pragma translate_off
+always_comb begin
+  if (~ARG[0] == 1'b1) begin
+    $finish;
+  end
+end
+// pragma translate_on
+"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.finishedGen"
+    , "templateD" :
+"always begin
+// pragma translate_off
+  ~RESULT <= 1'b0;
+  #~LIT[0]
+// pragma translate_on
+  ~RESULT = 1'b1;
+end"
+    }
+  }
+]
diff --git a/primitives/CLaSH.GHC.GHC2Core.json b/primitives/CLaSH.GHC.GHC2Core.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.GHC.GHC2Core.json
@@ -0,0 +1,16 @@
+[ { "BlackBox" :
+    { "name"      : "EmptyCase"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "Primitive" :
+    { "name"     : "_CO_"
+    , "primType" : "Constructor"
+    }
+  }
+, { "Primitive" :
+    { "name"     : "_TY_"
+    , "primType" : "Constructor"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Prelude.BlockRam.json b/primitives/CLaSH.Prelude.BlockRam.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Prelude.BlockRam.json
@@ -0,0 +1,31 @@
+[ { "BlackBox" :
+    { "name" : "CLaSH.Prelude.BlockRam.blockRam'"
+    , "type" :
+"blockRam' :: (KnownNat n, KnownNat m) -- (ARG[0],ARG[1])
+           => SClock clk               -- clk,  ARG[2]
+           -> Vec n a                  -- init, ARG[3]
+           -> Signal' clk (Unsigned m) -- wr,   ARG[4]
+           -> Signal' clk (Unsigned m) -- rd,   ARG[5]
+           -> Signal' clk Bool         -- wren, ARG[6]
+           -> Signal' clk a            -- din,  ARG[7]
+           -> Signal' clk a"
+    , "templateD" :
+"// blockRam
+~SIGD[~SYM[0]][3];
+~SIGD[~SYM[1]][7];
+
+initial begin
+  ~SYM[0] = ~LIT[3];
+end
+
+always @(posedge ~CLK[2]) begin
+  if (~ARG[6]) begin
+    ~SYM[0][~ARG[4]] <= ~ARG[7];
+  end
+  ~SYM[1] <= ~SYM[0][~ARG[5]];
+end
+
+assign ~RESULT = ~SYM[1];"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Prelude.Testbench.json b/primitives/CLaSH.Prelude.Testbench.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Prelude.Testbench.json
@@ -0,0 +1,22 @@
+[ { "BlackBox" :
+    { "name" : "CLaSH.Prelude.Testbench.assert"
+    , "type" :
+"assert :: (Eq a,Show a) -- (ARG[0],ARG[1])
+        => Signal' t a   -- ^ Checked value (ARG[2])
+        -> Signal' t a   -- ^ Expected value (ARG[3])
+        -> Signal' t b   -- ^ Return valued (ARG[4])
+        -> Signal' t b"
+    , "templateD" :
+"// assert
+// pragma translate_off
+always @(posedge ~CLK[2] or negedge ~RST[2]) begin
+  if (~ARG[2] != ~ARG[3]) begin
+    $display(\"expected: %b, actual: %b\", ~TYPM[3]_to_lv(~ARG[3]), ~TYPM[2]_to_lv(~ARG[2]));
+    $stop;
+  end
+end
+// pragma translate_on
+assign ~RESULT = ~ARG[4];"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Promoted.Nat.json b/primitives/CLaSH.Promoted.Nat.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Promoted.Nat.json
@@ -0,0 +1,13 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Promoted.Nat.SNat"
+    , "type"      : "SNat :: KnownNat n => Proxy n -> SNat n"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Promoted.Nat.snatToInteger"
+    , "type"      : "snatToInteger :: SNat n -> Integer"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Promoted.Symbol.json b/primitives/CLaSH.Promoted.Symbol.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Promoted.Symbol.json
@@ -0,0 +1,13 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Promoted.Symbol.SSymbol"
+    , "type"      : "SSymbol :: KnownNat n => Proxy n -> SSymbol n"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Promoted.Symbol.symbolToString"
+    , "type"      : "symbolToString :: SSymbol n -> String"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Signal.Bundle.json b/primitives/CLaSH.Signal.Bundle.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Signal.Bundle.json
@@ -0,0 +1,6 @@
+[ { "Primitive" :
+    { "name"      : "CLaSH.Signal.Bundle.vecBundle#"
+    , "primType"  : "Function"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Signal.Explicit.json b/primitives/CLaSH.Signal.Explicit.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Signal.Explicit.json
@@ -0,0 +1,11 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Signal.Explicit.unsafeSynchronizer"
+    , "type" :
+"unsafeSynchronizer :: SClock clk1
+                    -> SClock clk2
+                    -> Signal' clk1 a -- ARG[2]
+                    -> Signal' clk2 a"
+    , "templateE" : "~ARG[2]"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Signal.Internal.json b/primitives/CLaSH.Signal.Internal.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Signal.Internal.json
@@ -0,0 +1,70 @@
+[ { "BlackBox" :
+    { "name" : "CLaSH.Signal.Internal.register#"
+    , "type" :
+"register# :: SClock clk     -- ARG[0]
+           -> a              -- ARG[1]
+           -> Signal' clk a  -- ARG[2]
+           -> Signal' clk a"
+    , "templateD" :
+"~SIGD[~SYM[0]][2];
+
+always_ff @(posedge ~CLK[0] or negedge ~RST[0])
+if (~ ~RST[0]) begin
+  ~SYM[0] <= ~ARG[1];
+end else begin
+  ~SYM[0] <= ~ARG[2];
+end
+
+assign ~RESULT = ~SYM[0];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Signal.Internal.regEn#"
+    , "type" :
+"regEn# :: SClock clk       -- ARG[0]
+        -> a                -- ARG[1]
+        -> Signal' clk Bool -- ARG[2]
+        -> Signal' clk a    -- ARG[3]
+        -> Signal' clk a"
+    , "templateD" :
+"~SIGD[~SYM[0]][3];
+
+always_ff @(posedge ~CLK[0] or negedge ~RST[0])
+if (~ ~RST[0]) begin
+  ~SYM[1] <= ~ARG[1];
+end else begin
+  if (~ARG[2]) begin
+    ~SYM[1] <= ~ARG[3];
+  end
+end
+
+assign ~RESULT = ~SYM[1];"
+    }
+  }
+
+, { "Primitive" :
+    { "name"      : "CLaSH.Signal.Internal.signal#"
+    , "primType"  : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"      : "CLaSH.Signal.Internal.mapSignal#"
+    , "primType"  : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"      : "CLaSH.Signal.Internal.appSignal#"
+    , "primType"  : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"      : "CLaSH.Signal.Internal.foldr#"
+    , "primType"  : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"      : "CLaSH.Signal.Internal.traverse#"
+    , "primType"  : "Function"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Sized.Internal.BitVector.json b/primitives/CLaSH.Sized.Internal.BitVector.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Sized.Internal.BitVector.json
@@ -0,0 +1,365 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.size#"
+    , "type"      : "size# :: KnownNat n => BitVector n -> Int"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.maxIndex#"
+    , "type"      : "maxIndex# :: KnownNat n => BitVector n -> Int"
+    , "templateE" : "~LIT[0] - 1"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.high"
+    , "type"      : "high :: Bit"
+    , "templateE" : "1'b1"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.low"
+    , "type"      : "low :: Bit"
+    , "templateE" : "1'b0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.++#"
+    , "type"      : "(++#) :: KnownNat m => BitVector n -> BitVector m -> BitVector (n + m)"
+    , "templateE" : "{~ARG[1],~ARG[2]}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.reduceAnd#"
+    , "type"      : "reduceAnd# :: KnownNat n => BitVector n -> BitVector 1"
+    , "templateE" : "& (~ARG[1])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.reduceOr#"
+    , "type"      : "reduceOr# :: BitVector n -> BitVector 1"
+    , "templateE" : "| (~ARG[0])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.reduceXor#"
+    , "type"      : "reduceXor# :: BitVector n -> BitVector 1"
+    , "templateE" : "^ (~ARG[0])"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.index#"
+    , "type" :
+"index# :: KnownNat n  -- ARG[0]
+        => BitVector n -- ARG[1]
+        -> Int         -- ARG[2]
+        -> Bit"
+    , "templateD" :
+"// index
+~SIGD[~SYM[0]][1];
+~SIGD[~SYM[1]][2];
+
+assign ~SYM[0] = ~ARG[1];
+assign ~SYM[1] = ~ARG[2];
+
+// pragma translate_off
+always_comb begin
+  if (~SYM[1] < $low(~SYM[0]) || ~SYM[1] > $high(~SYM[0])) begin
+    $display(\"Index: %d, is out of bounds: %d to %d\", ~SYM[1], $low(~SYM[0]), $high(~SYM[0]));
+    ~RESULT = ~ERRORO;
+  end else begin
+  // pragma translate_on
+    ~RESULT = ~SYM[0][~SYM[1]];
+  // pragma translate_off
+  end
+end
+// pragma translate_on"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.replaceBit#"
+    , "type" :
+"replaceBit# :: KnownNat n  -- ARG[0]
+             => BitVector n -- ARG[1]
+             -> Int         -- ARG[2]
+             -> Bit         -- ARG[3]
+             -> BitVector n"
+    , "templateD" :
+"// replaceBit
+~SIGD[~SYM[0]][2];
+assign ~SYM[0] = ~ARG[2];
+
+~SIGD[~SYM[1]][1];
+always_comb begin
+  ~SYM[1] = ~ARG[1];
+  // pragma translate_off
+  if (~SYM[0] < $low(~SYM[1]) || ~SYM[0] > $high(~SYM[1])) begin
+    $display(\"Index: %d, is out of bounds: %d to %d\", ~SYM[0], $low(~SYM[1]), $high(~SYM[1]));
+    ~SYM[1] = ~ERROR[1];
+  end else begin
+    // pragma translate_on
+    ~SYM[1][~SYM[0]] = ~ARG[3];
+    // pragma translate_off
+  end
+  // pragma translate_on
+end
+
+assign ~RESULT = ~SYM[1];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.setSlice#"
+    , "type" :
+"setSlice# :: BitVector (m + 1 + i) -- ARG[0]
+           -> SNat m                -- ARG[1]
+           -> SNat n                -- ARG[2]
+           -> BitVector (m + 1 - n) -- ARG[3]
+           -> BitVector (m + 1 + i)"
+    , "templateD" :
+"// setSlice
+~SIGD[~SYM[0]][0];
+
+always_comb begin
+  ~SYM[0] = ~ARG[0];
+  ~SYM[0][~LIT[1] : ~LIT[2]] = ~ARG[3];
+end
+
+assign ~RESULT = ~SYM[0];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.slice#"
+    , "type" :
+"slice# :: BitVector (m + 1 + i) -- ARG[0]
+        -> SNat m                -- ARG[1]
+        -> SNat n                -- ARG[2]
+        -> BitVector (m + 1 - n)"
+    , "templateD" :
+"// slice
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+assign ~RESULT = ~SYM[1][~LIT[1] : ~LIT[2]];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.split#"
+    , "type" :
+"split# :: KnownNat n        -- ARG[0]
+        => BitVector (m + n) -- ARG[1]
+        -> (BitVector m, BitVector n)"
+    , "templateD" :
+"// split
+~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+assign ~RESULT = '{ ~SYM[0][$high(~SYM[0]) : ~LIT[0]]
+                  , ~SYM[0][(~LIT[0]-1) : 0]
+                  };"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.msb#"
+    , "type" :
+"msb# :: KnownNat n  -- ARG[0]
+      => BitVector n -- ARG[1]
+      -> Bit"
+    , "templateD" :
+"// msb
+~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+assign ~RESULT = ~SYM[0][~LIT[0]-1];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.lsb#"
+    , "type" :
+"lsb# :: BitVector n -- ARG[0]
+      -> Bit"
+    , "templateD" :
+"// lsb
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+assign ~RESULT = ~SYM[0][0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.eq#"
+    , "type"      : "eq# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.neq#"
+    , "type"      : "neq# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.lt#"
+    , "type"      : "lt# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.ge#"
+    , "type"      : "ge# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.gt#"
+    , "type"      : "gt# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.le#"
+    , "type"      : "le# :: BitVector n -> BitVector n -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.minBound#"
+    , "type"      : "minBound# :: KnownNat n => BitVector n"
+    , "templateE" : "~LIT[0]'d0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.maxBound#"
+    , "type"      : "maxBound# :: KnownNat n => BitVector n"
+    , "templateE" : "{~LIT[0] {1'b1}}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.+#"
+    , "type"      : "(+#) :: KnownNat n => BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.-#"
+    , "type"      : "(-#) :: KnownNat n => BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.*#"
+    , "type"      : "(*#) :: KnownNat n => BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.negate#"
+    , "type"      : "negate# :: KnownNat n => BitVector n -> BitVector n"
+    , "templateE" : "-~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.fromInteger#"
+    , "type"      : "fromInteger# :: KnownNat n => Integer -> BitVector n"
+    , "templateE" : "$unsigned(~ARG[1])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.plus#"
+    , "type"      : "plus# :: KnownNat (Max m n + 1) => BitVector m -> BitVector n -> BitVector (Max m n + 1)"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.minus#"
+    , "type"      : "minus# :: KnownNat (Max m n + 1) => BitVector m -> BitVector n -> BitVector (Max m n + 1)"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.times#"
+    , "type"      : "times# :: KnownNat (m + n) => BitVector m -> BitVector n -> BitVector (m + n)"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.quot#"
+    , "type"      : "quot# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1]) / ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.rem#"
+    , "type"      : "rem# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.mod#"
+    , "type"      : "mod# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.toInteger#"
+    , "type"      : "toInteger# :: BitVector n -> Integer"
+    , "templateE" : "$unsigned(~ARG[0])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.and#"
+    , "type"      : "and# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[0] & ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.or#"
+    , "type"      : "or# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[0] | ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.xor#"
+    , "type"      : "xor# :: BitVector n -> BitVector n -> BitVector n"
+    , "templateE" : "~ARG[0] ^ ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.complement#"
+    , "type"      : "complement# :: KnownNat n => BitVector n -> BitVector n"
+    , "templateE" : "~ ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.shiftL#"
+    , "type"      : "shiftL# :: KnownNat n => BitVector n -> Int -> BitVector n"
+    , "templateE" : "~ARG[1] << ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.shiftR#"
+    , "type"      : "shiftR# :: KnownNat n => BitVector n -> Int -> BitVector n"
+    , "templateE" : "~ARG[1] >> ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.rotateL#"
+    , "type"      : "rotateL# :: KnownNat n => BitVector n -> Int -> BitVector n"
+    , "templateD" :
+"// rotateL
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} << ~ARG[2];
+assign ~RESULT = ~SYM[0][~LIT[1]-1 : 0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.rotateR#"
+    , "type"      : "rotateR# :: KnownNat n => BitVector n -> Int -> BitVector n"
+    , "templateD" :
+"// rotateR
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} >> ~ARG[2];
+assign ~RESULT = ~SYM[0][~LIT[1]-1 : 0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.resize#"
+    , "type"      : "resize# :: KnownNat m => BitVector n -> BitVector m"
+    , "templateE" : "$unsigned(~ARG[1])"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Sized.Internal.Index.json b/primitives/CLaSH.Sized.Internal.Index.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Sized.Internal.Index.json
@@ -0,0 +1,91 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.eq#"
+    , "type"      : "eq# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.neq#"
+    , "type"      : "neq# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.lt#"
+    , "type"      : "lt# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.ge#"
+    , "type"      : "ge# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.gt#"
+    , "type"      : "gt# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.le#"
+    , "type"      : "le# :: Index n -> Index n -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.maxBound#"
+    , "type"      : "maxBound# :: KnownNat n => Index n"
+    , "templateE" : "~LIT[0]-1"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.+#"
+    , "type"      : "(+#) :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.-#"
+    , "type"      : "(-#) :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.*#"
+    , "type"      : "(*#) :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.fromInteger#"
+    , "type"      : "fromInteger# :: KnownNat n => Integer -> Index n"
+    , "templateE" : "$unsigned(~ARG[1])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.quot#"
+    , "type"      : "quot# :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] / ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.rem#"
+    , "type"      : "rem# :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.mod#"
+    , "type"      : "mod# :: KnownNat n => Index n -> Index n -> Index n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Index.toInteger#"
+    , "type"      : "toInteger# :: Index n -> Integer"
+    , "templateE" : "$unsigned(~ARG[0])"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Sized.Internal.Signed.json b/primitives/CLaSH.Sized.Internal.Signed.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Sized.Internal.Signed.json
@@ -0,0 +1,260 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Internal.Signed.size#"
+    , "type"      : "size# :: KnownNat n => Signed n -> Int"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.pack#"
+    , "type"      : "pack# :: KnownNat n => Signed n -> BitVector n"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.unpack#"
+    , "type"      : "unpack# :: KnownNat n => BitVector n -> Signed n"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.eq#"
+    , "type"      : "eq# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.neq#"
+    , "type"      : "neq# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.lt#"
+    , "type"      : "lt# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.ge#"
+    , "type"      : "ge# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.gt#"
+    , "type"      : "gt# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.le#"
+    , "type"      : "le# :: Signed n -> Signed n -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.minBound#"
+    , "type"      : "minBound# :: KnownNat n => Signed n"
+    , "comment"   : "Generates incorrect SV for n=0"
+    , "templateE" : "{1'b1, {(~LIT[0]-1) {1'b0}}}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.maxBound#"
+    , "type"      : "maxBound# :: KnownNat n => Signed n"
+    , "comment"   : "Generates incorrect SV for n=0"
+    , "templateE" : "{1'b0, {(~LIT[0]-1) {1'b1}}}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.+#"
+    , "type"      : "(+#) :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.-#"
+    , "type"      : "(-#) :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.*#"
+    , "type"      : "(*#) :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.negate#"
+    , "type"      : "negate# :: KnownNat n => Signed n -> Signed n"
+    , "templateE" : "-~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.abs#"
+    , "type"      : "abs# :: KnownNat n => Signed n -> Signed n"
+    , "templateE" : "(~ARG[1] < ~LIT[0]'sd0) ? -~ARG[1] : ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.fromInteger#"
+    , "type"      : "fromInteger# :: KnownNat n => Integer -> Signed (n :: Nat)"
+    , "templateE" : "$signed(~ARG[1])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.plus#"
+    , "type"      : "plus# :: KnownNat (1 + Max m n) => Signed m -> Signed n -> Signed (1 + Max m n)"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.minus#"
+    , "type"      : "minus# :: KnownNat (1 + Max m n) => Signed m -> Signed n -> Signed (1 + Max m n)"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.times#"
+    , "type"      : "times# :: KnownNat (m + n) => Signed m -> Signed n -> Signed (m + n)"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.quot#"
+    , "type"      : "quot# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] / ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.rem#"
+    , "type"      : "rem# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.div#"
+    , "type"      : "div# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateD" :
+"// divInt
+~SIGD[~SYM[0]][1];
+~SIGD[~SYM[1]][1];
+~SIGD[~SYM[2]][2];
+
+// divide (rounds towards zero)
+assign ~SYM[0] = ~ARG[1] / ~ARG[2];
+
+// round toward minus infinity
+assign ~SYM[1] = ~ARG[1];
+assign ~SYM[2] = ~ARG[2];
+assign ~RESULT = (~SYM[1][~LIT[0]-1] == ~SYM[2][~LIT[0]-1]) ? ~SYM[0] : ~SYM[0] - ~LIT[0]'sd1;"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.mod#"
+    , "type"      : "mod# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateD" :
+"// modSigned
+~SIGD[~SYM[0]][1];
+~SIGD[~SYM[1]][1];
+~SIGD[~SYM[2]][2];
+
+// remainder
+assign ~SYM[0] = ~ARG[1] % ~ARG[2];
+
+// modulo
+assign ~SYM[1] = ~ARG[1];
+assign ~SYM[2] = ~ARG[2];
+assign ~RESULT = (~SYM[1][~LIT[0]-1] == ~SYM[2][~LIT[0]-1]) ?
+                 ~SYM[0] :
+                 (~ARG[1] == ~LIT[0]'sd0 ? ~LIT[0]'sd0 : ~SYM[0] + ~ARG[1]);"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.toInteger#"
+    , "type"      : "toInteger# :: Signed n -> Integer"
+    , "templateE" : "$signed(~ARG[0])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.and#"
+    , "type"      : "and# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] & ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.or#"
+    , "type"      : "or# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] | ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.xor#"
+    , "type"      : "xor# :: KnownNat n => Signed n -> Signed n -> Signed n"
+    , "templateE" : "~ARG[1] ^ ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.complement#"
+    , "type"      : "complement# :: KnownNat n => Signed n -> Signed n"
+    , "templateE" : "~ ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.shiftL#"
+    , "type"      : "shiftL# :: KnownNat n => Signed n -> Int -> Signed n"
+    , "templateE" : "~ARG[1] <<< ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.shiftR#"
+    , "type"      : "shiftR# :: KnownNat n => Signed n -> Int -> Signed n"
+    , "templateE" : "~ARG[1] >>> ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.rotateL#"
+    , "type"      : "rotateL# :: KnownNat n => Signed n -> Int -> Signed n"
+    , "templateD" :
+"// rotateL
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} << ~ARG[2];
+assign ~RESULT = $signed(~SYM[0][~LIT[1]-1 : 0]);"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.rotateR#"
+    , "type"      : "rotateR# :: KnownNat n => Signed n -> Int -> Signed n"
+    , "templateD" :
+"// rotateR
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} >> ~ARG[2];
+assign ~RESULT = $signed(~SYM[0][~LIT[1]-1 : 0]);"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.resize#"
+    , "type"      : "resize# :: (KnownNat n, KnownNat m) => Signed n -> Signed m"
+    , "comment"   : "Back-end should only use this code when the result is smaller than the argument"
+    , "templateD" :
+"// resize
+generate
+  if (~LIT[1] < ~LIT[0]) begin
+    // truncate, sign preserving
+    ~SIGD[~SYM[0]][2];
+    assign ~SYM[0] = ~ARG[2];
+    assign ~RESULT = $signed({~SYM[0][~LIT[0]-1],~SYM[0][(~LIT[1]-2):0]});
+  end else begin
+    // sign-extend
+    assign ~RESULT = $signed(~ARG[2]);
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Signed.truncateB#"
+    , "type"      : "truncateB# :: KnownNat m => Signed (n + m) -> Signed m"
+    , "templateE" : "$signed(~ARG[1])"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Sized.Internal.Unsigned.json b/primitives/CLaSH.Sized.Internal.Unsigned.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Sized.Internal.Unsigned.json
@@ -0,0 +1,201 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.size#"
+    , "type"      : "size# :: KnownNat n => Unsigned n -> Int"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.pack#"
+    , "type"      : "pack# :: Unsigned n -> BitVector n"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.unpack#"
+    , "type"      : "unpack# :: BitVector n -> Unsigned n"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.eq#"
+    , "type"      : "eq# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.neq#"
+    , "type"      : "neq# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.lt#"
+    , "type"      : "lt# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.ge#"
+    , "type"      : "ge# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.gt#"
+    , "type"      : "gt# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.le#"
+    , "type"      : "le# :: Unsigned n -> Unsigned n -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.minBound#"
+    , "type"      : "minBound# :: KnownNat n => Unsigned n"
+    , "templateE" : "~LIT[0]'d0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.maxBound#"
+    , "type"      : "maxBound# :: KnownNat n => Unsigned n"
+    , "templateE" : "{~LIT[0] {1'b1}}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.+#"
+    , "type"      : "(+#) :: KnownNat n => Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.-#"
+    , "type"      : "(-#) :: KnownNat n => Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.*#"
+    , "type"      : "(*#) :: KnownNat n => Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.negate#"
+    , "type"      : "negate# :: KnownNat n => Unsigned n -> Unsigned n"
+    , "templateE" : "- ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.fromInteger#"
+    , "type"      : "fromInteger# :: KnownNat n => Integer -> Unsigned n"
+    , "templateE" : "$unsigned(~ARG[1])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.plus#"
+    , "type"      : "plus# :: KnownNat (1 + Max m n) => Unsigned m -> Unsigned n -> Unsigned (1 + Max m n)"
+    , "templateE" : "~ARG[1] + ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.minus#"
+    , "type"      : "minus# :: KnownNat (1 + Max m n) => Unsigned m -> Unsigned n -> Unsigned (1 + Max m n)"
+    , "templateE" : "~ARG[1] - ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.times#"
+    , "type"      : "times# :: KnownNat (m + n) => Unsigned m -> Unsigned n -> Unsigned (m + n)"
+    , "templateE" : "~ARG[1] * ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.quot#"
+    , "type"      : "quot# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] / ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.rem#"
+    , "type"      : "rem# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.mod#"
+    , "type"      : "mod# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[1] % ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.toInteger#"
+    , "type"      : "toInteger# :: Unsigned n -> Integer"
+    , "templateE" : "$unsigned(~ARG[0])"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.and#"
+    , "type"      : "and# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[0] & ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.or#"
+    , "type"      : "or# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[0] | ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.xor#"
+    , "type"      : "xor# :: Unsigned n -> Unsigned n -> Unsigned n"
+    , "templateE" : "~ARG[0] ^ ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.complement#"
+    , "type"      : "complement# :: KnownNat n => Unsigned n -> Unsigned n"
+    , "templateE" : "~ ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.shiftL#"
+    , "type"      : "shiftL# :: KnownNat n => Unsigned n -> Int -> Unsigned n"
+    , "templateE" : "~ARG[1] << ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.shiftR#"
+    , "type"      : "shiftR# :: KnownNat n => Unsigned n -> Int -> Unsigned n"
+    , "templateE" : "~ARG[1] >> ~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.rotateL#"
+    , "type"      : "rotateL# :: KnownNat n => Unsigned n -> Int -> Unsigned n"
+    , "templateD" :
+"// rotateL
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} << ~ARG[2];
+assign ~RESULT = ~SYM[0][~LIT[1]-1 : 0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.rotateR#"
+    , "type"      : "rotateR# :: KnownNat n => Unsigned n -> Int -> Unsigned n"
+    , "templateD" :
+"// rotateR
+logic [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} >> ~ARG[2];
+assign ~RESULT = ~SYM[0][~LIT[1]-1 : 0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.Unsigned.resize#"
+    , "type"      : "resize# :: KnownNat m => Unsigned n -> Unsigned m"
+    , "templateE" : "$unsigned(~ARG[1])"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Sized.Vector.json b/primitives/CLaSH.Sized.Vector.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Sized.Vector.json
@@ -0,0 +1,341 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.eq#"
+    , "type"      : "eq# :: Eq a => Vec n a -> Vec n a -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.neq#"
+    , "type"      : "neq# :: Eq a => Vec n a -> Vec n a -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.head"
+    , "type"      : "head :: Vec (n + 1) a -> a"
+    , "templateD" :
+"// head
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.tail"
+    , "type"      : "tail :: Vec (n + 1) a -> Vec n a"
+    , "templateD" :
+"// tail
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][1 : $high(~SYM[0])];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.last"
+    , "type"      : "Vec (n + 1) a -> a"
+    , "templateD" :
+"// last
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][$high(~SYM[0])];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.init"
+    , "type"      : "Vec (n + 1) a -> Vec n a"
+    , "templateD" :
+"// init
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][0 : $high(~SYM[0]) - 1];"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Vector.select"
+    , "type" :
+"select :: (CmpNat (i + s) (s * n) ~ GT) -- ARG[0]
+        => SNat f                        -- ARG[1]
+        -> SNat s                        -- ARG[2]
+        -> SNat n                        -- ARG[3]
+        -> Vec i a                       -- ARG[4]
+        -> Vec n a"
+    , "templateD" :
+"// select
+~SIGD[~SYM[0]][4];
+assign ~SYM[0] = ~ARG[4];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1]=0; ~SYM[1] < ~LIT[3]; ~SYM[1] = ~SYM[1] + 1) begin : select_~SYM[2]
+    assign ~RESULT[~SYM[1]] = ~SYM[0][~LIT[1] + (~LIT[2] * ~SYM[1])];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.++"
+    , "type"      : "(++) :: Vec n a -> Vec m a -> Vec (n + m) a"
+    , "templateD" :
+"// (++)
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][1];
+
+assign ~SYM[0] = ~ARG[0];
+assign ~SYM[1] = ~ARG[1];
+
+genvar ~SYM[2];
+generate
+  for (~SYM[2]=0; ~SYM[2] < $size(~RESULT); ~SYM[2] = ~SYM[2] + 1) begin : append_~SYM[3]
+    if (~SYM[2] < $size(~SYM[0])) begin
+      assign ~RESULT[~SYM[2]] = ~SYM[0][~SYM[2]];
+    end else begin
+      assign ~RESULT[~SYM[2]] = ~SYM[1][~SYM[2]-$size(~SYM[0])];
+    end
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.concat"
+    , "type"      : "concat :: Vec n (Vec m a) -> Vec (n * m) a"
+    , "templateD" :
+"// concat
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1]=0; ~SYM[1] < $size(~SYM[0]); ~SYM[1] = ~SYM[1] + 1) begin : concat_~SYM[2]
+    assign ~RESULT[(~SYM[5] * $size(~SYM[0][0])) : ((~SYM[5] * $size(~SYM[0][0])) + $high(~SYM[0][0]))] = ~SYM[0][~SYM[1]];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.splitAt"
+    , "type"      : "splitAt :: SNat m -> Vec (m + n) a -> (Vec m a, Vec n a)"
+    , "templateD" :
+"// splitAt
+~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+
+assign ~RESULT = '{~SYM[0][$left(~RESULT.~TYPMO_sel0) : $right(~RESULT.~TYPMO_sel0)]
+                  ,~SYM[0][($left(~RESULT.~TYPMO_sel1) + $size(~RESULT.~TYPMO_sel0)) : ($right(~RESULT.~TYPMO_sel1) + $size(~RESULT.~TYPMO_sel0))]
+                  };"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Vector.unconcat"
+    , "type" :
+ "unconcat :: KnownNat n     -- ARG[0]
+           => SNat m         -- ARG[1]
+           -> Vec (n * m) a  -- ARG[2]
+           -> Vec n (Vec m a)"
+    , "templateD" :
+"// unconcat
+~SIGD[~SYM[0]][2];
+assign ~SYM[0] = ~ARG[2];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1] = 0; ~SYM[1] < $size(~RESULT); ~SYM[1] = ~SYM[1] + 1) begin : unconcat_~SYM[2]
+    assign ~RESULT[~SYM[1]] = ~SYM[0][(~SYM[1] * ~LIT[1]) : ((~SYM[1] * ~LIT[1]) + ~LIT[1] - 1)];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.merge"
+    , "type"      : "merge :: Vec n a -> Vec n a -> Vec (n + n) a"
+    , "templateD" :
+"// merge
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][1];
+assign ~SYM[0] = ~ARG[0];
+assign ~SYM[1] = ~ARG[1];
+
+genvar ~SYM[2];
+generate
+  for (~SYM[2] = 0; ~SYM[2] < $size(~SYM[0]); ~SYM[2] = ~SYM[2] + 1) begin : merge_~SYM[3]
+    assign ~RESULT[2*~SYM[2]]   = ~SYM[0][~SYM[2]];
+    assign ~RESULT[2*~SYM[2]+1] = ~SYM[1][~SYM[2]];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.map"
+    , "type"      : "map :: (a -> b) -> Vec n a -> Vec n b"
+    , "templateD" :
+"// map
+~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1]=0; ~SYM[1] < $size(~RESULT); ~SYM[1] = ~SYM[1] + 1) begin : map_~SYM[2]
+    ~INST 0
+      ~OUTPUT <= ~RESULT[~SYM[1]]~ ~TYPEL[~TYPO]~
+      ~INPUT  <= ~SYM[0][~SYM[1]]~ ~TYPEL[~TYP[1]]~
+    ~INST
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.zipWith"
+    , "type"      : "zipWith :: (a -> b -> c) -> Vec n a -> Vec n b -> Vec n c"
+    , "templateD" :
+"// zipWith
+~SIGD[~SYM[0]][1];
+~SIGD[~SYM[1]][2];
+assign ~SYM[0] = ~ARG[1];
+assign ~SYM[1] = ~ARG[2];
+
+genvar ~SYM[2];
+generate
+  for (~SYM[2] = 0; ~SYM[2] < $size(~RESULT); ~SYM[2] = ~SYM[2] + 1) begin : zipWith_~SYM[2]
+    ~INST 0
+      ~OUTPUT <= ~RESULT[~SYM[2]]~ ~TYPEL[~TYPO]~
+      ~INPUT  <= ~SYM[0][~SYM[2]]~ ~TYPEL[~TYP[1]]~
+      ~INPUT  <= ~SYM[1][~SYM[2]]~ ~TYPEL[~TYP[2]]~
+    ~INST
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.index_int"
+    , "type"      : "index_integer :: KnownNat n => Vec n a -> Int -> a"
+    , "templateD" :
+"// index_integer
+~SIGD[~SYM[0]][1];
+~SIGD[~SYM[1]][2];
+
+assign ~SYM[0] = ~ARG[1];
+assign ~SYM[1] = ~ARG[2];
+
+
+always_comb begin
+// pragma translate_off
+  if (~SYM[1] < $low(~SYM[0]) || ~SYM[1] > $high(~SYM[0])) begin
+    $display(\"Index: %d, is out of bounds: %d to %d\", ~SYM[1], $low(~SYM[0]), $high(~SYM[0]));
+    ~RESULT = ~ERRORO;
+  end else begin
+  // pragma translate_on
+    ~RESULT = ~SYM[0][~SYM[1]];
+  // pragma translate_off
+  end
+// pragma translate_on
+end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.replace_int"
+    , "type"      : "replace_int :: KnownNat n => Vec n a -> Int -> a -> Vec n a"
+    , "templateD" :
+"// replace_integer
+~SIGD[~SYM[0]][2];
+assign ~SYM[0] = ~ARG[2];
+
+~SIGD[~SYM[1]][1];
+always_comb begin
+  ~SYM[1] = ~ARG[1];
+  // pragma translate_off
+  if (~SYM[0] < $low(~SYM[1]) || ~SYM[0] > $high(~SYM[1])) begin
+    $display(\"Index: %d, is out of bounds: %d to %d\", ~SYM[0], $low(~SYM[1]), $high(~SYM[1]));
+    ~SYM[1] = ~ERROR[1];
+  end else begin
+    // pragma translate_on
+    ~SYM[1][~SYM[0]] = ~ARG[3];
+    // pragma translate_off
+  end
+  // pragma translate_on
+end
+
+assign ~RESULT = ~SYM[1];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.maxIndex"
+    , "type"      : "maxIndex :: KnownNat n => Vec n a -> Integer"
+    , "templateE" : "~LIT[0] - 1"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.length"
+    , "type"      : "length :: KnownNat n => Vec n a -> Integer"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.replicate"
+    , "type"      : "replicate :: SNat n -> a -> Vec n a"
+    , "templateE" : "'{~LIT[0] {~ARG[1]}}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.reverse"
+    , "type"      : "reverse :: Vec n a -> Vec n a"
+    , "templateD" :
+"// reverse
+~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1] = 0; ~SYM[1] < $size(~SYM[0]); ~SYM[1] = ~SYM[1] + 1) begin : reverse_~SYM[2]
+    assign ~RESULT[$high(~SYM[0]) - ~SYM[1]] = ~SYM[0][~SYM[1]];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.lazyV"
+    , "type"      : "lazyV :: KnownNat n => Vec n a -> Vec n a"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Vector.concatBitVector#"
+    , "type" :
+"concatBitVector# :: KnownNat m           -- ARG[0]
+                  => Vec n (BitVector m)  -- ARG[1]
+                  -> BitVector (n * m)"
+    , "templateD" :
+"// concatBitVector
+~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1] = 0; ~SYM[1] < $size(~SYM[0]); ~SYM[1] = ~SYM[1] + 1) begin : concatBitVector_~SYM[2]
+    assign ~RESULT[((~SYM[1] * ~LIT[0]) + ~LIT[0] - 1) : (~SYM[1] * ~LIT[0])] = ~SYM[0][~SYM[1]];
+  end
+endgenerate"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Vector.unconcatBitVector#"
+    , "type" :
+"unconcatBitVector# :: (KnownNat n, KnownNat m) -- (ARG[0],ARG[1])
+                    => BitVector (n * m)        -- ARG[2]
+                    -> Vec n (BitVector m)"
+    , "templateD" :
+"// unconcatBitVector
+~SIGD[~SYM[0]][2];
+assign ~SYM[0] = ~ARG[2];
+
+genvar ~SYM[1];
+generate
+  for (~SYM[1] = 0; ~SYM[1] < $size(~RESULT); ~SYM[1] = ~SYM[1] + 1) begin : unconcatBitVector_~SYM[2]
+    assign ~RESULT[~SYM[1]] = ~SYM[0][((~SYM[1] * ~LIT[1]) + ~LIT[1] - 1) : (~SYM[1] * ~LIT[1])];
+  end
+endgenerate"
+    }
+  }
+]
diff --git a/primitives/Control.Exception.Base.json b/primitives/Control.Exception.Base.json
new file mode 100644
--- /dev/null
+++ b/primitives/Control.Exception.Base.json
@@ -0,0 +1,25 @@
+[ { "BlackBox" :
+    { "name"      : "Control.Exception.Base.patError"
+    , "type"      : "patError :: Addr# -> a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "Control.Exception.Base.irrefutPatError"
+    , "type"      : "irrefutPatError :: Addr# -> a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "Control.Exception.Base.recSelError"
+    , "type"      : "recSelError :: Addr# -> a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "Control.Exception.Base.absentError"
+    , "type"      : "absentError :: Addr# -> a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+]
diff --git a/primitives/GHC.Base.json b/primitives/GHC.Base.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Base.json
@@ -0,0 +1,56 @@
+[ { "Primitive" :
+    { "name"      : "GHC.Base.$"
+    , "primType"  : "Function"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Base.quotInt"
+    , "type"      : "quotInt :: Int -> Int -> Int"
+    , "templateE" : "~ARG[0] / ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Base.remInt"
+    , "type"      : "remInt :: Int -> Int -> Int"
+    , "templateE" : "~ARG[0] % ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Base.divInt"
+    , "type"      : "divInt :: Int -> Int -> Int"
+    , "templateD" :
+"// divInt
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// divide (rounds towards zero)
+assign ~SYM[0] = ~ARG[0] / ~ARG[1];
+
+// round toward minus infinity
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ? ~SYM[0] : ~SYM[0] - 32'sd1;"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Base.modInt"
+    , "type"      : "modInt :: Int -> Int -> Int"
+    , "templateD" :
+"// modInt
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// remainder
+assign ~SYM[0] = ~ARG[0] % ~ARG[1];
+
+// modulo
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ?
+                 ~SYM[0] :
+                 (~ARG[1] == 32'sd0 ? 32'sd0 : ~SYM[0] + ~ARG[1]);"
+    }
+  }
+]
diff --git a/primitives/GHC.CString.json b/primitives/GHC.CString.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.CString.json
@@ -0,0 +1,11 @@
+[ { "Primitive" :
+    { "name"     : "GHC.CString.unpackCString#"
+    , "primType" : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"     : "GHC.CString.unpackCStringUtf8#"
+    , "primType" : "Function"
+    }
+  }
+]
diff --git a/primitives/GHC.Classes.json b/primitives/GHC.Classes.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Classes.json
@@ -0,0 +1,93 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.Classes.eqInt"
+    , "type"      : "eqInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.neInt"
+    , "type"      : "neInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.gtInt"
+    , "type"      : "gtInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.geInt"
+    , "type"      : "geInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.ltInt"
+    , "type"      : "ltInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.leInt"
+    , "type"      : "leInt :: Int -> Int -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.&&"
+    , "type"      : "(&&) :: Bool -> Bool -> Bool"
+    , "templateE" : "~ARG[0] & ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.||"
+    , "type"      : "(::) :: Bool -> Bool -> Bool"
+    , "templateE" : "~ARG[0] | ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.not"
+    , "type"      : "not :: Bool -> Bool"
+    , "templateE" : "~ ~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.divInt#"
+    , "type"      : "divInt# :: Int# -> Int# -> Int#"
+    , "templateD" :
+"// divInt
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// divide (rounds towards zero)
+assign ~SYM[0] = ~ARG[0] / ~ARG[1];
+
+// round toward minus infinity
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ? ~SYM[0] : ~SYM[0] - 32'sd1;"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Classes.modInt#"
+    , "type"      : "modInt# :: Int# -> Int# -> Int#"
+    , "templateD" :
+"// modInt
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// remainder
+assign ~SYM[0] = ~ARG[0] % ~ARG[1];
+
+// modulo
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ?
+                 ~SYM[0] :
+                 (~ARG[1] == 32'sd0 ? 32'sd0 : ~SYM[0] + ~ARG[1]);"
+    }
+  }
+]
diff --git a/primitives/GHC.Err.json b/primitives/GHC.Err.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Err.json
@@ -0,0 +1,13 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.Err.error"
+    , "type"      : "error :: [Char] -> a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Err.undefined"
+    , "type"      : "undefined :: a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+]
diff --git a/primitives/GHC.Integer.Type.json b/primitives/GHC.Integer.Type.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Integer.Type.json
@@ -0,0 +1,177 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.smallInteger"
+    , "type"      : "smallInteger :: Int# -> Integer"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.integerToInt"
+    , "type"      : "integerToInt :: Integer -> Int#"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.plusInteger"
+    , "type"      : "plusInteger :: Integer -> Integer -> Integer"
+    , "templateE" : "~ARG[0] + ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.minusInteger"
+    , "type"      : "minusInteger :: Integer -> Integer -> Integer"
+    , "templateE" : "~ARG[0] - ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.timesInteger"
+    , "type"      : "timesInteger :: Integer -> Integer -> Integer"
+    , "templateE" : "~ARG[0] * ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.negateInteger"
+    , "type"      : "negateInteger :: Integer -> Integer"
+    , "templateE" : "-~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.absInteger"
+    , "type"      : "absInteger :: Integer -> Integer"
+    , "templateE" : "~ARG[0] < 32'sd0 ? -~ARG[0] : ~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.divInteger"
+    , "type"      : "divInteger :: Integer -> Integer -> Integer"
+    , "templateD" :
+"// divInteger
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// divide (rounds towards zero)
+assign ~SYM[0] = ~ARG[0] / ~ARG[1];
+
+// round toward minus infinity
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ? ~SYM[0] : ~SYM[0] - 32'sd1;"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.modInteger"
+    , "type"      : "modInteger :: Integer -> Integer -> Integer"
+    , "templateD" :
+"// modInteger
+~SIGD[~SYM[0]][0];
+~SIGD[~SYM[1]][0];
+~SIGD[~SYM[2]][1];
+
+// remainder
+assign ~SYM[0] = ~ARG[0] % ~ARG[1];
+
+// modulo
+assign ~SYM[1] = ~ARG[0];
+assign ~SYM[2] = ~ARG[1];
+assign ~RESULT = (~SYM[1][31] == ~SYM[2][31]) ?
+                 ~SYM[0] :
+                 (~ARG[1] == 32'sd0 ? 32'sd0 : ~SYM[0] + ~ARG[1]);"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.quotInteger"
+    , "type"      : "quotInteger :: Integer -> Integer -> Integer"
+    , "templateE" : "~ARG[0] / ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.remInteger"
+    , "type"      : "remInteger :: Integer -> Integer -> Integer"
+    , "templateE" : "~ARG[0] % ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.eqInteger"
+    , "type"      : "eqInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] == ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.neqInteger"
+    , "type"      : "neqInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] != ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.leInteger"
+    , "type"      : "leInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] <= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.gtInteger"
+    , "type"      : "gtInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] > ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.ltInteger"
+    , "type"      : "ltInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] < ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.geInteger"
+    , "type"      : "geInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "~ARG[0] >= ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.eqInteger#"
+    , "type"      : "eqInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] == ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.neqInteger#"
+    , "type"      : "neqInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] != ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.leInteger#"
+    , "type"      : "leInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] <= ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.gtInteger#"
+    , "type"      : "gtInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] > ~ARG[1] ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.ltInteger#"
+    , "type"      : "ltInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] < ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.geInteger#"
+    , "type"      : "geInteger :: Integer -> Integer -> Bool"
+    , "templateE" : "(~ARG[0] >= ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.shiftRInteger"
+    , "type"      : "shiftRInteger :: Integer -> Int# -> Integer"
+    , "templateE" : "~ARG[0] >>> ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Integer.Type.shiftLInteger"
+    , "type"      : "shiftLInteger :: Integer -> Int# -> Integer"
+    , "templateE" : "~ARG[0] <<< ~ARG[1]"
+    }
+  }
+]
diff --git a/primitives/GHC.Prim.json b/primitives/GHC.Prim.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Prim.json
@@ -0,0 +1,89 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.Prim.+#"
+    , "type"      : "(+#) :: Int# -> Int# -> Int#"
+    , "templateE" : "~ARG[0] + ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.-#"
+    , "type"      : "(-#) :: Int# -> Int# -> Int#"
+    , "templateE" : "~ARG[0] - ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.*#"
+    , "type"      : "(*#) :: Int# -> Int# -> Int#"
+    , "templateE" : "~ARG[0] * ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.quotInt#"
+    , "type"      : "quotInt# :: Int# -> Int# -> Int#"
+    , "templateE" : "~ARG[0] / ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.remInt#"
+    , "type"      : "remInt# :: Int# -> Int# -> Int#"
+    , "templateE" : "~ARG[0] % ~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.negateInt#"
+    , "type"      : "negateInt# :: Int# -> Int#"
+    , "templateE" : "-~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.>#"
+     , "type"      : "(>#) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] > ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.>=#"
+    , "type"      : "(>=#) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] >= ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.==#"
+    , "type"      : "(==) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] == ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim./=#"
+    , "type"      : "(/=#) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] != ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.<#"
+    , "type"      : "(<#) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] < ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.<=#"
+    , "type"      : "(<=#) :: Int# -> Int# -> Bool"
+    , "templateE" : "(~ARG[0] <= ~ARG[1]) ? 32'sd1 : 32'sd0"
+    }
+  }
+, { "Primitive" :
+    { "name"     : "GHC.Prim.dataToTag#"
+    , "primType" : "Function"
+    }
+  }
+, { "Primitive" :
+    { "name"     : "GHC.Prim.tagToEnum#"
+    , "primType" : "Function"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Prim.unsafeCoerce#"
+    , "type"      : "unsafeCoerce# :: a -> b"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+]
diff --git a/primitives/GHC.Real.json b/primitives/GHC.Real.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Real.json
@@ -0,0 +1,19 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.Real.divZeroError"
+    , "type"      : "divZeroError :: a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Real.ratioZeroDenominatorError"
+    , "type"      : "ratioZeroDenominatorError :: a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "GHC.Real.overflowError"
+    , "type"      : "overflowError :: a"
+    , "templateE" : "~ERRORO"
+    }
+  }
+]
diff --git a/primitives/GHC.Typelits.json b/primitives/GHC.Typelits.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Typelits.json
@@ -0,0 +1,7 @@
+[ { "BlackBox" :
+    { "name"      : "GHC.TypeLits.natVal"
+    , "type"      : "natVal :: forall n proxy. KnownNat n => proxy n -> Integer"
+    , "templateE" : "~LIT[0]"
+    }
+  }
+]
diff --git a/primitives/GHC.Types.json b/primitives/GHC.Types.json
new file mode 100644
--- /dev/null
+++ b/primitives/GHC.Types.json
@@ -0,0 +1,11 @@
+[ { "Primitive" :
+    { "name"      : "GHC.Types.Eq#"
+    , "primType"  : "Constructor"
+    }
+  }
+, { "Primitive" :
+    { "name"      : "GHC.Types.MkCoercible"
+    , "primType"  : "Constructor"
+    }
+  }
+]
diff --git a/primitives/Unsafe.Coerce.json b/primitives/Unsafe.Coerce.json
new file mode 100644
--- /dev/null
+++ b/primitives/Unsafe.Coerce.json
@@ -0,0 +1,7 @@
+[ { "BlackBox" :
+    { "name"      : "Unsafe.Coerce.unsafeCoerce"
+    , "type"      : "unsafeCoerce :: a -> b"
+    , "templateE" : "~ARG[0]"
+    }
+  }
+]
diff --git a/src/CLaSH/Backend/SystemVerilog.hs b/src/CLaSH/Backend/SystemVerilog.hs
new file mode 100644
--- /dev/null
+++ b/src/CLaSH/Backend/SystemVerilog.hs
@@ -0,0 +1,458 @@
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecursiveDo       #-}
+{-# LANGUAGE TemplateHaskell   #-}
+{-# LANGUAGE TupleSections     #-}
+{-# LANGUAGE ViewPatterns      #-}
+
+-- | Generate SystemVerilog for assorted Netlist datatypes
+module CLaSH.Backend.SystemVerilog (SystemVerilogState) where
+
+import qualified Control.Applicative                  as A
+import           Control.Lens                         hiding (Indexed)
+import           Control.Monad                        (join,liftM,zipWithM)
+import           Control.Monad.State                  (State)
+import           Data.Graph.Inductive                 (Gr, mkGraph, topsort')
+import           Data.HashMap.Lazy                    (HashMap)
+import qualified Data.HashMap.Lazy                    as HashMap
+import           Data.HashSet                         (HashSet)
+import qualified Data.HashSet                         as HashSet
+import           Data.List                            (mapAccumL,nubBy)
+import           Data.Maybe                           (catMaybes,mapMaybe)
+import           Data.Text.Lazy                       (unpack)
+import           Text.PrettyPrint.Leijen.Text.Monadic
+
+import           CLaSH.Backend
+import           CLaSH.Netlist.BlackBox.Util          (extractLiterals, renderBlackBox)
+import           CLaSH.Netlist.Types
+import           CLaSH.Netlist.Util
+import           CLaSH.Util                           (curLoc, makeCached, (<:>))
+
+#ifdef CABAL
+import qualified Paths_clash_systemverilog
+#else
+import qualified System.FilePath
+#endif
+
+-- | State for the 'CLaSH.Backend.SystemVerilog.SystemVerilogM' monad:
+data SystemVerilogState =
+  SystemVerilogState
+    { _tyCache   :: HashSet HWType -- ^ Previously encountered  HWTypes
+    , _tyCount   :: Int -- ^ Product type counter
+    , _nameCache :: HashMap HWType Doc -- ^ Cache for previously generated product type names
+    }
+
+makeLenses ''SystemVerilogState
+
+instance Backend SystemVerilogState where
+  initBackend     = SystemVerilogState HashSet.empty 0 HashMap.empty
+#ifdef CABAL
+  primDir         = const (Paths_clash_systemverilog.getDataFileName "primitives")
+#else
+  primDir _       = return ("clash-systemverilog" System.FilePath.</> "primitives")
+#endif
+  extractTypes    = _tyCache
+  name            = const "systemverilog"
+  extension       = const ".sv"
+
+  genHDL          = genVerilog
+  mkTyPackage     = mkTyPackage_
+  hdlType         = verilogType
+  hdlTypeErrValue = verilogTypeErrValue
+  hdlTypeMark     = verilogTypeMark
+  hdlSig t ty     = sigDecl (text t) ty
+  inst            = inst_
+  expr            = expr_
+
+type SystemVerilogM a = State SystemVerilogState a
+
+-- | Generate VHDL for a Netlist component
+genVerilog :: Component -> SystemVerilogM (String,Doc)
+genVerilog c = (unpack cName,) A.<$> verilog
+  where
+    cName   = componentName c
+    verilog = "// Automatically generated SystemVerilog" <$$>
+              tyImports <$$>
+              module_ c
+
+-- | Generate a SystemVerilog package containing type definitions for the given HWTypes
+mkTyPackage_ :: [HWType]
+             -> SystemVerilogM Doc
+mkTyPackage_ hwtys =
+    "package types ;" <$>
+      indent 2 packageDec <$>
+      indent 2 funDecs <$>
+    "endpackage : types"
+  where
+    usedTys     = concatMap mkUsedTys hwtys
+    needsDec    = nubBy eqReprTy $ (hwtys ++ usedTys)
+    hwTysSorted = topSortHWTys needsDec
+    packageDec  = vcat $ mapM tyDec hwTysSorted
+    funDecs     = vcat $ mapM funDec hwTysSorted
+
+    eqReprTy :: HWType -> HWType -> Bool
+    eqReprTy (Vector n ty1) (Vector m ty2)
+      | m == n    = eqReprTy ty1 ty2
+      | otherwise = False
+    eqReprTy ty1 ty2
+      | isUnsigned ty1 && isUnsigned ty2 = typeSize ty1 == typeSize ty2
+      | otherwise                        = ty1 == ty2
+
+    isUnsigned :: HWType -> Bool
+    isUnsigned Bool          = True
+    isUnsigned (Unsigned _)  = True
+    isUnsigned (BitVector _) = True
+    isUnsigned (Index _)     = True
+    isUnsigned (Sum _ _)     = True
+    isUnsigned (SP _ _)      = True
+    isUnsigned _             = False
+
+mkUsedTys :: HWType
+        -> [HWType]
+mkUsedTys v@(Vector _ elTy)   = v : mkUsedTys elTy
+mkUsedTys p@(Product _ elTys) = p : concatMap mkUsedTys elTys
+mkUsedTys sp@(SP _ elTys)     = sp : concatMap mkUsedTys (concatMap snd elTys)
+mkUsedTys t                   = [t]
+
+topSortHWTys :: [HWType]
+             -> [HWType]
+topSortHWTys hwtys = sorted
+  where
+    nodes  = zip [0..] hwtys
+    nodesI = HashMap.fromList (zip hwtys [0..])
+    edges  = concatMap edge hwtys
+    graph  = mkGraph nodes edges :: Gr HWType ()
+    sorted = reverse $ topsort' graph
+
+    edge t@(Vector _ elTy) = maybe [] ((:[]) . (HashMap.lookupDefault (error $ $(curLoc) ++ "Vector") t nodesI,,()))
+                                      (HashMap.lookup elTy nodesI)
+    edge t@(Product _ tys) = let ti = HashMap.lookupDefault (error $ $(curLoc) ++ "Product") t nodesI
+                             in mapMaybe (\ty -> liftM (ti,,()) (HashMap.lookup ty nodesI)) tys
+    edge t@(SP _ ctys)     = let ti = HashMap.lookupDefault (error $ $(curLoc) ++ "SP") t nodesI
+                             in concatMap (\(_,tys) -> mapMaybe (\ty -> liftM (ti,,()) (HashMap.lookup ty nodesI)) tys) ctys
+    edge _                 = []
+
+tyDec :: HWType -> SystemVerilogM Doc
+tyDec (Vector n elTy) = "typedef" <+> verilogType elTy <+>  "array_of_" <> int n <> "_" <> tyName elTy <+> brackets (int 0 <> colon <> int (n-1)) <> semi
+
+tyDec ty@(Product _ tys) = prodDec
+  where
+    prodDec = "typedef struct {" <$>
+                indent 2 (vcat $ zipWithM (\x y -> sigDecl x y <> semi) selNames tys) <$>
+              "}" <+> tName <> semi
+
+    tName    = tyName ty
+    selNames = map (\i -> tName <> "_sel" <> int i) [0..]
+
+tyDec _ = empty
+
+funDec :: HWType -> SystemVerilogM Doc
+funDec (Clock _) = empty
+funDec (Reset _) = empty
+funDec t =
+  "function logic" <+> brackets (int (typeSize t - 1) <> colon <> int 0)  <+> verilogTypeMark t <> "_to_lv" <> parens (sigDecl "i" t) <> semi <$>
+  indent 2 (verilogTypeMark t <> "_to_lv" <+> "=" <+>
+    (case t of
+       Vector n elTy -> listBraces (sequence [verilogTypeMark elTy <> "_to_lv" <> parens ("i" <> brackets (int i)) | i <- [0..(n-1)]])
+       Product _ tys -> listBraces (zipWithM (\elTy i -> verilogTypeMark elTy <> "_to_lv" <> parens ("i" <> dot <> verilogTypeMark t <> "_sel" <> int i)) tys [0..])
+       _             -> "i")
+       <> semi) <$>
+  "endfunction"
+
+tyImports :: SystemVerilogM Doc
+tyImports = "import types:: * ;"
+
+module_ :: Component -> SystemVerilogM Doc
+module_ c =
+    "module" <+> text (componentName c) <> tupled ports <> semi <$>
+    indent 2 (inputPorts <$> outputPort <$$> decls (declarations c)) <$$> insts (declarations c) <$>
+    "endmodule"
+  where
+    ports = sequence
+          $ [ text i | (i,_) <- inputs c ] ++
+            [ text i | (i,_) <- hiddenPorts c] ++
+            [ text (fst $ output c) ]
+
+    inputPorts = case (inputs c ++ hiddenPorts c) of
+                   [] -> empty
+                   p  -> vcat (punctuate semi (sequence [ "input" <+> sigDecl (text i) ty | (i,ty) <- p ])) <> semi
+
+    outputPort = "output" <+> sigDecl (text (fst $ output c)) (snd $ output c) <> semi
+
+verilogType :: HWType -> SystemVerilogM Doc
+verilogType t = do
+  tyCache %= HashSet.insert t
+  case t of
+    (Vector _ _)  -> tyName t
+    (Product _ _) -> tyName t
+    Integer       -> verilogType (Signed 32)
+    (Signed n)    -> "logic signed" <+> brackets (int (n-1) <> colon <> int 0)
+    (Clock _)     -> "logic"
+    (Reset _)     -> "logic"
+    _             -> "logic" <+> brackets (int (typeSize t -1) <> colon <> int 0)
+
+sigDecl :: SystemVerilogM Doc -> HWType -> SystemVerilogM Doc
+sigDecl d t = verilogType t <+> d
+
+-- | Convert a Netlist HWType to the root of a Verilog type
+verilogTypeMark :: HWType -> SystemVerilogM Doc
+verilogTypeMark t = do
+  tyCache %= HashSet.insert t
+  tyName t
+
+tyName :: HWType -> SystemVerilogM Doc
+tyName Integer           = "integer_32"
+tyName Bool              = "logic_vector_1"
+tyName (Vector n elTy)   = "array_of_" <> int n <> "_" <> tyName elTy
+tyName (BitVector n)     = "logic_vector_" <> int n
+tyName t@(Index _)       = "logic_vector_" <> int (typeSize t)
+tyName (Signed n)        = "signed_" <> int n
+tyName (Unsigned n)      = "logic_vector_" <> int n
+tyName t@(Sum _ _)       = "logic_vector_" <> int (typeSize t)
+tyName t@(Product _ _)   = makeCached t nameCache prodName
+  where
+    prodName = do i <- tyCount <<%= (+1)
+                  "product" <> int i
+tyName t@(SP _ _)        = "logic_vector_" <> int (typeSize t)
+tyName (Clock _) = "logic"
+tyName (Reset _) = "logic"
+tyName t =  error $ $(curLoc) ++ "tyName: " ++ show t
+
+-- | Convert a Netlist HWType to an error VHDL value for that type
+verilogTypeErrValue :: HWType -> SystemVerilogM Doc
+verilogTypeErrValue Bool                = "1'bx"
+verilogTypeErrValue Integer         = "{32 {1'bx}}"
+verilogTypeErrValue (Unsigned n)    = braces (int n <+> braces "1'bx")
+verilogTypeErrValue (Signed n)      = braces (int n <+> braces "1'bx")
+verilogTypeErrValue (Vector n elTy) = "'" <> braces (int n <+> braces (verilogTypeErrValue elTy))
+verilogTypeErrValue t@(Sum _ _)     = braces (int (typeSize t) <+> braces "1'bx")
+verilogTypeErrValue (Product _ elTys)   = "'" <> listBraces (mapM verilogTypeErrValue elTys)
+verilogTypeErrValue (BitVector 1)   = "1'bx"
+verilogTypeErrValue (BitVector n)   = braces (int n <+> braces "1'bx")
+verilogTypeErrValue t@(SP _ _)      = braces (int (typeSize t) <+> braces "1'bx")
+verilogTypeErrValue e = error $ $(curLoc) ++ "no error value defined for: " ++ show e
+
+decls :: [Declaration] -> SystemVerilogM Doc
+decls [] = empty
+decls ds = do
+    dsDoc <- catMaybes A.<$> mapM decl ds
+    case dsDoc of
+      [] -> empty
+      _  -> punctuate' semi (A.pure dsDoc)
+
+decl :: Declaration -> SystemVerilogM (Maybe Doc)
+decl (NetDecl id_ ty) = Just A.<$> sigDecl (text id_) ty
+
+decl _ = return Nothing
+
+insts :: [Declaration] -> SystemVerilogM Doc
+insts [] = empty
+insts is = indent 2 . vcat . punctuate linebreak . fmap catMaybes $ mapM inst_ is
+
+-- | Turn a Netlist Declaration to a SystemVerilog concurrent block
+inst_ :: Declaration -> SystemVerilogM (Maybe Doc)
+inst_ (Assignment id_ e) = fmap Just $
+  "assign" <+> text id_ <+> equals <+> expr_ False e <> semi
+
+inst_ (CondAssignment id_ scrut es) = fmap Just $
+    "always_comb begin" <$>
+    indent 2 ("case" <> parens (expr_ True scrut) <$>
+                (indent 2 $ vcat $ punctuate semi (conds es)) <> semi <$>
+              "endcase") <$>
+    "end"
+  where
+    conds :: [(Maybe Expr,Expr)] -> SystemVerilogM [Doc]
+    conds []                = return []
+    conds [(_,e)]           = ("default" <+> colon <+> text id_ <+> equals <+> expr_ False e) <:> return []
+    conds ((Nothing,e):_)   = ("default" <+> colon <+> text id_ <+> equals <+> expr_ False e) <:> return []
+    conds ((Just c ,e):es') = (expr_ True c <+> colon <+> text id_ <+> equals <+> expr_ False e) <:> conds es'
+
+inst_ (InstDecl nm lbl pms) = fmap Just $
+    text nm <+> text lbl <$$> pms' <> semi
+  where
+    pms' = tupled $ sequence [dot <> text i <+> parens (expr_ False e) | (i,e) <- pms]
+
+inst_ (BlackBoxD _ bs bbCtx) = do
+  t <- renderBlackBox bs bbCtx
+  fmap Just (string t)
+
+inst_ (NetDecl _ _) = return Nothing
+
+-- | Turn a Netlist expression into a SystemVerilog expression
+expr_ :: Bool -- ^ Enclose in parenthesis?
+      -> Expr -- ^ Expr to convert
+      -> SystemVerilogM Doc
+expr_ _ (Literal sizeM lit)                           = exprLit sizeM lit
+expr_ _ (Identifier id_ Nothing)                      = text id_
+expr_ _ (Identifier id_ (Just (Indexed (ty@(SP _ args),dcI,fI)))) = fromSLV argTy id_ start end
+  where
+    argTys   = snd $ args !! dcI
+    argTy    = argTys !! fI
+    argSize  = typeSize argTy
+    other    = otherSize argTys (fI-1)
+    start    = typeSize ty - 1 - conSize ty - other
+    end      = start - argSize + 1
+
+expr_ _ (Identifier id_ (Just (Indexed (ty@(Product _ _),_,fI)))) = text id_ <> dot <> verilogTypeMark ty <> "_sel" <> int fI
+expr_ _ (Identifier id_ (Just (DC (ty@(SP _ _),_)))) = text id_ <> brackets (int start <> colon <> int end)
+  where
+    start = typeSize ty - 1
+    end   = typeSize ty - conSize ty
+
+expr_ _ (Identifier id_ (Just _))                      = text id_
+
+expr_ _ (DataCon (Vector 1 _) _ [e]) = "'" <> braces (expr_ False e)
+expr_ _ e@(DataCon (Vector n _) _ [e1,e2]) = "'" <> case vectorChain e of
+                                                     Just es -> listBraces (mapM (expr_ False) es)
+                                                     Nothing -> let e2' = expr_ False e2
+                                                                in  listBraces $ sequence ((expr_ False e1):[e2' <> brackets (int i) | i <- [0..(n-2)] ])
+
+expr_ _ (DataCon ty@(SP _ args) (DC (_,i)) es) = assignExpr
+  where
+    argTys     = snd $ args !! i
+    dcSize     = conSize ty + sum (map typeSize argTys)
+    dcExpr     = expr_ False (dcToExpr ty i)
+    argExprs   = zipWith toSLV argTys es
+    extraArg   = case typeSize ty - dcSize of
+                   0 -> []
+                   n -> [exprLit (Just (ty,n)) (NumLit 0)]
+    assignExpr = braces (hcat $ punctuate comma $ sequence (dcExpr:argExprs ++ extraArg))
+
+expr_ _ (DataCon ty@(Sum _ _) (DC (_,i)) []) = int (typeSize ty) <> "'d" <> int i
+expr_ _ (DataCon ty@(Product _ _) _ es) = "'" <> listBraces (zipWithM (\i e -> verilogTypeMark ty <> "_sel" <> int i <> colon <+> expr_ False e) [0..] es)
+
+expr_ _ (BlackBoxE pNm _ bbCtx _)
+  | pNm == "CLaSH.Sized.Internal.Signed.fromInteger#"
+  , [Literal _ (NumLit n), Literal _ i] <- extractLiterals bbCtx
+  = exprLit (Just (Signed (fromInteger n),fromInteger n)) i
+
+expr_ _ (BlackBoxE pNm _ bbCtx _)
+  | pNm == "CLaSH.Sized.Internal.Unsigned.fromInteger#"
+  , [Literal _ (NumLit n), Literal _ i] <- extractLiterals bbCtx
+  = exprLit (Just (Unsigned (fromInteger n),fromInteger n)) i
+
+expr_ _ (BlackBoxE pNm _ bbCtx _)
+  | pNm == "CLaSH.Sized.Internal.BitVector.fromInteger#"
+  , [Literal _ (NumLit n), Literal _ i] <- extractLiterals bbCtx
+  = exprLit (Just (BitVector (fromInteger n),fromInteger n)) i
+
+expr_ b (BlackBoxE _ bs bbCtx b') = do
+  t <- renderBlackBox bs bbCtx
+  parenIf (b || b') $ string t
+
+expr_ _ (DataTag Bool (Left id_))          = text id_ <> brackets (int 0)
+expr_ _ (DataTag Bool (Right id_))         = "$signed" <> parens (listBraces (sequence [braces (int 31 <+> braces "1'b0"),text id_]))
+
+expr_ _ (DataTag (Sum _ _) (Left id_))     = "$unsigned" <> parens (text id_)
+expr_ _ (DataTag (Sum _ _) (Right id_))    = "$signed" <> parens (text id_)
+
+expr_ _ (DataTag (Product _ _) (Right _))  = "32'sd0"
+
+expr_ _ (DataTag hty@(SP _ _) (Right id_)) = "$signed" <> parens
+                                               (text id_ <> brackets
+                                               (int start <> colon <> int end))
+  where
+    start = typeSize hty - 1
+    end   = typeSize hty - conSize hty
+
+expr_ _ (DataTag (Vector 0 _) (Right _)) = "32'sd0"
+expr_ _ (DataTag (Vector _ _) (Right _)) = "32'sd1"
+
+expr_ _ e = error $ $(curLoc) ++ (show e) -- empty
+
+otherSize :: [HWType] -> Int -> Int
+otherSize _ n | n < 0 = 0
+otherSize []     _    = 0
+otherSize (a:as) n    = typeSize a + otherSize as (n-1)
+
+vectorChain :: Expr -> Maybe [Expr]
+vectorChain (DataCon (Vector 0 _) _ _)        = Just []
+vectorChain (DataCon (Vector 1 _) _ [e])     = Just [e]
+vectorChain (DataCon (Vector _ _) _ [e1,e2]) = Just e1 <:> vectorChain e2
+vectorChain _                                       = Nothing
+
+exprLit :: Maybe (HWType,Size) -> Literal -> SystemVerilogM Doc
+exprLit Nothing         (NumLit i) = integer i
+exprLit (Just (hty,sz)) (NumLit i) = case hty of
+                                       Unsigned _   -> int sz <> "'d" <> integer i
+                                       Signed _
+                                        | i < 0     -> "-" <> int sz <> "'sd" <> integer (abs i)
+                                        | otherwise -> int sz <> "'sd" <> integer i
+                                       _            -> int sz <> "'b" <> blit
+
+  where
+    blit = bits (toBits sz i)
+exprLit _             (BoolLit t)  = if t then "1'b1" else "1'b0"
+exprLit _             (BitLit b)   = "1'b" <> bit_char b
+exprLit _             l            = error $ $(curLoc) ++ "exprLit: " ++ show l
+
+toBits :: Integral a => Int -> a -> [Bit]
+toBits size val = map (\x -> if odd x then H else L)
+                $ reverse
+                $ take size
+                $ map (`mod` 2)
+                $ iterate (`div` 2) val
+
+bits :: [Bit] -> SystemVerilogM Doc
+bits = hcat . mapM bit_char
+
+bit_char :: Bit -> SystemVerilogM Doc
+bit_char H = char '1'
+bit_char L = char '0'
+bit_char U = char 'U'
+bit_char Z = char 'Z'
+
+toSLV :: HWType -> Expr -> SystemVerilogM Doc
+toSLV t@(Product _ tys) (Identifier id_ Nothing) = do
+    selIds' <- sequence selIds
+    listBraces (zipWithM toSLV tys selIds')
+  where
+    tName    = verilogTypeMark t
+    selNames = map (fmap (displayT . renderOneLine) ) [text id_ <> dot <> tName <> "_sel" <> int i | i <- [0..(length tys)-1]]
+    selIds   = map (fmap (\n -> Identifier n Nothing)) selNames
+toSLV (Product _ tys) (DataCon _ _ es) = listBraces (zipWithM toSLV tys es)
+
+toSLV (Vector n elTy) (Identifier id_ Nothing) = do
+    selIds' <- sequence (reverse selIds)
+    listBraces (mapM (toSLV elTy) selIds')
+  where
+    selNames = map (fmap (displayT . renderOneLine) ) $ reverse [text id_ <> brackets (int i) | i <- [0 .. (n-1)]]
+    selIds   = map (fmap (`Identifier` Nothing)) selNames
+toSLV (Vector n elTy) (DataCon _ _ es) = listBraces (zipWithM toSLV [elTy,Vector (n-1) elTy] es)
+
+toSLV _ e = expr_ False e
+
+fromSLV :: HWType -> Identifier -> Int -> Int -> SystemVerilogM Doc
+fromSLV t@(Product _ tys) id_ start _ = "'" <> listBraces (zipWithM (\s e -> s <> colon <+> e) selNames args)
+  where
+    tName      = tyName t
+    selNames   = [tName <> "_sel" <> int i | i <- [0..]]
+    argLengths = map typeSize tys
+    starts     = start : snd (mapAccumL ((join (,) .) . (-)) start argLengths)
+    ends       = map (+1) (tail starts)
+    args       = zipWith3 (`fromSLV` id_) tys starts ends
+
+fromSLV t@(Vector n elTy) id_ start _ = verilogTypeMark t <> "'" <> parens ("'" <> listBraces (fmap reverse args))
+  where
+    argLength = typeSize elTy
+    starts    = take (n + 1) $ iterate (subtract argLength) start
+    ends      = map (+1) (tail starts)
+    args      = zipWithM (fromSLV elTy id_) starts ends
+
+fromSLV Integer    id_ start end = fromSLV (Signed 32) id_ start end
+fromSLV (Signed _) id_ start end = "$signed" <> parens (text id_ <> brackets (int start <> colon <> int end))
+
+fromSLV _ id_ start end = text id_ <> brackets (int start <> colon <> int end)
+
+dcToExpr :: HWType -> Int -> Expr
+dcToExpr ty i = Literal (Just (ty,conSize ty)) (NumLit (toInteger i))
+
+listBraces :: Monad m => m [Doc] -> m Doc
+listBraces = encloseSep lbrace rbrace comma
+
+parenIf :: Monad m => Bool -> m Doc -> m Doc
+parenIf True  = parens
+parenIf False = id
+
+punctuate' :: Monad m => m Doc -> m [Doc] -> m Doc
+punctuate' s d = vcat (punctuate s d) <> s
