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.5 *June 3rd 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-verilog`
+  * 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-verilog.cabal b/clash-verilog.cabal
new file mode 100644
--- /dev/null
+++ b/clash-verilog.cabal
@@ -0,0 +1,80 @@
+Name:                 clash-verilog
+Version:              0.5.5
+Synopsis:             CAES Language for Synchronous Hardware - Verilog backend
+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:
+  .
+  * Verilog 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.Driver.TopWrapper.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
+  CPP-Options:        -DCABAL
+
+  Build-depends:      base                    >= 4.6.0.1 && < 5,
+                      clash-lib               >= 0.5.6,
+                      clash-prelude           >= 0.8,
+                      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.Verilog
+
+  other-modules:      Paths_clash_verilog
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,61 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.clockGen"
+    , "templateD" :
+"// pragma translate_off
+reg ~TYPO ~SYM[0];
+always begin
+  ~SYM[0] = 0;
+  #~LIT[0] forever begin
+    ~SYM[0] = ~ ~SYM[0];
+    #~LIT[1];
+    ~SYM[0] = ~ ~SYM[0];
+    #~LIT[2];
+  end
+end
+assign ~RESULT = ~SYM[0];
+// pragma translate_on"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.resetGen"
+    , "templateD" :
+"// pragma translate_off
+reg ~TYPO ~SYM[0];
+initial begin
+  ~SYM[0] = 0;
+  #~LIT[0] ~SYM[0] = 1;
+end
+assign ~RESULT = ~SYM[0];
+// pragma translate_on"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.doneGen"
+    , "templateD" :
+"assign ~RESULT = ~ARG[0];
+
+// pragma translate_off
+always @(*) begin
+  if (~ARG[0] == 1'b1) begin
+    $finish;
+  end
+end
+// pragma translate_on
+"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Driver.TestbenchGen.finishedGen"
+    , "templateD" :
+"reg ~TYPO ~SYM[0];
+always begin
+// pragma translate_off
+  ~SYM[0] <= 1'b0;
+  #~LIT[0]
+// pragma translate_on
+  ~SYM[0] = 1'b1;
+end
+assign ~RESULT = ~SYM[0];"
+    }
+  }
+]
diff --git a/primitives/CLaSH.Driver.TopWrapper.json b/primitives/CLaSH.Driver.TopWrapper.json
new file mode 100644
--- /dev/null
+++ b/primitives/CLaSH.Driver.TopWrapper.json
@@ -0,0 +1,20 @@
+[ { "BlackBox" :
+    { "name"      : "CLaSH.TopWrapper.syncReset"
+    , "templateD" :
+"// reset ~RESULT is asynchronously asserted, but synchronously de-asserted
+reg ~SIGD[~SYM[0]][0];
+reg ~SIGD[~SYM[1]][0];
+
+always @(posedge ~CLKO or negedge ~ARG[0])
+if (~ ~ARG[0]) begin
+  ~SYM[0] <= 1'b0;
+  ~SYM[1] <= 1'b0;
+end else begin
+  ~SYM[0] <= 1'b1;
+  ~SYM[1] <= ~SYM[0];
+end
+
+assign ~RESULT = ~SYM[1];"
+    }
+  }
+]
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,36 @@
+[ { "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
+reg ~TYPO ~SYM[0] [0:~LIT[0]-1];
+reg ~SIGD[~SYM[1]][7];
+
+reg ~TYP[3] ~SYM[2];
+integer ~SYM[3];
+initial begin
+  ~SYM[2] = ~ARG[3];
+  for (~SYM[3]=0; ~SYM[3] < ~LIT[0]; ~SYM[3] = ~SYM[3] + 1) begin
+    ~SYM[0][~LIT[0]-1-~SYM[3]] = ~SYM[2][~SYM[3]*~SIZE[~TYPO]+:~SIZE[~TYPO]];
+  end
+end
+
+always @(posedge ~CLK[2]) begin : blockRam_~COMPNAME_~SYM[4]
+  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\", ~ARG[3], ~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,74 @@
+[ { "BlackBox" :
+    { "name" : "CLaSH.Signal.Internal.register#"
+    , "type" :
+"register# :: SClock clk     -- ARG[0]
+           -> a              -- ARG[1]
+           -> Signal' clk a  -- ARG[2]
+           -> Signal' clk a"
+    , "templateD" :
+"// register
+reg ~SIGD[~SYM[0]][2];
+
+always @(posedge ~CLK[0] or negedge ~RST[0]) begin : register_~COMPNAME_~SYM[1]
+  if (~ ~RST[0]) begin
+    ~SYM[0] <= ~ARG[1];
+  end else begin
+    ~SYM[0] <= ~ARG[2];
+  end
+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" :
+"// regEn
+reg ~SIGD[~SYM[0]][3];
+
+always @(posedge ~CLK[0] or negedge ~RST[0]) begin : regEn_~COMPNAME_~SYM[1]
+  if (~ ~RST[0]) begin
+    ~SYM[0] <= ~ARG[1];
+  end else begin
+    if (~ARG[2]) begin
+      ~SYM[0] <= ~ARG[3];
+    end
+  end
+end
+
+assign ~RESULT = ~SYM[0];"
+    }
+  }
+
+, { "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,364 @@
+[ { "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
+wire ~SIGD[~SYM[0]][1];
+wire ~SIGD[~SYM[1]][2];
+
+assign ~SYM[0] = ~ARG[1];
+assign ~SYM[1] = ~ARG[2];
+
+reg ~TYPO ~SYM[2];
+// pragma translate_off
+always @(*) 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], 0, ~LIT[0]-1);
+    ~SYM[2] = ~ERRORO;
+  end else begin
+  // pragma translate_on
+    ~SYM[2] = ~SYM[0][~SYM[1]];
+  // pragma translate_off
+  end
+end
+assign ~RESULT = ~SYM[2];
+// 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 start
+reg ~TYPO ~SYM[0];
+wire ~TYPO ~SYM[1];
+wire ~TYP[2] ~SYM[2];
+wire ~TYP[3] ~SYM[3];
+
+assign ~SYM[1] = ~ARG[1];
+assign ~SYM[2] = ~ARG[2];
+assign ~SYM[3] = ~ARG[3];
+
+genvar ~SYM[4];
+for (~SYM[4]=0; ~SYM[4] < ~LIT[0]; ~SYM[4] = ~SYM[4] + 1) begin : replace_int_~SYM[5]
+  always @(*) begin
+    if (~SYM[2] == (~LIT[0] - 1 - ~SYM[4])) begin
+      ~SYM[0][~SYM[4]] = ~SYM[3];
+    end else begin
+      ~SYM[0][~SYM[4]] = ~SYM[1][~SYM[4]];
+    end
+  end
+end
+
+assign ~RESULT = ~SYM[0];
+// replaceBit end"
+    }
+  }
+, { "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
+wire ~SIGD[~SYM[0]][0];
+
+always @(*) 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
+wire ~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)"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "BlackBox" :
+    { "name" : "CLaSH.Sized.Internal.BitVector.msb#"
+    , "type" :
+"msb# :: KnownNat n  -- ARG[0]
+      => BitVector n -- ARG[1]
+      -> Bit"
+    , "templateD" :
+"// msb
+wire ~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
+wire ~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
+wire [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} << ~ARG[2];
+assign ~RESULT = ~SYM[0][2*~LIT[0]-1 : ~LIT[0]];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Internal.BitVector.rotateR#"
+    , "type"      : "rotateR# :: KnownNat n => BitVector n -> Int -> BitVector n"
+    , "templateD" :
+"// rotateR
+wire [2*~LIT[0]-1:0] ~SYM[0];
+assign ~SYM[0] = {~ARG[1],~ARG[1]} >> ~ARG[2];
+assign ~RESULT = ~SYM[0][~LIT[0]-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,259 @@
+[ { "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
+wire ~SIGD[~SYM[0]][1];
+wire ~SIGD[~SYM[1]][1];
+wire ~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
+wire ~SIGD[~SYM[0]][1];
+wire ~SIGD[~SYM[1]][1];
+wire ~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
+wire [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
+wire [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
+if (~LIT[1] < ~LIT[0]) begin
+  // truncate, sign preserving
+  wire ~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
+"
+    }
+  }
+, { "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
+wire [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
+wire [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,287 @@
+[ { "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
+wire ~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][~SIZE[~TYP[0]]-1:~SIZE[~TYP[0]]-~SIZE[~TYPO]];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.tail"
+    , "type"      : "tail :: Vec (n + 1) a -> Vec n a"
+    , "templateD" :
+"// tail
+wire ~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][~SIZE[~TYPO]-1 : 0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.last"
+    , "type"      : "Vec (n + 1) a -> a"
+    , "templateD" :
+"// last
+wire ~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][~SIZE[~TYPO]-1:0];"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.init"
+    , "type"      : "Vec (n + 1) a -> Vec n a"
+    , "templateD" :
+"// init
+wire ~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+assign ~RESULT = ~SYM[0][~SIZE[~TYP[0]]-1 : ~SIZE[~TYPEL[~TYP[0]]]];"
+    }
+  }
+, { "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 begin
+wire ~SIGD[~SYM[0]][4];
+assign ~SYM[0] = ~ARG[4];
+
+wire ~TYPEL[~TYPO] ~SYM[1] [0:~LENGTH[~TYP[4]]-1];
+genvar ~SYM[2];
+for (~SYM[2]=0; ~SYM[2] < ~LENGTH[~TYP[4]]; ~SYM[2]=~SYM[2]+1) begin : array_~SYM[3]
+  assign ~SYM[1][(~LENGTH[~TYP[4]]-1)-~SYM[2]] = ~SYM[0][~SYM[2]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]];
+end
+
+genvar ~SYM[4];
+for (~SYM[4]=0; ~SYM[4] < ~LIT[3]; ~SYM[4] = ~SYM[4] + 1) begin : select_~SYM[5]
+  assign ~RESULT[(~LIT[3]-1-~SYM[4])*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]] = ~SYM[1][~LIT[1] + (~LIT[2] * ~SYM[4])];
+end
+// select end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.++"
+    , "type"      : "(++) :: Vec n a -> Vec m a -> Vec (n + m) a"
+    , "templateE" : "{~ARG[0],~ARG[1]}"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.concat"
+    , "type"      : "concat :: Vec n (Vec m a) -> Vec (n * m) a"
+    , "templateD" : "~ARG[0]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.splitAt"
+    , "type"      : "splitAt :: SNat m -> Vec (m + n) a -> (Vec m a, Vec n a)"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "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)"
+    , "templateE" : "~ARG[2]"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.merge"
+    , "type"      : "merge :: Vec n a -> Vec n a -> Vec (n + n) a"
+    , "templateD" :
+"// merge begin
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][1];
+assign ~SYM[0] = ~ARG[0];
+assign ~SYM[1] = ~ARG[1];
+
+genvar ~SYM[2];
+for (~SYM[2] = 0; ~SYM[2] < ~LENGTH[~TYP[0]]; ~SYM[2] = ~SYM[2] + 1) begin : merge_~SYM[3]
+  assign ~RESULT[(2*~SYM[2]+1)*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]] = ~SYM[0][~SYM[2]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]];
+  assign ~RESULT[(2*~SYM[2])*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]]   = ~SYM[1][~SYM[2]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]];
+end
+// merge end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.map"
+    , "type"      : "map :: (a -> b) -> Vec n a -> Vec n b"
+    , "templateD" :
+"// map begin
+wire ~SIGD[~SYM[0]][1];
+assign ~SYM[0] = ~ARG[1];
+
+genvar ~SYM[1];
+for (~SYM[1]=0; ~SYM[1] < ~LENGTH[~TYPO]; ~SYM[1] = ~SYM[1] + 1) begin : map_~SYM[2]
+  ~INST 0
+    ~OUTPUT <= ~RESULT[~SYM[1]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]]~ ~TYPEL[~TYPO]~
+    ~INPUT  <= ~SYM[0][~SYM[1]*~SIZE[~TYPEL[~TYP[1]]]+:~SIZE[~TYPEL[~TYP[1]]]]~ ~TYPEL[~TYP[1]]~
+  ~INST
+end
+// map end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.zipWith"
+    , "type"      : "zipWith :: (a -> b -> c) -> Vec n a -> Vec n b -> Vec n c"
+    , "templateD" :
+"// zipWith start
+wire ~SIGD[~SYM[0]][1];
+wire ~SIGD[~SYM[1]][2];
+assign ~SYM[0] = ~ARG[1];
+assign ~SYM[1] = ~ARG[2];
+
+genvar ~SYM[2];
+for (~SYM[2] = 0; ~SYM[2] < ~LENGTH[~TYPO]; ~SYM[2] = ~SYM[2] + 1) begin : zipWith_~SYM[2]
+  ~INST 0
+    ~OUTPUT <= ~RESULT[~SYM[2]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]]~ ~TYPEL[~TYPO]~
+    ~INPUT  <= ~SYM[0][~SYM[2]*~SIZE[~TYPEL[~TYP[1]]]+:~SIZE[~TYPEL[~TYP[1]]]]~ ~TYPEL[~TYP[1]]~
+    ~INPUT  <= ~SYM[1][~SYM[2]*~SIZE[~TYPEL[~TYP[2]]]+:~SIZE[~TYPEL[~TYP[2]]]]~ ~TYPEL[~TYP[2]]~
+  ~INST
+end
+// zipWith end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.index_int"
+    , "type"      : "index_integer :: KnownNat n => Vec n a -> Int -> a"
+    , "templateD" :
+"// index_integer start
+wire ~TYPO ~SYM[0] [0:~LIT[0]-1];
+wire ~TYP[1] ~SYM[1];
+assign ~SYM[1] = ~ARG[1];
+genvar ~SYM[3];
+for (~SYM[3]=0; ~SYM[3] < ~LIT[0]; ~SYM[3]=~SYM[3]+1) begin : array_~SYM[4]
+  assign ~SYM[0][(~LIT[0]-1)-~SYM[3]] = ~SYM[1][~SYM[3]*~SIZE[~TYPO]+:~SIZE[~TYPO]];
+end
+
+wire ~TYP[2] ~SYM[2];
+assign ~SYM[2] = ~ARG[2];
+
+reg ~TYPO ~SYM[5];
+always @(*) begin
+// pragma translate_off
+  if (~SYM[2] < 0 || ~SYM[2] >= ~LIT[0]) begin
+    $display(\"Index: %d, is out of bounds: %d to %d\", ~SYM[2], 0, ~LIT[0]-1);
+    ~SYM[5] = ~ERRORO;
+  end else begin
+  // pragma translate_on
+    ~SYM[5] = ~SYM[0][~SYM[2]];
+  // pragma translate_off
+  end
+// pragma translate_on
+end
+assign ~RESULT = ~SYM[5];
+// index_integer end"
+    }
+  }
+, { "BlackBox" :
+    { "name"      : "CLaSH.Sized.Vector.replace_int"
+    , "type"      : "replace_int :: KnownNat n => Vec n a -> Int -> a -> Vec n a"
+    , "templateD" :
+"// replace_integer start
+reg ~TYPO ~SYM[0];
+wire ~TYPO ~SYM[1];
+wire ~TYP[2] ~SYM[2];
+wire ~TYP[3] ~SYM[3];
+
+assign ~SYM[1] = ~ARG[1];
+assign ~SYM[2] = ~ARG[2];
+assign ~SYM[3] = ~ARG[3];
+
+genvar ~SYM[4];
+for (~SYM[4]=0; ~SYM[4] < ~LIT[0]; ~SYM[4] = ~SYM[4] + 1) begin : replace_int_~SYM[5]
+  always @(*) begin
+    if (~SYM[2] == (~LIT[0] - 1 - ~SYM[4])) begin
+      ~SYM[0][~SYM[4]*~SIZE[~TYP[3]]+:~SIZE[~TYP[3]]] = ~SYM[3];
+    end else begin
+      ~SYM[0][~SYM[4]*~SIZE[~TYP[3]]+:~SIZE[~TYP[3]]] = ~SYM[1][~SYM[4]*~SIZE[~TYP[3]]+:~SIZE[~TYP[3]]];
+    end
+  end
+end
+
+assign ~RESULT = ~SYM[0];
+// replace_integer end"
+    }
+  }
+, { "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
+wire ~SIGD[~SYM[0]][0];
+assign ~SYM[0] = ~ARG[0];
+
+genvar ~SYM[1];
+for (~SYM[1] = 0; ~SYM[1] < ~LENGTH[~TYPO]; ~SYM[1] = ~SYM[1] + 1) begin : reverse_~SYM[2]
+  assign ~RESULT[(~LENGTH[~TYPO] - 1 - ~SYM[1])*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]] = ~SYM[0][~SYM[1]*~SIZE[~TYPEL[~TYPO]]+:~SIZE[~TYPEL[~TYPO]]];
+end"
+    }
+  }
+, { "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)"
+    , "templateE" : "~ARG[1]"
+    }
+  }
+, { "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)"
+    , "templateE" : "~ARG[2]"
+    }
+  }
+]
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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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
+wire ~SIGD[~SYM[0]][0];
+wire ~SIGD[~SYM[1]][0];
+wire ~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/Verilog.hs b/src/CLaSH/Backend/Verilog.hs
new file mode 100644
--- /dev/null
+++ b/src/CLaSH/Backend/Verilog.hs
@@ -0,0 +1,328 @@
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecursiveDo       #-}
+{-# LANGUAGE TemplateHaskell   #-}
+{-# LANGUAGE TupleSections     #-}
+{-# LANGUAGE ViewPatterns      #-}
+
+-- | Generate SystemVerilog for assorted Netlist datatypes
+module CLaSH.Backend.Verilog (VerilogState) where
+
+import qualified Control.Applicative                  as A
+import           Control.Monad.State                  (State)
+import qualified Data.HashSet                         as HashSet
+import           Data.Maybe                           (catMaybes)
+import           Data.Text.Lazy                       (unpack)
+import           Prelude                              hiding ((<$>))
+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, (<:>))
+
+#ifdef CABAL
+import qualified Paths_clash_verilog
+#else
+import qualified System.FilePath
+#endif
+
+-- | State for the 'CLaSH.Backend.Verilog.VerilogM' monad:
+data VerilogState = VerilogState
+
+instance Backend VerilogState where
+  initBackend     = VerilogState
+#ifdef CABAL
+  primDir         = const (Paths_clash_verilog.getDataFileName "primitives")
+#else
+  primDir _       = return ("clash-verilog" System.FilePath.</> "primitives")
+#endif
+  extractTypes    = const HashSet.empty
+  name            = const "verilog"
+  extension       = const ".v"
+
+  genHDL          = const genVerilog
+  mkTyPackage _ _ = return []
+  hdlType         = verilogType
+  hdlTypeErrValue = verilogTypeErrValue
+  hdlTypeMark     = verilogTypeMark
+  hdlSig t ty     = sigDecl (text t) ty
+  inst            = inst_
+  expr            = expr_
+
+type VerilogM a = State VerilogState a
+
+-- | Generate VHDL for a Netlist component
+genVerilog :: Component -> VerilogM (String,Doc)
+genVerilog c = (unpack cName,) A.<$> verilog
+  where
+    cName   = componentName c
+    verilog = "// Automatically generated Verilog-2005" <$$>
+              module_ c
+
+module_ :: Component -> VerilogM Doc
+module_ c =
+    "module" <+> text (componentName c) <> tupled ports <> semi <$>
+    indent 2 (inputPorts <$> outputPorts <$$> decls (declarations c)) <$$> insts (declarations c) <$>
+    "endmodule"
+  where
+    ports = sequence
+          $ [ encodingNote hwty <$> text i | (i,hwty) <- inputs c ] ++
+            [ encodingNote hwty <$> text i | (i,hwty) <- hiddenPorts c] ++
+            [ encodingNote hwty <$> text i | (i,hwty) <- outputs c]
+
+    inputPorts = case (inputs c ++ hiddenPorts c) of
+                   [] -> empty
+                   p  -> vcat (punctuate semi (sequence [ "input" <+> sigDecl (text i) ty | (i,ty) <- p ])) <> semi
+
+    outputPorts = case (outputs c) of
+                   [] -> empty
+                   p  -> vcat (punctuate semi (sequence [ "output" <+> sigDecl (text i) ty | (i,ty) <- p ])) <> semi
+
+verilogType :: HWType -> VerilogM Doc
+verilogType t = case t of
+    Integer       -> verilogType (Signed 32)
+    (Signed n)    -> "signed" <+> brackets (int (n-1) <> colon <> int 0)
+    (Clock _ _)   -> empty
+    (Reset _ _)   -> empty
+    _             -> brackets (int (typeSize t -1) <> colon <> int 0)
+
+sigDecl :: VerilogM Doc -> HWType -> VerilogM Doc
+sigDecl d t = verilogType t <+> d
+
+-- | Convert a Netlist HWType to the root of a Verilog type
+verilogTypeMark :: HWType -> VerilogM Doc
+verilogTypeMark = const empty
+
+-- | Convert a Netlist HWType to an error VHDL value for that type
+verilogTypeErrValue :: HWType -> VerilogM Doc
+verilogTypeErrValue ty = braces (int (typeSize ty) <+> braces "1'bx")
+
+decls :: [Declaration] -> VerilogM Doc
+decls [] = empty
+decls ds = do
+    dsDoc <- catMaybes A.<$> mapM decl ds
+    case dsDoc of
+      [] -> empty
+      _  -> punctuate' semi (A.pure dsDoc)
+
+decl :: Declaration -> VerilogM (Maybe Doc)
+decl (NetDecl id_ ty) = Just A.<$> "wire" <+> sigDecl (text id_) ty
+
+decl _ = return Nothing
+
+insts :: [Declaration] -> VerilogM 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 -> VerilogM (Maybe Doc)
+inst_ (Assignment id_ e) = fmap Just $
+  "assign" <+> text id_ <+> equals <+> expr_ False e <> semi
+
+inst_ (CondAssignment id_ ty scrut [(Just (Literal _ (BoolLit b)), l),(_,r)]) = fmap Just $
+    "reg" <+> verilogType ty <+> regId <> semi <$>
+    "always @(*) begin" <$>
+    indent 2 ("if" <> parens (expr_ True scrut) <$>
+                (indent 2 $ regId <+> equals <+> expr_ False t <> semi) <$>
+             "else" <$>
+                (indent 2 $ regId <+> equals <+> expr_ False f <> semi)) <$>
+    "end" <$>
+    "assign" <+> text id_ <+> equals <+> regId <> semi
+  where
+    (t,f) = if b then (l,r) else (r,l)
+    regId = text id_ <> "_reg"
+
+
+inst_ (CondAssignment id_ ty scrut es) = fmap Just $
+    "reg" <+> verilogType ty <+> regId <> semi <$>
+    "always @(*) begin" <$>
+    indent 2 ("case" <> parens (expr_ True scrut) <$>
+                (indent 2 $ vcat $ punctuate semi (conds es)) <> semi <$>
+              "endcase") <$>
+    "end" <$>
+    "assign" <+> text id_ <+> equals <+> regId <> semi
+  where
+    regId = text id_ <> "_reg"
+
+    conds :: [(Maybe Expr,Expr)] -> VerilogM [Doc]
+    conds []                = return []
+    conds [(_,e)]           = ("default" <+> colon <+> regId <+> equals <+> expr_ False e) <:> return []
+    conds ((Nothing,e):_)   = ("default" <+> colon <+> regId <+> equals <+> expr_ False e) <:> return []
+    conds ((Just c ,e):es') = (expr_ True c <+> colon <+> regId <+> 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
+      -> VerilogM Doc
+expr_ _ (Literal sizeM lit) = exprLit sizeM lit
+
+expr_ _ (Identifier id_ Nothing) = text id_
+
+expr_ _ (Identifier id_ (Just (Indexed (ty@(SP _ args),dcI,fI)))) =
+    text id_ <> brackets (int start <> colon <> int 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 _ argTys),_,fI)))) =
+    text id_ <> brackets (int start <> colon <> int end)
+  where
+    argTy   = argTys !! fI
+    argSize = typeSize argTy
+    otherSz = otherSize argTys (fI - 1)
+    start   = typeSize ty - 1 - otherSz
+    end     = start - argSize + 1
+
+expr_ _ (Identifier id_ (Just (Indexed (ty@(Vector _ argTy),_,fI)))) =
+    text id_ <> brackets (int start <> colon <> int end)
+  where
+    argSize = typeSize argTy
+    start   = typeSize ty - (fI * argSize) - 1
+    end     = start - argSize + 1
+
+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]) = expr_ False e
+expr_ _ e@(DataCon (Vector _ _) _ es@[_,_]) =
+  case vectorChain e of
+    Just es' -> listBraces (mapM (expr_ False) es')
+    Nothing  -> listBraces (mapM (expr_ False) es)
+
+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   = map (expr_ False) 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 (Product _ _) _ es) = listBraces (mapM (expr_ False) 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 -> VerilogM 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
+                                       Integer
+                                        | i < 0     -> "-" <> int 32 <> "'sd" <> integer (abs i)
+                                        | otherwise -> int 32 <> "'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] -> VerilogM Doc
+bits = hcat . mapM bit_char
+
+bit_char :: Bit -> VerilogM Doc
+bit_char H = char '1'
+bit_char L = char '0'
+bit_char U = char 'x'
+bit_char Z = char 'z'
+
+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
+
+encodingNote :: HWType -> VerilogM Doc
+encodingNote (Clock _ _) = "// clock"
+encodingNote (Reset _ _) = "// asynchronous reset: active low"
+encodingNote _           = empty
